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
18 changes: 16 additions & 2 deletions crates/goose/src/providers/chatgpt_codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ const OAUTH_TIMEOUT_SECS: u64 = 300;
const HTML_AUTO_CLOSE_TIMEOUT_MS: u64 = 2000;

const CHATGPT_CODEX_PROVIDER_NAME: &str = "chatgpt_codex";
pub const CHATGPT_CODEX_DEFAULT_MODEL: &str = "gpt-5.1-codex";
pub const CHATGPT_CODEX_DEFAULT_MODEL: &str = "gpt-5.3-codex";
pub const CHATGPT_CODEX_KNOWN_MODELS: &[&str] = &[
"gpt-5.4",
Comment on lines +48 to +50
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 Keep the ChatGPT Codex UI default aligned with the provider default

The desktop model switcher does not use default_model; it asks the backend for recommended models, then SwitchModelModal::findPreferredModel() falls back to the first returned entry when no regex matches. fetch_recommended_models() sorts ChatGPT models by release date, and the canonical registry dates gpt-5.4 after gpt-5.3-codex, so adding gpt-5.4 here makes the UI preselect gpt-5.4 whenever a user switches to chatgpt_codex. That silently diverges from the declared default gpt-5.3-codex and bypasses the new GPT-5.3-specific prompt tuning in create_codex_request().

Useful? React with 👍 / 👎.

"gpt-5.3-codex",
"gpt-5.2-codex",
"gpt-5.1-codex",
Expand All @@ -56,6 +57,14 @@ pub const CHATGPT_CODEX_KNOWN_MODELS: &[&str] = &[

const CHATGPT_CODEX_DOC_URL: &str = "https://openai.com/chatgpt";

const GPT_53_CODEX_TOOL_PREAMBLE: &str = "\
You are a coding agent. You have access to tools to accomplish tasks. \
Always use your tools to fulfill requests - do not just describe what you would do. \
Keep going until the query is completely resolved before yielding back to the user. \
Autonomously resolve the query using the tools available to you. \
Do NOT guess or make up an answer. \
Before making tool calls, send a brief message explaining what you're about to do.";

#[derive(Debug)]
struct ChatGptCodexAuthState {
oauth_mutex: TokioMutex<()>,
Expand Down Expand Up @@ -181,11 +190,16 @@ fn create_codex_request(
) -> Result<Value> {
let input_items = build_input_items(messages)?;

let instructions = match model_config.model_name.as_str() {
"gpt-5.3-codex" => format!("{GPT_53_CODEX_TOOL_PREAMBLE}\n\n{system}"),
_ => system.to_string(),
Comment thread
michaelneale marked this conversation as resolved.
};

let mut payload = json!({
"model": model_config.model_name,
"input": input_items,
"store": false,
"instructions": system,
"instructions": instructions,
});

let payload_obj = payload
Expand Down
2 changes: 1 addition & 1 deletion crates/goose/src/providers/claude_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl ProviderDef for ClaudeCodeProvider {
ProviderMetadata::new(
CLAUDE_CODE_PROVIDER_NAME,
"Claude Code CLI",
"Requires claude CLI installed, no MCPs. Use Anthropic provider for full features.",
"[Deprecated: use claude-acp instead] Requires claude CLI installed, no MCPs. Use claude-acp for ACP support with extensions.",
CLAUDE_CODE_DEFAULT_MODEL,
// Only a few agentic choices; fetched dynamically via fetch_supported_models.
vec![],
Expand Down
2 changes: 1 addition & 1 deletion crates/goose/src/providers/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ impl ProviderDef for CodexProvider {
ProviderMetadata::new(
CODEX_PROVIDER_NAME,
"OpenAI Codex CLI",
"Execute OpenAI models via Codex CLI tool. Requires codex CLI installed.",
"[Deprecated: use chatgpt_codex or codex-acp instead] Execute OpenAI models via Codex CLI tool. Requires codex CLI installed.",
CODEX_DEFAULT_MODEL,
CODEX_KNOWN_MODELS.to_vec(),
CODEX_DOC_URL,
Expand Down
81 changes: 81 additions & 0 deletions crates/goose/src/providers/gemini_acp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use anyhow::Result;
use futures::future::BoxFuture;
use std::path::PathBuf;

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

const GEMINI_ACP_PROVIDER_NAME: &str = "gemini-acp";
pub const GEMINI_ACP_DEFAULT_MODEL: &str = "default";
const GEMINI_ACP_DOC_URL: &str = "https://github.com/google-gemini/gemini-cli";

pub struct GeminiAcpProvider;

impl ProviderDef for GeminiAcpProvider {
type Provider = AcpProvider;

fn metadata() -> ProviderMetadata {
ProviderMetadata::new(
GEMINI_ACP_PROVIDER_NAME,
"Gemini CLI (ACP)",
"ACP provider for Google's Gemini CLI. Install: npm install -g @google/gemini-cli",
GEMINI_ACP_DEFAULT_MODEL,
vec![],
GEMINI_ACP_DOC_URL,
vec![],
)
}

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_gemini_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 = PermissionMapping {
allow_option_id: Some("allow".to_string()),
reject_option_id: Some("reject".to_string()),
rejected_tool_status: sacp::schema::ToolCallStatus::Failed,
};

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

let provider_config = AcpProviderConfig {
command: resolved_command,
args,
env: vec![],
Comment on lines +56 to +59
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 Pass Goose's selected Gemini model into the ACP subprocess

Unlike the existing gemini-cli provider, this ACP provider never threads model.model_name into Gemini: it always spawns gemini --acp, and AcpProvider::stream() ignores _model_config when creating the session. As a result, any non-default model selected in Goose (for example flash/pro) is silently ignored and Gemini falls back to its own default model, even though Gemini CLI's current reference documents --model/-m for model selection (https://geminicli.com/docs/cli/cli-reference/).

Useful? React with 👍 / 👎.

env_remove: vec![],
Comment on lines +56 to +60
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve PATH enrichment when spawning Gemini ACP

In desktop installs where the app inherits a minimal PATH, the new provider can resolve the gemini wrapper but still fail to launch it. GeminiCliProvider::build_command() explicitly injects SearchPaths::builder().with_npm().path() before spawning for this reason, while spawn_acp_process() only inherits config.env; with env left empty here, npm/Homebrew locations (and the node interpreter used by many npm shims) are no longer added. That makes gemini-acp unusable in environments where the deprecated gemini-cli provider still works.

Useful? React with 👍 / 👎.

work_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
mcp_servers: extension_configs_to_mcp_servers(&extensions),
session_mode_id: Some(map_goose_mode(goose_mode)),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Derive the initial ACP mode from the session, not global config

This freezes session_mode_id from Config::get_goose_mode() at provider construction time. That breaks the common path where Goose changes the mode before the first prompt (ExecutionManager::get_or_create_session and Agent::restore_provider_from_session both call update_mode() pre-session): AcpProvider::update_mode() only updates its in-memory GooseMode, but session/new later still uses the stale session_mode_id. A new or resumed gemini-acp session opened in Chat/Approve/SmartApprove can therefore start its first turn in whatever global mode was active at startup (often yolo), which is a real approval/safety regression.

Useful? React with 👍 / 👎.

permission_mapping,
notification_callback: None,
};

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

fn map_goose_mode(goose_mode: GooseMode) -> String {
match goose_mode {
GooseMode::Auto => "yolo".to_string(),
GooseMode::Approve => "default".to_string(),
GooseMode::SmartApprove => "auto_edit".to_string(),
GooseMode::Chat => "plan".to_string(),
Comment on lines +76 to +79
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve Gemini ACP mode IDs after the first turn

This mapping is only used during session/new. After a gemini-acp session exists, Agent::update_goose_mode() goes through AcpProvider::update_mode(), which sends mode.to_string().to_lowercase() (auto, approve, smart-approve, chat) in session/set_mode (crates/goose/src/acp/provider.rs:288-304). Gemini's mode IDs here are yolo, default, auto_edit, and plan, so any mid-session mode change will either be rejected by the agent or leave the old approval policy active. That is a real safety/usability regression for users who switch from Auto to Approve/Chat after the session has started.

Useful? React with 👍 / 👎.

Comment thread
michaelneale marked this conversation as resolved.
}
}
2 changes: 1 addition & 1 deletion crates/goose/src/providers/gemini_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl ProviderDef for GeminiCliProvider {
ProviderMetadata::new(
GEMINI_CLI_PROVIDER_NAME,
"Gemini CLI",
"Execute Gemini models via gemini CLI tool",
"[Deprecated: use gemini-acp instead] Execute Gemini models via gemini CLI tool. Requires gemini CLI installed.",
GEMINI_CLI_DEFAULT_MODEL,
GEMINI_CLI_KNOWN_MODELS.to_vec(),
GEMINI_CLI_DOC_URL,
Expand Down
2 changes: 2 additions & 0 deletions crates/goose/src/providers/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::{
cursor_agent::CursorAgentProvider,
databricks::DatabricksProvider,
gcpvertexai::GcpVertexAIProvider,
gemini_acp::GeminiAcpProvider,
gemini_cli::GeminiCliProvider,
githubcopilot::GithubCopilotProvider,
google::GoogleProvider,
Expand Down Expand Up @@ -51,6 +52,7 @@ async fn init_registry() -> RwLock<ProviderRegistry> {
registry.register::<LocalInferenceProvider>(false);
registry.register::<ChatGptCodexProvider>(true);
registry.register::<ClaudeAcpProvider>(false);
registry.register::<GeminiAcpProvider>(false);
registry.register::<ClaudeCodeProvider>(true);
registry.register::<CodexAcpProvider>(false);
registry.register::<CodexProvider>(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 @@ -21,6 +21,7 @@ pub mod errors;
pub mod formats;
mod gcpauth;
pub mod gcpvertexai;
pub mod gemini_acp;
pub mod gemini_cli;
pub mod githubcopilot;
pub mod google;
Expand Down
9 changes: 9 additions & 0 deletions crates/goose/tests/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use goose::providers::codex_acp::CODEX_ACP_DEFAULT_MODEL;
use goose::providers::create_with_named_model;
use goose::providers::databricks::DATABRICKS_DEFAULT_MODEL;
use goose::providers::errors::ProviderError;
use goose::providers::gemini_acp::GEMINI_ACP_DEFAULT_MODEL;
use goose::providers::google::GOOGLE_DEFAULT_MODEL;
use goose::providers::litellm::LITELLM_DEFAULT_MODEL;
use goose::providers::openai::OPEN_AI_DEFAULT_MODEL;
Expand Down Expand Up @@ -890,6 +891,14 @@ async fn test_codex_acp_provider() -> Result<()> {
.await
}

// Requires: npm install -g @google/gemini-cli
#[tokio::test]
async fn test_gemini_acp_provider() -> Result<()> {
ProviderTestConfig::with_agentic_provider("gemini-acp", GEMINI_ACP_DEFAULT_MODEL, "gemini")
.run()
.await
}

#[ctor::dtor]
fn print_test_report() {
TEST_REPORT.print_summary();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: "Use Goose with Your AI Subscription"
description: "A quick update on using subscriptions for claude, gemini and codex"
authors:
- mic
---

You can use your subscriptions for codex, claude and gemini now with goose, thanks to ACP! (Agent Client Protocol).
Codex is also special in that you can login directly to chatgpt - nothing else needs to be installed.

Gemini natively supports ACP, so it now works with a gemini acp provider in goose. At the time of writing, claude requires just one utility installed just once.

<!--truncate-->

## Why subscriptions?

Well you can use what you already pay for. Obviously! and sessions and so on are still in goose.
ACP gives a deeper connection to these agents than using the CLI as providers. In this world - you can think of this as a stack of agents:
goose plugs into gemini via ACP (and other things, clients could plug in to goose!) but gemini (and also claude code) also act as an agent loop somewhat.
With ACP you are using the tools that are (mostly) in the underlying agent. Codex, however, is a full power LLM api, so you can use extensions natively in goose for that one.

## Claude Code — via ACP

If you have a Claude Code subscription, you can use it through goose via the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/). This requires installing a small adapter package:

```bash
npm install -g @zed-industries/claude-agent-acp
```

Then configure goose to use it via the claude acp extension (CLI or GUI)


Or set it via environment variables:

```bash
export GOOSE_PROVIDER=claude-acp
goose
```

goose passes your MCP extensions through to Claude via ACP, so any custom MCP servers you've configured in goose are available to the agent.

## ChatGPT — sign in with your account

If you have ChatGPT Plus or Pro, the `chatgpt_codex` provider lets you use goose with your existing account. Just pick ChatGPT when you are setting up the goose app for the first time (or changing to that provider)

The first time you run it, goose will open a browser window for you to sign in with your ChatGPT account. After that, your session is cached locally.

The recommended model is `gpt-5.3-codex`, which is the default. You can also select `gpt-5.4` (OpenAI's latest omni model) or `gpt-5.2-codex` from the model picker.

## Gemini — via ACP (native)

If you have a Google account with Gemini access, the Gemini CLI speaks ACP natively — no separate adapter needed. Just install the Gemini CLI itself:

```bash
npm install -g @google/gemini-cli
```

... and run `gemini` at least once.

On first run, Gemini CLI will ask you to authenticate with your Google account. After that, goose passes your extensions directly through to Gemini via ACP.

## What about the old CLI providers?

Goose previously supported `claude-code`, `codex`, and `gemini-cli` as "pass-through" CLI providers. These will be removed soon as ACP is the future!

## Quick reference

| Subscription | Provider | Install | Extensions |
|---|---|---|---|
| Claude Code | `claude-acp` | `npm install -g @zed-industries/claude-agent-acp` | ✅ via MCP |
| ChatGPT Plus/Pro | `chatgpt_codex` | Nothing — OAuth sign-in | ✅ via MCP |
| Gemini | `gemini-acp` | `npm install -g @google/gemini-cli` | ✅ via MCP |

Pick the one that matches what you're already paying for, and you're good to go.
10 changes: 1 addition & 9 deletions documentation/docs/getting-started/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,9 @@ goose automatically enables Anthropic's [prompt caching](https://platform.claude

### CLI Providers

goose also supports special "pass-through" providers that work with existing CLI tools, allowing you to use your subscriptions instead of paying per token:

| Provider | Description | Requirements |
|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Claude Code](https://www.anthropic.com/claude-code) (`claude-code`) | Uses Anthropic's Claude CLI tool with your Claude Code subscription. Provides access to Claude with 200K context limit. | Claude CLI installed and authenticated, active Claude Code subscription |
| [OpenAI Codex](https://developers.openai.com/codex/cli) (`codex`) | Uses OpenAI's Codex CLI tool with your ChatGPT Plus/Pro subscription. Provides access to GPT-5 models with up to 400K context limit. | Codex CLI installed and authenticated, active ChatGPT Plus/Pro subscription |
| [Cursor Agent](https://docs.cursor.com/en/cli/overview) (`cursor-agent`) | Uses Cursor's AI CLI tool with your Cursor subscription. Provides access to GPT-5, Claude 4, and other models through the cursor-agent command-line interface. | cursor-agent CLI installed and authenticated |
| [Gemini CLI](https://ai.google.dev/gemini-api/docs) (`gemini-cli`) | Uses Google's Gemini CLI tool with your Google AI subscription. Provides access to Gemini with 1M context limit. | Gemini CLI installed and authenticated |

:::tip CLI Providers
CLI providers are cost-effective alternatives that use your existing subscriptions. They work differently from API providers as they execute CLI commands and integrate with the tools' native capabilities. See the [CLI Providers guide](/docs/guides/cli-providers) for detailed setup instructions.
:::

### ACP Providers

Expand All @@ -76,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 |
| [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
See the [ACP Providers guide](/docs/guides/acp-providers) for detailed setup instructions.
Expand Down
Loading
Loading