Skip to content
Closed
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
2 changes: 1 addition & 1 deletion crates/goose-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ pub struct ModelOptions {
long = "provider",
value_name = "PROVIDER",
help = "Specify the LLM provider to use (e.g., 'openai', 'anthropic')",
long_help = "Override the GOOSE_PROVIDER environment variable for this run. Available providers include openai, anthropic, ollama, databricks, gemini-cli, claude-code, and others."
long_help = "Override the GOOSE_PROVIDER environment variable for this run. Available providers include openai, anthropic, ollama, databricks, claude-acp, codex-acp, gemini-acp, copilot-acp, and others."
)]
pub provider: Option<String>,

Expand Down
1 change: 1 addition & 0 deletions crates/goose/src/config/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,7 @@ impl Config {
}

config_value!(CLAUDE_CODE_COMMAND, String, "claude");
config_value!(COPILOT_CLI_COMMAND, String, "copilot");
config_value!(GEMINI_CLI_COMMAND, String, "gemini");
config_value!(CURSOR_AGENT_COMMAND, String, "cursor-agent");
config_value!(CODEX_COMMAND, String, "codex");
Expand Down
116 changes: 116 additions & 0 deletions crates/goose/src/providers/copilot_acp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use anyhow::Result;
use futures::future::BoxFuture;
use std::collections::HashMap;
use std::path::PathBuf;

use crate::acp::{
extension_configs_to_mcp_servers, AcpProvider, AcpProviderConfig, PermissionMapping,
ACP_CURRENT_MODEL,
};
use crate::config::search_path::SearchPaths;
use crate::config::{Config, GooseMode};
use crate::model::ModelConfig;
use crate::providers::base::{ProviderDef, ProviderMetadata};

const COPILOT_ACP_PROVIDER_NAME: &str = "copilot-acp";
const COPILOT_ACP_DOC_URL: &str =
"https://docs.github.com/en/copilot/reference/copilot-cli-reference/acp-server";
const ACP_AGENT_MODE: &str = "https://agentclientprotocol.com/protocol/session-modes#agent";
const ACP_PLAN_MODE: &str = "https://agentclientprotocol.com/protocol/session-modes#plan";
const ACP_AUTOPILOT_MODE: &str = "https://agentclientprotocol.com/protocol/session-modes#autopilot";
const COPILOT_ALLOW_OPTION_ID: &str = "allow_once";
const COPILOT_REJECT_OPTION_ID: &str = "reject_once";

pub struct CopilotAcpProvider;

fn copilot_permission_mapping() -> PermissionMapping {
PermissionMapping {
allow_option_id: Some(COPILOT_ALLOW_OPTION_ID.to_string()),
reject_option_id: Some(COPILOT_REJECT_OPTION_ID.to_string()),
rejected_tool_status: sacp::schema::ToolCallStatus::Failed,
}
}

