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

# GitHub Copilot CLI

> Run GitHub Copilot CLI in a secure E2B sandbox with full filesystem, terminal, and git access.

[GitHub Copilot CLI](https://github.com/github/copilot-cli) (`copilot`) is GitHub's coding agent for the terminal. E2B provides a pre-built `copilot` template with Copilot CLI already installed.

## Authentication

Copilot CLI reads a GitHub token from `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN`, in that order. Create a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new) on an account with a Copilot plan, add the **Copilot Requests** account permission, and pass it to the sandbox as `COPILOT_GITHUB_TOKEN`. Without a token, `copilot -p` exits with an error instead of waiting for a login.

> [!WARNING]
>
> Copilot CLI rejects classic personal access tokens (`ghp_`), even when a model provider is configured. If you use a classic token for `git`, pass it only to the git command, not as a sandbox-wide `GITHUB_TOKEN`, as in the [cloned repository example](#example-work-on-a-cloned-repository).

To use your own model provider instead of a Copilot plan, set `COPILOT_PROVIDER_BASE_URL`, `COPILOT_PROVIDER_API_KEY`, and `COPILOT_MODEL`. No GitHub token is needed in that mode. For OpenAI GPT-5 models, also set `COPILOT_PROVIDER_WIRE_API=responses`; for Anthropic, set `COPILOT_PROVIDER_TYPE=anthropic`. Run `copilot help providers` in the sandbox for all options.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
const sandbox = await Sandbox.create('copilot', {
  envs: {
    COPILOT_PROVIDER_BASE_URL: 'https://api.openai.com/v1',
    COPILOT_PROVIDER_API_KEY: process.env.OPENAI_API_KEY!,
    COPILOT_PROVIDER_WIRE_API: 'responses',
    COPILOT_MODEL: 'gpt-5.6-luna',
  },
})
```

```python Python theme={"theme":"css-variables"}
sandbox = Sandbox.create("copilot", envs={
    "COPILOT_PROVIDER_BASE_URL": "https://api.openai.com/v1",
    "COPILOT_PROVIDER_API_KEY": os.environ["OPENAI_API_KEY"],
    "COPILOT_PROVIDER_WIRE_API": "responses",
    "COPILOT_MODEL": "gpt-5.6-luna",
})
```

## CLI

Create a sandbox with the [E2B CLI](https://docs.e2b.dev/cli.md) and pass your token to the terminal session.

```bash theme={"theme":"css-variables"}
e2b sbx create copilot -e COPILOT_GITHUB_TOKEN=$COPILOT_GITHUB_TOKEN
```

Once inside the sandbox, start Copilot CLI.

```bash theme={"theme":"css-variables"}
copilot
```

If you did not pass a token, run `/login` in Copilot CLI to sign in with your GitHub account.

## Run headless

Use `-p` for non-interactive mode and `--allow-all-tools` to auto-approve all tool calls. Without it, headless runs cannot ask for approval: tools that need it are denied, and the run still exits with code 0. Add `-s` to print only the final answer.

Agent runs often take longer than the default command timeout, so pass `timeoutMs: 0` (`timeout=0` in Python) to wait until the run completes, and give the sandbox enough lifetime.

> [!NOTE]
>
> Auto-approving tool calls is contained by the sandbox: the agent cannot touch your host machine, local files, or credentials. It can still make outbound network requests — internet access is enabled by default. To limit where an auto-approved agent can connect, configure [outbound network rules](https://docs.e2b.dev/network/internet-access.md) (`allowInternetAccess`, plus allow lists by CIDR or hostname and deny lists by CIDR). Hostname rules apply to HTTP(S) traffic only; use CIDR rules for other protocols.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('copilot', {
  envs: { COPILOT_GITHUB_TOKEN: process.env.COPILOT_GITHUB_TOKEN! },
  timeoutMs: 600_000,
})

const result = await sandbox.commands.run(
  `copilot --allow-all-tools -p "Create a hello world HTTP server in Python"`,
  { timeoutMs: 0 }
)

console.log(result.stdout)
await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
from e2b import Sandbox

sandbox = Sandbox.create("copilot", envs={
    "COPILOT_GITHUB_TOKEN": os.environ["COPILOT_GITHUB_TOKEN"],
}, timeout=600)

result = sandbox.commands.run(
    'copilot --allow-all-tools -p "Create a hello world HTTP server in Python"',
    timeout=0,
)

print(result.stdout)
sandbox.kill()
```

> [!TIP]
>
> Select a model with `--model`, or with `COPILOT_MODEL` when you use your own provider. To allow only some tools, replace `--allow-all-tools` with `--allow-tool` and `--deny-tool` rules, for example `--allow-tool='shell(git:*)' --deny-tool='shell(git push)'`.

### Example: work on a cloned repository

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('copilot', {
  envs: { COPILOT_GITHUB_TOKEN: process.env.COPILOT_GITHUB_TOKEN! },
  timeoutMs: 900_000,
})

await sandbox.commands.run(
  'git clone --depth 1 https://x-access-token:$GITHUB_TOKEN@github.com/your-org/your-repo.git /home/user/repo',
  { envs: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! } }
)
// Remove the token from .git/config so the agent cannot read it
await sandbox.commands.run('git -C /home/user/repo remote set-url origin https://github.com/your-org/your-repo.git')

