Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ uv tool install -U openshell
### Create a sandbox

```bash
openshell sandbox create -- claude # or opencode, codex, ollama
openshell sandbox create -- claude # or opencode, codex, copilot, ollama
```

A gateway is created automatically on first use. To deploy on a remote host instead, pass `--remote user@host` to the create command.
Expand All @@ -45,7 +45,7 @@ The sandbox container includes the following tools by default:

| Category | Tools |
| ---------- | -------------------------------------------------------- |
| Agent | `claude`, `opencode`, `codex` |
| Agent | `claude`, `opencode`, `codex`, `copilot` |
| Language | `python` (3.13), `node` (22) |
| Developer | `gh`, `git`, `vim`, `nano` |
| Networking | `ping`, `dig`, `nslookup`, `nc`, `traceroute`, `netstat` |
Expand Down Expand Up @@ -115,7 +115,7 @@ Policies are declarative YAML files. Static sections (filesystem, process) are l

## Providers

Agents need credentials — API keys, tokens, service accounts. OpenShell manages these as **providers**: named credential bundles that are injected into sandboxes at creation. The CLI auto-discovers credentials for recognized agents (Claude, Codex, OpenCode) from your shell environment, or you can create providers explicitly with `openshell provider create`. Credentials never leak into the sandbox filesystem; they are injected as environment variables at runtime.
Agents need credentials — API keys, tokens, service accounts. OpenShell manages these as **providers**: named credential bundles that are injected into sandboxes at creation. The CLI auto-discovers credentials for recognized agents (Claude, Codex, OpenCode, Copilot) from your shell environment, or you can create providers explicitly with `openshell provider create`. Credentials never leak into the sandbox filesystem; they are injected as environment variables at runtime.

## GPU Support