impl ProviderDef for CopilotAcpProvider {
type Provider = AcpProvider;

fn metadata() -> ProviderMetadata {
ProviderMetadata::new(
COPILOT_ACP_PROVIDER_NAME,
"GitHub Copilot CLI (ACP)",
"Use goose with your GitHub Copilot subscription via GitHub Copilot CLI.",
ACP_CURRENT_MODEL,
vec![],
COPILOT_ACP_DOC_URL,
vec![],
)
.with_setup_steps(vec![
"Install GitHub Copilot CLI: `brew install copilot-cli` or `npm install -g @github/copilot`",
"Run `copilot` once and authenticate with your GitHub account (`/login` if prompted)",
"Set in your goose config file (`~/.config/goose/config.yaml` on macOS/Linux):\n GOOSE_PROVIDER: copilot-acp\n GOOSE_MODEL: current",
"Restart goose for changes to take effect",
])
}

fn from_env(
model: ModelConfig,
extensions: Vec<crate::config::ExtensionConfig>,
) -> BoxFuture<'static, Result<AcpProvider>> {
Box::pin(async move {
let config = Config::global();
let command_name: String = config.get_copilot_cli_command().unwrap_or_default().into();
let resolved_command = SearchPaths::builder().with_npm().resolve(&command_name)?;
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);

let permission_mapping = copilot_permission_mapping();

let mut args = vec!["--acp".to_string()];
if model.model_name != ACP_CURRENT_MODEL {
args.push("--model".to_string());
args.push(model.model_name.clone());
}

let mode_mapping = HashMap::from([
(GooseMode::Auto, ACP_AUTOPILOT_MODE.to_string()),
(GooseMode::Approve, ACP_AGENT_MODE.to_string()),
(GooseMode::SmartApprove, ACP_AGENT_MODE.to_string()),
(GooseMode::Chat, ACP_PLAN_MODE.to_string()),
]);

let provider_config = AcpProviderConfig {
command: resolved_command,
args,
env: vec![],
env_remove: vec![],
work_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
mcp_servers: extension_configs_to_mcp_servers(&extensions),
session_mode_id: Some(mode_mapping[&goose_mode].clone()),
mode_mapping,
permission_mapping,
notification_callback: None,
};

let metadata = Self::metadata();
AcpProvider::connect(metadata.name, model, goose_mode, provider_config).await
})
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_copilot_permission_mapping_uses_acp_option_ids() {
let permission_mapping = copilot_permission_mapping();

assert_eq!(
permission_mapping.allow_option_id.as_deref(),
Some(COPILOT_ALLOW_OPTION_ID)
);
assert_eq!(
permission_mapping.reject_option_id.as_deref(),
Some(COPILOT_REJECT_OPTION_ID)
);
}
}
2 changes: 2 additions & 0 deletions crates/goose/src/providers/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::{
claude_code::ClaudeCodeProvider,
codex::CodexProvider,
codex_acp::CodexAcpProvider,
copilot_acp::CopilotAcpProvider,
cursor_agent::CursorAgentProvider,
databricks::DatabricksProvider,
gcpvertexai::GcpVertexAIProvider,
Expand Down Expand Up @@ -59,6 +60,7 @@ async fn init_registry() -> RwLock<ProviderRegistry> {
registry.register::<ClaudeAcpProvider>(false);
registry.register::<ClaudeCodeProvider>(true);
registry.register::<CodexAcpProvider>(false);
registry.register::<CopilotAcpProvider>(false);
registry.register::<CodexProvider>(true);
registry.register::<CursorAgentProvider>(false);
registry.register::<DatabricksProvider>(true);
Expand Down
1 change: 1 addition & 0 deletions crates/goose/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod claude_code;
pub(crate) mod cli_common;
pub mod codex;
pub mod codex_acp;
pub mod copilot_acp;
pub mod cursor_agent;
pub mod databricks;
pub mod embedding;
Expand Down
18 changes: 18 additions & 0 deletions crates/goose/tests/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,24 @@ async fn test_codex_acp_provider() -> Result<()> {
.await
}

#[tokio::test]
async fn test_copilot_acp_provider() -> Result<()> {
ProviderTestConfig::with_agentic_provider("copilot-acp", ACP_CURRENT_MODEL, "copilot")
.run()
.await
}

// Requires: npm install -g @google/gemini-cli
#[tokio::test]
async fn test_gemini_acp_provider() -> Result<()> {
// Don't run tests with ACP_CURRENT_MODEL, as gemini sets "auto-gemini-3" even when the user
// has no access to the Preview Release Channel, resulting in "Requested entity was not found."
// See https://github.com/google-gemini/gemini-cli/issues/22803
ProviderTestConfig::with_agentic_provider("gemini-acp", "auto-gemini-2.5", "gemini")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use a registered provider ID in gemini ACP test

This test will fail on machines that actually have the gemini binary installed, because the skip gate passes and create_with_named_model("gemini-acp", ...) is executed, but the registry setup in crates/goose/src/providers/init.rs does not register a gemini-acp provider (only GeminiCliProvider, i.e. gemini-cli). That makes the new test deterministically error with Unknown provider: gemini-acp in environments where it runs instead of being skipped.

Useful? React with 👍 / 👎.

.model_switch_name("gemini-2.5-flash")
.run()
.await
}
#[ctor::dtor]
fn print_test_report() {
TEST_REPORT.print_summary();
Expand Down
1 change: 1 addition & 0 deletions documentation/docs/getting-started/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ goose supports [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) a
|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Claude ACP](https://github.com/zed-industries/claude-agent-acp) (`claude-acp`) | Uses Claude Code via ACP. Passes goose extensions to the agent as MCP servers. | `npm install -g @zed-industries/claude-agent-acp`, active Claude Code subscription |
| [Codex ACP](https://github.com/zed-industries/codex-acp) (`codex-acp`) | Uses OpenAI Codex via ACP. Passes goose extensions to the agent as MCP servers. | `npm install -g @zed-industries/codex-acp`, active ChatGPT Plus/Pro subscription |
| [GitHub Copilot CLI](https://docs.github.com/en/copilot/reference/copilot-cli-reference/acp-server) (`copilot-acp`) | Uses GitHub Copilot CLI via ACP (native `--acp` support). Passes goose extensions to the agent as MCP servers. | GitHub Copilot CLI installed, active GitHub Copilot subscription, authenticated with GitHub account |
| [Gemini ACP](https://github.com/google-gemini/gemini-cli) (`gemini-acp`) | Uses Google's Gemini CLI via ACP (native `--acp` support). Passes goose extensions to the agent as MCP servers. | `npm install -g @google/gemini-cli`, authenticated with Google account |

:::tip ACP Providers
Expand Down
85 changes: 79 additions & 6 deletions documentation/docs/guides/acp-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
sidebar_position: 46
title: ACP Providers
sidebar_label: ACP Providers
description: Use ACP agents like Claude Code and Codex as goose providers with extension support
description: Use ACP agents like Claude Code, GitHub Copilot CLI, Codex, and Gemini as goose providers with extension support
---

# ACP Providers
Expand All @@ -12,7 +12,7 @@ goose supports [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) a
ACP providers pass goose [extensions](/docs/getting-started/using-extensions) through to the agent as MCP servers, so the agent can call your extensions directly.

:::tip Use Your Existing Subscriptions
ACP providers let you use goose with your existing Claude Code, ChatGPT Plus/Pro, or Google Gemini subscriptions — no per-token API costs. They are the recommended replacement for the deprecated [CLI providers](/docs/guides/cli-providers).
ACP providers let you use goose with your existing Claude Code, ChatGPT Plus/Pro, GitHub Copilot, or Google Gemini subscriptions — no per-token API costs. They are the recommended replacement for the deprecated [CLI providers](/docs/guides/cli-providers).
:::

:::warning Limitations
Expand Down Expand Up @@ -40,6 +40,15 @@ Wraps [codex-acp](https://github.com/zed-industries/codex-acp), an ACP adapter f
- Active ChatGPT Plus/Pro subscription or OpenAI API credits
- Authenticated with your OpenAI account (`codex` CLI working)

### GitHub Copilot CLI ACP

Uses [GitHub Copilot CLI](https://docs.github.com/en/copilot/reference/copilot-cli-reference/acp-server) directly via its native `--acp` flag. No shim needed. Supports goose extensions by passing them through as MCP servers.

**Requirements:**
- Active GitHub Copilot subscription or organization-managed Copilot access
- GitHub Copilot CLI installed
- Authenticated with your GitHub account (`copilot` CLI working)

### Gemini ACP

Uses Google's [Gemini CLI](https://github.com/google-gemini/gemini-cli) directly via its native `--acp` flag. No shim needed — Gemini CLI speaks ACP natively. Replaces the deprecated `gemini-cli` CLI provider.
Expand Down Expand Up @@ -123,6 +132,50 @@ Uses Google's [Gemini CLI](https://github.com/google-gemini/gemini-cli) directly
│ gpt-5.2-codex
```

### GitHub Copilot CLI ACP

1. **Install GitHub Copilot CLI**

Install Copilot CLI using one of GitHub's supported methods:

```bash
brew install copilot-cli
```

Or:

```bash
npm install -g @github/copilot
```

2. **Authenticate with GitHub**

Run `copilot` once and follow the login flow. If prompted, use the `/login` slash command to authenticate.

3. **Configure goose**

Set the provider environment variable:
```bash
export GOOSE_PROVIDER=copilot-acp
```

Or configure through the goose CLI using `goose configure`:

```bash
┌ goose-configure
◇ What would you like to configure?
│ Configure Providers
◇ Which model provider should we use?
│ GitHub Copilot CLI (ACP)
◇ Model fetch complete
◇ Enter a model from that provider:
│ default
```

### Gemini ACP

1. **Install Gemini CLI**
Expand Down Expand Up @@ -183,6 +236,12 @@ GOOSE_PROVIDER=codex-acp goose run \
-t 'Search for flights from BKI to SYD tomorrow'
```

```bash
GOOSE_PROVIDER=copilot-acp goose run \
--with-extension 'npx -y @modelcontextprotocol/server-everything' \
-t 'Use the echo tool to say hello'
```

```bash
GOOSE_PROVIDER=gemini-acp goose run \
--with-extension 'npx -y @modelcontextprotocol/server-everything' \
Expand Down Expand Up @@ -240,6 +299,20 @@ See [claude-agent-acp](https://github.com/zed-industries/claude-agent-acp) for s

See [codex-acp](https://github.com/zed-industries/codex-acp) for approval policy and sandbox details.

### GitHub Copilot CLI ACP Configuration

| Environment Variable | Description | Default |
|----------------------|---------------------|-----------|
| `GOOSE_PROVIDER` | Set to `copilot-acp` | None |
| `GOOSE_MODEL` | Model to use | `default` |
| `GOOSE_MODE` | Permission mode | `auto` |

**Known Models:**
- Models are fetched dynamically from Copilot CLI and may vary by account plan or preview access.

**Notes:**
- ACP support in Copilot CLI may change as GitHub evolves the CLI.

### Gemini ACP Configuration

| Environment Variable | Description | Default |
Expand All @@ -261,11 +334,11 @@ See the [Gemini CLI documentation](https://github.com/google-gemini/gemini-cli)

## Error Handling

ACP providers depend on external npm packages, so ensure:
ACP providers depend on external agent binaries, so ensure:

- The ACP agent binary is installed and in your PATH (`claude-agent-acp`, `codex-acp`, or `gemini`)
- The ACP agent binary is installed and in your PATH (`claude-agent-acp`, `codex-acp`, `copilot`, or `gemini`)
- The underlying CLI tool is authenticated and working
- Subscription limits are not exceeded
- Node.js and npm are installed
- Any required runtime for the selected agent is installed

If goose can't find the binary, session startup will fail with an error. Run `which claude-agent-acp`, `which codex-acp`, or `which gemini` to verify installation.
If goose can't find the binary, session startup will fail with an error. Run `which claude-agent-acp`, `which codex-acp`, `which copilot`, or `which gemini` to verify installation.
Loading