const result = await sandbox.commands.run(
  `cd /home/user/repo && copilot --allow-all-tools -p "Add error handling to all API endpoints"`,
  { timeoutMs: 0, onStdout: (data) => { process.stdout.write(data) } }
)

const diff = await sandbox.commands.run('cd /home/user/repo && git diff')
console.log(diff.stdout)

await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
from e2b import Sandbox

sandbox = Sandbox.create("copilot", envs={
    "COPILOT_GITHUB_TOKEN": os.environ["COPILOT_GITHUB_TOKEN"],
}, timeout=900)

sandbox.commands.run(
    "git clone --depth 1 https://x-access-token:$GITHUB_TOKEN@github.com/your-org/your-repo.git /home/user/repo",
    envs={"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},
)
# Remove the token from .git/config so the agent cannot read it
sandbox.commands.run("git -C /home/user/repo remote set-url origin https://github.com/your-org/your-repo.git")

result = sandbox.commands.run(
    'cd /home/user/repo && copilot --allow-all-tools -p "Add error handling to all API endpoints"',
    timeout=0,
    on_stdout=lambda data: print(data, end=""),
)

diff = sandbox.commands.run("cd /home/user/repo && git diff")
print(diff.stdout)

sandbox.kill()
```

## Streaming events

Use `--output-format json` to get a JSONL event stream: `assistant.message_delta` events with response text, `tool.execution_start` and `tool.execution_complete` events for tool calls, and a final `result` event with the session ID and the files the run changed.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('copilot', {
  envs: { COPILOT_GITHUB_TOKEN: process.env.COPILOT_GITHUB_TOKEN! },
  timeoutMs: 600_000,
})

// Output arrives in chunks that can split a JSON line, so buffer until a newline
let buffer = ''
const handleOutput = (data: string) => {
  buffer += data
  const lines = buffer.split('\n')
  buffer = lines.pop() ?? ''
  for (const line of lines.filter(Boolean)) {
    const event = JSON.parse(line)
    if (event.type === 'tool.execution_start') {
      console.log(`[tool] ${event.data.toolName}`)
    } else if (event.type === 'assistant.message_delta') {
      process.stdout.write(event.data.deltaContent)
    } else if (event.type === 'result') {
      console.log(`\n[done] session ${event.sessionId}, changed: ${event.usage.codeChanges.filesModified.join(', ')}`)
    }
  }
}

await sandbox.commands.run(
  `copilot --allow-all-tools --output-format json -p "Create hello.py that prints hello, then run it"`,
  { timeoutMs: 0, onStdout: handleOutput }
)

await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import json
import os
from e2b import Sandbox

sandbox = Sandbox.create("copilot", envs={
    "COPILOT_GITHUB_TOKEN": os.environ["COPILOT_GITHUB_TOKEN"],
}, timeout=600)

# Output arrives in chunks that can split a JSON line, so buffer until a newline
buffer = ""

def handle_output(data):
    global buffer
    buffer += data
    *lines, buffer = buffer.split("\n")
    for line in filter(None, lines):
        event = json.loads(line)
        if event["type"] == "tool.execution_start":
            print(f"[tool] {event['data']['toolName']}")
        elif event["type"] == "assistant.message_delta":
            print(event["data"]["deltaContent"], end="")
        elif event["type"] == "result":
            changed = ", ".join(event["usage"]["codeChanges"]["filesModified"])
            print(f"\n[done] session {event['sessionId']}, changed: {changed}")

sandbox.commands.run(
    'copilot --allow-all-tools --output-format json -p "Create hello.py that prints hello, then run it"',
    timeout=0,
    on_stdout=handle_output,
)

sandbox.kill()
```

## Resume a session

Copilot CLI stores sessions in `~/.copilot` inside the sandbox. Use `--continue` to resume the most recent one, or `--resume=<session-id>` with the ID from the `result` event, to give follow-up instructions with the earlier context.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('copilot', {
  envs: { COPILOT_GITHUB_TOKEN: process.env.COPILOT_GITHUB_TOKEN! },
  timeoutMs: 600_000,
})

await sandbox.commands.run(
  `mkdir -p /home/user/app && cd /home/user/app && copilot --allow-all-tools -p "Create a Flask app in app.py with a /health endpoint"`,
  { timeoutMs: 0 }
)

const followUp = await sandbox.commands.run(
  `cd /home/user/app && copilot --continue --allow-all-tools -s -p "Add a /version endpoint that returns 1.0.0"`,
  { timeoutMs: 0 }
)

console.log(followUp.stdout)
await sandbox.kill()
```

```python Python theme={"theme":"css-variables"}
import os
from e2b import Sandbox

sandbox = Sandbox.create("copilot", envs={
    "COPILOT_GITHUB_TOKEN": os.environ["COPILOT_GITHUB_TOKEN"],
}, timeout=600)

sandbox.commands.run(
    'mkdir -p /home/user/app && cd /home/user/app && copilot --allow-all-tools -p "Create a Flask app in app.py with a /health endpoint"',
    timeout=0,
)

follow_up = sandbox.commands.run(
    'cd /home/user/app && copilot --continue --allow-all-tools -s -p "Add a /version endpoint that returns 1.0.0"',
    timeout=0,
)

print(follow_up.stdout)
sandbox.kill()
```

To keep sessions across sandbox restarts, [pause the sandbox](https://docs.e2b.dev/sandbox/persistence.md) instead of killing it.

## Build a custom template

If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `copilot` template.

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
// template.ts
import { Template } from 'e2b'

export const template = Template()
  .fromTemplate('copilot')
```

```python Python theme={"theme":"css-variables"}
# template.py
from e2b import Template

template = (
    Template()
    .from_template("copilot")
)
```

```typescript JavaScript & TypeScript theme={"theme":"css-variables"}
// build.ts
import { Template, defaultBuildLogger } from 'e2b'
import { template as copilotTemplate } from './template'

await Template.build(copilotTemplate, 'my-copilot', {
  cpuCount: 2,
  memoryMB: 2048,
  onBuildLogs: defaultBuildLogger(),
})
```

```python Python theme={"theme":"css-variables"}
# build.py
from e2b import Template, default_build_logger
from template import template as copilot_template

Template.build(copilot_template, "my-copilot",
    cpu_count=2,
    memory_mb=2048,
    on_build_logs=default_build_logger(),
)
```

Run the build script to create the template.

```bash JavaScript & TypeScript theme={"theme":"css-variables"}
npx tsx build.ts
```

```bash Python theme={"theme":"css-variables"}
python build.py
```

## Related guides

> [card] [Cookbook example](https://github.com/e2b-dev/e2b-cookbook/tree/main/examples/github-copilot-cli-in-sandbox-js)
>
> Run Copilot CLI on a repository and print the diff

> [card] [Sandbox persistence](https://docs.e2b.dev/sandbox/persistence.md)
>
> Auto-pause, resume, and manage sandbox lifecycle

> [card] [SSH access](https://docs.e2b.dev/sandbox/ssh-access.md)
>
> Connect to the sandbox via SSH for interactive sessions