Expand All @@ -136,6 +136,7 @@ The CLI auto-bootstraps a GPU-enabled gateway on first use. GPU intent is also i
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Works out of the box. Provider uses `ANTHROPIC_API_KEY`. |
| [OpenCode](https://opencode.ai/) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Works out of the box. Provider uses `OPENAI_API_KEY` or `OPENROUTER_API_KEY`. |
| [Codex](https://developers.openai.com/codex) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Works out of the box. Provider uses `OPENAI_API_KEY`. |
| [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Works out of the box. Provider uses `GITHUB_TOKEN` or `COPILOT_GITHUB_TOKEN`. |
| [OpenClaw](https://openclaw.ai/) | [Community](https://github.com/NVIDIA/OpenShell-Community) | Launch with `openshell sandbox create --from openclaw`. |
| [Ollama](https://ollama.com/) | [Community](https://github.com/NVIDIA/OpenShell-Community) | Launch with `openshell sandbox create --from ollama`. |

Expand Down
17 changes: 17 additions & 0 deletions crates/openshell-providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl ProviderRegistry {
let mut registry = Self::default();
registry.register(providers::claude::ClaudeProvider);
registry.register(providers::codex::CodexProvider);
registry.register(providers::copilot::CopilotProvider);
registry.register(providers::opencode::OpencodeProvider);
registry.register(providers::generic::GenericProvider);
registry.register(providers::openai::OpenaiProvider);
Expand Down Expand Up @@ -128,6 +129,7 @@ pub fn normalize_provider_type(input: &str) -> Option<&'static str> {
match normalized.as_str() {
"claude" => Some("claude"),
"codex" => Some("codex"),
"copilot" => Some("copilot"),
"opencode" => Some("opencode"),
"generic" => Some("generic"),
"openai" => Some("openai"),
Expand Down Expand Up @@ -164,6 +166,7 @@ mod tests {
assert_eq!(normalize_provider_type("openai"), Some("openai"));
assert_eq!(normalize_provider_type("anthropic"), Some("anthropic"));
assert_eq!(normalize_provider_type("nvidia"), Some("nvidia"));
assert_eq!(normalize_provider_type("copilot"), Some("copilot"));
assert_eq!(normalize_provider_type("unknown"), None);
}

Expand All @@ -181,5 +184,19 @@ mod tests {
detect_provider_from_command(&["/usr/bin/bash".to_string()]),
None
);
// Copilot standalone binary
assert_eq!(
detect_provider_from_command(&["copilot".to_string()]),
Some("copilot")
);
assert_eq!(
detect_provider_from_command(&["/usr/local/bin/copilot".to_string()]),
Some("copilot")
);
// gh alone still maps to github
assert_eq!(
detect_provider_from_command(&["gh".to_string()]),
Some("github")
);
}
}
46 changes: 46 additions & 0 deletions crates/openshell-providers/src/providers/copilot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::{
ProviderDiscoverySpec, ProviderError, ProviderPlugin, RealDiscoveryContext, discover_with_spec,
};

pub struct CopilotProvider;

pub const SPEC: ProviderDiscoverySpec = ProviderDiscoverySpec {
id: "copilot",
credential_env_vars: &["COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"],
};

impl ProviderPlugin for CopilotProvider {
fn id(&self) -> &'static str {
SPEC.id
}

fn discover_existing(&self) -> Result<Option<crate::DiscoveredProvider>, ProviderError> {
discover_with_spec(&SPEC, &RealDiscoveryContext)
}

fn credential_env_vars(&self) -> &'static [&'static str] {
SPEC.credential_env_vars
}
}

#[cfg(test)]
mod tests {
use super::SPEC;
use crate::discover_with_spec;
use crate::test_helpers::MockDiscoveryContext;

#[test]
fn discovers_copilot_env_credentials() {
let ctx = MockDiscoveryContext::new().with_env("COPILOT_GITHUB_TOKEN", "ghp-copilot-token");
let discovered = discover_with_spec(&SPEC, &ctx)
.expect("discovery")
.expect("provider");
assert_eq!(
discovered.credentials.get("COPILOT_GITHUB_TOKEN"),
Some(&"ghp-copilot-token".to_string())
);
}
}
1 change: 1 addition & 0 deletions crates/openshell-providers/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
pub mod anthropic;
pub mod claude;
pub mod codex;
pub mod copilot;
pub mod generic;
pub mod github;
pub mod gitlab;
Expand Down
20 changes: 20 additions & 0 deletions crates/openshell-sandbox/testdata/sandbox-policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ network_policies:
binaries:
- { path: /usr/bin/git }

copilot:
name: copilot
endpoints:
- { host: github.com, port: 443 }
- { host: api.github.com, port: 443 }
- { host: api.githubcopilot.com, port: 443 }
- { host: api.individual.githubcopilot.com, port: 443 }
- { host: api.business.githubcopilot.com, port: 443 }
- { host: api.enterprise.githubcopilot.com, port: 443 }
- { host: copilot-proxy.githubusercontent.com, port: 443 }
- { host: copilot-telemetry.githubusercontent.com, port: 443 }
- { host: default.exp-tas.com, port: 443 }
- { host: origin-tracker.githubusercontent.com, port: 443 }
- { host: release-assets.githubusercontent.com, port: 443 }
binaries:
- { path: "/usr/lib/node_modules/@github/copilot/node_modules/@github/**/copilot" }
- { path: /usr/local/bin/copilot }
- { path: "/home/*/.local/bin/copilot" }
- { path: /usr/bin/node }

gitlab:
name: gitlab
endpoints:
Expand Down
1 change: 1 addition & 0 deletions docs/about/supported-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following table summarizes the agents that run in OpenShell sandboxes. All a
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Full coverage | Works out of the box. Requires `ANTHROPIC_API_KEY`. |
| [OpenCode](https://opencode.ai/) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Partial coverage | Pre-installed. Add `opencode.ai` endpoint and OpenCode binary paths to the policy for full functionality. |
| [Codex](https://developers.openai.com/codex) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | No coverage | Pre-installed. Requires a custom policy with OpenAI endpoints and Codex binary paths. Requires `OPENAI_API_KEY`. |
| [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) | [`base`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) | Full coverage | Pre-installed. Works out of the box. Requires `GITHUB_TOKEN` or `COPILOT_GITHUB_TOKEN`. |
| [OpenClaw](https://openclaw.ai/) | [`openclaw`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/openclaw) | Bundled | Agent orchestration layer. Launch with `openshell sandbox create --from openclaw`. |
| [Ollama](https://ollama.com/) | [`ollama`](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/ollama) | Bundled | Run cloud and local models. Includes Claude Code, Codex, and OpenClaw. Launch with `openshell sandbox create --from ollama`. |

Expand Down
Loading