diff --git a/messages/en-US.json b/messages/en-US.json
index 02c022e35..46f255c39 100644
--- a/messages/en-US.json
+++ b/messages/en-US.json
@@ -1785,6 +1785,7 @@
"aiClientConfigDescriptionClaude": "Anthropic's agentic coding tool for the terminal.",
"aiClientConfigDescriptionCodex": "OpenAI's agentic coding tool for the terminal.",
"aiClientConfigDescriptionOpencode": "Open source terminal coding agent.",
+ "aiClientConfigDescriptionGemini": "Google's agentic coding tool for the terminal.",
"aiClientConfigSetup": "Setup",
"aiClientConfigTabCli": "Automatic (CLI)",
"aiClientConfigTabManual": "Manual Configuration",
diff --git a/public/third-party/gemini-dark.svg b/public/third-party/gemini-dark.svg
new file mode 100644
index 000000000..03c310a83
--- /dev/null
+++ b/public/third-party/gemini-dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/third-party/gemini-light.svg b/public/third-party/gemini-light.svg
new file mode 100644
index 000000000..46647c7ff
--- /dev/null
+++ b/public/third-party/gemini-light.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/ai-client-config/AiClientConfigSection.tsx b/src/components/ai-client-config/AiClientConfigSection.tsx
index 955dfb4a9..d4f97e5f9 100644
--- a/src/components/ai-client-config/AiClientConfigSection.tsx
+++ b/src/components/ai-client-config/AiClientConfigSection.tsx
@@ -49,6 +49,10 @@ const CLIENT_LOGOS = {
opencode: {
light: "/third-party/opencode-dark.svg",
dark: "/third-party/opencode-light.svg"
+ },
+ gemini: {
+ light: "/third-party/gemini-dark.svg",
+ dark: "/third-party/gemini-light.svg"
}
} as const;
@@ -65,7 +69,8 @@ export function AiClientConfigSection({
const descriptions: Record = {
claude: t("aiClientConfigDescriptionClaude"),
codex: t("aiClientConfigDescriptionCodex"),
- opencode: t("aiClientConfigDescriptionOpencode")
+ opencode: t("aiClientConfigDescriptionOpencode"),
+ gemini: t("aiClientConfigDescriptionGemini")
};
return (
diff --git a/src/lib/aiClientConfig.ts b/src/lib/aiClientConfig.ts
index 37fe7cd16..1950c4e6c 100644
--- a/src/lib/aiClientConfig.ts
+++ b/src/lib/aiClientConfig.ts
@@ -1,10 +1,16 @@
-export const AI_CLIENT_IDS = ["claude", "codex", "opencode"] as const;
+export const AI_CLIENT_IDS = [
+ "claude",
+ "codex",
+ "opencode",
+ "gemini"
+] as const;
export type AiClientId = (typeof AI_CLIENT_IDS)[number];
export const AI_CLIENT_NAMES: Record = {
claude: "Claude Code",
codex: "Codex",
- opencode: "OpenCode"
+ opencode: "OpenCode",
+ gemini: "Gemini CLI"
};
/** Auth as supplied by callers: the real key isn't fetched yet. */
@@ -74,7 +80,7 @@ export function aiConfigBlockHasPlaceholders(block: AiConfigBlock): boolean {
}
function buildCli(
- clientArg: "claude" | "codex" | "opencode",
+ clientArg: "claude" | "codex" | "opencode" | "gemini",
auth: AiClientAuth,
resourceNiceId?: string
): AiConfigBlock[] {
@@ -351,6 +357,49 @@ function buildOpencodeGuide(
};
}
+function buildGeminiGuide(
+ endpoint: string,
+ auth: AiClientAuth,
+ resourceNiceId?: string
+): AiClientGuide {
+ const defaultEnv = block(
+ "gemini-default-env",
+ "~/.gemini/.env",
+ (key) =>
+ [
+ `GOOGLE_GEMINI_BASE_URL=${endpoint}`,
+ `GEMINI_API_KEY=${auth.mode === "keyed" ? key : "none"}`
+ ].join("\n"),
+ auth
+ );
+
+ const defaultShell = block(
+ "gemini-default-shell",
+ "Shell",
+ (key) =>
+ [
+ `export GOOGLE_GEMINI_BASE_URL=${endpoint}`,
+ `export GEMINI_API_KEY=${auth.mode === "keyed" ? key : "none"}`,
+ "gemini"
+ ].join("\n"),
+ auth
+ );
+
+ return {
+ id: "gemini",
+ name: AI_CLIENT_NAMES.gemini,
+ cli: buildCli("gemini", auth, resourceNiceId),
+ presets: [
+ {
+ id: "default",
+ label: "Default",
+ relation: "options",
+ blocks: [defaultEnv, defaultShell]
+ }
+ ]
+ };
+}
+
const GUIDE_BUILDERS: Record<
AiClientId,
(
@@ -361,7 +410,8 @@ const GUIDE_BUILDERS: Record<
> = {
claude: buildClaudeGuide,
codex: buildCodexGuide,
- opencode: buildOpencodeGuide
+ opencode: buildOpencodeGuide,
+ gemini: buildGeminiGuide
};
export function buildAiClientGuide(