diff --git a/.icons/gemini.svg b/.icons/gemini.svg
new file mode 100644
index 00000000..f1cf3575
--- /dev/null
+++ b/.icons/gemini.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/registry/coder-labs/modules/gemini/README.md b/registry/coder-labs/modules/gemini/README.md
new file mode 100644
index 00000000..65b9d9bc
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/README.md
@@ -0,0 +1,78 @@
+---
+display_name: Gemini CLI
+icon: ../../../../.icons/gemini.svg
+description: Run Gemini CLI in your workspace with AgentAPI integration
+verified: true
+tags: [agent, gemini, ai, google, tasks]
+---
+
+# Gemini CLI
+
+Run [Gemini CLI](https://ai.google.dev/gemini-api/docs/cli) in your workspace to access Google's Gemini AI models, and custom pre/post install scripts. This module integrates with [AgentAPI](https://github.com/coder/agentapi) for Coder Tasks compatibility.
+
+```tf
+module "gemini" {
+ source = "registry.coder.com/coder-labs/gemini/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ gemini_api_key = var.gemini_api_key
+ gemini_model = "gemini-2.5-pro"
+ install_gemini = true
+ gemini_version = "latest"
+ agentapi_version = "latest"
+}
+```
+
+## Prerequisites
+
+- You must add the [Coder Login](https://registry.coder.com/modules/coder-login/coder) module to your template
+- Node.js and npm will be installed automatically if not present
+
+## Usage Example
+
+- Example 1:
+
+```tf
+variable "gemini_api_key" {
+ type = string
+ description = "Gemini API key"
+ sensitive = true
+}
+
+module "gemini" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder-labs/gemini/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ gemini_api_key = var.gemini_api_key # we recommend providing this parameter inorder to have a smoother experience (i.e. no google sign-in)
+ gemini_model = "gemini-2.5-flash"
+ install_gemini = true
+ gemini_version = "latest"
+ gemini_instruction_prompt = "Start every response with `Gemini says:`"
+}
+```
+
+## How it Works
+
+- **Install**: The module installs Gemini CLI using npm (installs Node.js via NVM if needed)
+- **Instruction Prompt**: If `GEMINI_INSTRUCTION_PROMPT` and `GEMINI_START_DIRECTORY` are set, creates the directory (if needed) and writes the prompt to `GEMINI.md`
+- **Start**: Launches Gemini CLI in the specified directory, wrapped by AgentAPI
+- **Environment**: Sets `GEMINI_API_KEY`, `GOOGLE_GENAI_USE_VERTEXAI`, `GEMINI_MODEL` for the CLI (if variables provided)
+
+## Troubleshooting
+
+- If Gemini CLI is not found, ensure `install_gemini = true` and your API key is valid
+- Node.js and npm are installed automatically if missing (using NVM)
+- Check logs in `/home/coder/.gemini-module/` for install/start output
+- We highly recommend using the `gemini_api_key` variable, this also ensures smooth tasks running without needing to sign in to Google.
+
+> [!IMPORTANT]
+> To use tasks with Gemini CLI, ensure you have the `gemini_api_key` variable set, and **you pass the `AI Prompt` Parameter**.
+> By default we inject the "theme": "Default" and "selectedAuthType": "gemini-api-key" to your ~/.gemini/settings.json along with the coder mcp server.
+> In `gemini_instruction_prompt` and `AI Prompt` text we recommend using (\`\`) backticks instead of quotes to avoid escaping issues. Eg: gemini_instruction_prompt = "Start every response with \`Gemini says:\` "
+
+## References
+
+- [Gemini CLI Documentation](https://ai.google.dev/gemini-api/docs/cli)
+- [AgentAPI Documentation](https://github.com/coder/agentapi)
+- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents)
diff --git a/registry/coder-labs/modules/gemini/main.test.ts b/registry/coder-labs/modules/gemini/main.test.ts
new file mode 100644
index 00000000..181b6114
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/main.test.ts
@@ -0,0 +1,207 @@
+import {
+ test,
+ afterEach,
+ describe,
+ setDefaultTimeout,
+ beforeAll,
+ expect,
+} from "bun:test";
+import { execContainer, readFileContainer, runTerraformInit } from "~test";
+import {
+ loadTestFile,
+ writeExecutable,
+ setup as setupUtil,
+ execModuleScript,
+ expectAgentAPIStarted,
+} from "../../../coder/modules/agentapi/test-util";
+
+let cleanupFunctions: (() => Promise)[] = [];
+const registerCleanup = (cleanup: () => Promise) => {
+ cleanupFunctions.push(cleanup);
+};
+afterEach(async () => {
+ const cleanupFnsCopy = cleanupFunctions.slice().reverse();
+ cleanupFunctions = [];
+ for (const cleanup of cleanupFnsCopy) {
+ try {
+ await cleanup();
+ } catch (error) {
+ console.error("Error during cleanup:", error);
+ }
+ }
+});
+
+interface SetupProps {
+ skipAgentAPIMock?: boolean;
+ skipGeminiMock?: boolean;
+ moduleVariables?: Record;
+ agentapiMockScript?: string;
+}
+
+const setup = async (props?: SetupProps): Promise<{ id: string }> => {
+ const projectDir = "/home/coder/project";
+ const { id } = await setupUtil({
+ moduleDir: import.meta.dir,
+ moduleVariables: {
+ install_gemini: props?.skipGeminiMock ? "true" : "false",
+ install_agentapi: props?.skipAgentAPIMock ? "true" : "false",
+ gemini_model: "test-model",
+ ...props?.moduleVariables,
+ },
+ registerCleanup,
+ projectDir,
+ skipAgentAPIMock: props?.skipAgentAPIMock,
+ agentapiMockScript: props?.agentapiMockScript,
+ });
+ if (!props?.skipGeminiMock) {
+ await writeExecutable({
+ containerId: id,
+ filePath: "/usr/bin/gemini",
+ content: await loadTestFile(import.meta.dir, "gemini-mock.sh"),
+ });
+ }
+ return { id };
+};
+
+setDefaultTimeout(60 * 1000);
+
+describe("gemini", async () => {
+ beforeAll(async () => {
+ await runTerraformInit(import.meta.dir);
+ });
+
+ test("happy-path", async () => {
+ const { id } = await setup();
+ await execModuleScript(id);
+ await expectAgentAPIStarted(id);
+ });
+
+ test("install-gemini-version", async () => {
+ const version_to_install = "0.1.13";
+ const { id } = await setup({
+ skipGeminiMock: true,
+ moduleVariables: {
+ install_gemini: "true",
+ gemini_version: version_to_install,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await execContainer(id, [
+ "bash",
+ "-c",
+ `cat /home/coder/.gemini-module/install.log || true`,
+ ]);
+ expect(resp.stdout).toContain(version_to_install);
+ });
+
+ test("gemini-settings-json", async () => {
+ const settings = '{"foo": "bar"}';
+ const { id } = await setup({
+ moduleVariables: {
+ gemini_settings_json: settings,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/.gemini/settings.json");
+ expect(resp).toContain("foo");
+ expect(resp).toContain("bar");
+ });
+
+ test("gemini-api-key", async () => {
+ const apiKey = "test-api-key-123";
+ const { id } = await setup({
+ moduleVariables: {
+ gemini_api_key: apiKey,
+ },
+ });
+ await execModuleScript(id);
+
+ const resp = await readFileContainer(id, "/home/coder/.gemini-module/agentapi-start.log");
+ expect(resp).toContain("gemini_api_key provided !");
+ });
+
+ test("use-vertexai", async () => {
+ const { id } = await setup({
+ skipGeminiMock: false,
+ moduleVariables: {
+ use_vertexai: "true",
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/.gemini-module/install.log");
+ expect(resp).toContain('GOOGLE_GENAI_USE_VERTEXAI=\'true\'');
+ });
+
+ test("gemini-model", async () => {
+ const model = "gemini-2.5-pro";
+ const { id } = await setup({
+ skipGeminiMock: false,
+ moduleVariables: {
+ gemini_model: model,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/.gemini-module/install.log");
+ expect(resp).toContain(model);
+ });
+
+ test("pre-post-install-scripts", async () => {
+ const { id } = await setup({
+ moduleVariables: {
+ pre_install_script: "#!/bin/bash\necho 'pre-install-script'",
+ post_install_script: "#!/bin/bash\necho 'post-install-script'",
+ },
+ });
+ await execModuleScript(id);
+ const preInstallLog = await readFileContainer(id, "/home/coder/.gemini-module/pre_install.log");
+ expect(preInstallLog).toContain("pre-install-script");
+ const postInstallLog = await readFileContainer(id, "/home/coder/.gemini-module/post_install.log");
+ expect(postInstallLog).toContain("post-install-script");
+ });
+
+ test("folder-variable", async () => {
+ const folder = "/tmp/gemini-test-folder";
+ const { id } = await setup({
+ skipGeminiMock: false,
+ moduleVariables: {
+ folder,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/.gemini-module/install.log");
+ expect(resp).toContain(folder);
+ });
+
+ test("additional-extensions", async () => {
+ const additional = '{"custom": {"enabled": true}}';
+ const { id } = await setup({
+ moduleVariables: {
+ additional_extensions: additional,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/.gemini/settings.json");
+ expect(resp).toContain("custom");
+ expect(resp).toContain("enabled");
+ });
+
+ test("gemini-system-prompt", async () => {
+ const prompt = "This is a system prompt for Gemini.";
+ const { id } = await setup({
+ moduleVariables: {
+ gemini_system_prompt: prompt,
+ },
+ });
+ await execModuleScript(id);
+ const resp = await readFileContainer(id, "/home/coder/GEMINI.md");
+ expect(resp).toContain(prompt);
+ });
+
+ test("start-without-prompt", async () => {
+ const { id } = await setup();
+ await execModuleScript(id);
+ const prompt = await execContainer(id, ["ls", "-l", "/home/coder/GEMINI.md"]);
+ expect(prompt.exitCode).not.toBe(0);
+ expect(prompt.stderr).toContain("No such file or directory");
+ });
+});
diff --git a/registry/coder-labs/modules/gemini/main.tf b/registry/coder-labs/modules/gemini/main.tf
new file mode 100644
index 00000000..ab4fa945
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/main.tf
@@ -0,0 +1,215 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 2.7"
+ }
+ }
+}
+
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+data "coder_workspace" "me" {}
+
+data "coder_workspace_owner" "me" {}
+
+variable "order" {
+ type = number
+ description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
+ default = null
+}
+
+variable "group" {
+ type = string
+ description = "The name of a group that this app belongs to."
+ default = null
+}
+
+variable "icon" {
+ type = string
+ description = "The icon to use for the app."
+ default = "/icon/gemini.svg"
+}
+
+variable "folder" {
+ type = string
+ description = "The folder to run Gemini in."
+ default = "/home/coder"
+}
+
+variable "install_gemini" {
+ type = bool
+ description = "Whether to install Gemini."
+ default = true
+}
+
+variable "gemini_version" {
+ type = string
+ description = "The version of Gemini to install."
+ default = ""
+}
+
+variable "gemini_settings_json" {
+ type = string
+ description = "json to use in ~/.gemini/settings.json."
+ default = ""
+}
+
+variable "gemini_api_key" {
+ type = string
+ description = "Gemini API Key"
+ default = ""
+}
+
+variable "use_vertexai" {
+ type = bool
+ description = "Whether to use vertex ai"
+ default = false
+}
+
+variable "install_agentapi" {
+ type = bool
+ description = "Whether to install AgentAPI."
+ default = true
+}
+
+variable "agentapi_version" {
+ type = string
+ description = "The version of AgentAPI to install."
+ default = "v0.3.0"
+}
+
+variable "gemini_model" {
+ type = string
+ description = "The model to use for Gemini (e.g., gemini-2.5-pro)."
+ default = ""
+}
+
+variable "pre_install_script" {
+ type = string
+ description = "Custom script to run before installing Gemini."
+ default = null
+}
+
+variable "post_install_script" {
+ type = string
+ description = "Custom script to run after installing Gemini."
+ default = null
+}
+
+data "coder_parameter" "ai_prompt" {
+ type = "string"
+ name = "AI Prompt"
+ default = ""
+ description = "Initial prompt for the Gemini CLI"
+ mutable = true
+}
+
+variable "additional_extensions" {
+ type = string
+ description = "Additional extensions configuration in json format to append to the config."
+ default = null
+}
+
+variable "gemini_system_prompt" {
+ type = string
+ description = "System prompt for Gemini. It will be added to GEMINI.md in the specified folder."
+ default = ""
+}
+
+resource "coder_env" "gemini_api_key" {
+ agent_id = var.agent_id
+ name = "GEMINI_API_KEY"
+ value = var.gemini_api_key
+}
+
+resource "coder_env" "gemini_use_vertex_ai" {
+ agent_id = var.agent_id
+ name = "GOOGLE_GENAI_USE_VERTEXAI"
+ value = var.use_vertexai
+}
+
+locals {
+ base_extensions = <<-EOT
+{
+ "coder": {
+ "args": [
+ "exp",
+ "mcp",
+ "server"
+ ],
+ "command": "coder",
+ "description": "Report ALL tasks and statuses (in progress, done, failed) you are working on.",
+ "enabled": true,
+ "env": {
+ "CODER_MCP_APP_STATUS_SLUG": "${local.app_slug}",
+ "CODER_MCP_AI_AGENTAPI_URL": "http://localhost:3284"
+ },
+ "name": "Coder",
+ "timeout": 3000,
+ "type": "stdio",
+ "trust": true
+ }
+}
+EOT
+
+ app_slug = "gemini"
+ install_script = file("${path.module}/scripts/install.sh")
+ start_script = file("${path.module}/scripts/start.sh")
+ module_dir_name = ".gemini-module"
+}
+
+module "agentapi" {
+ source = "registry.coder.com/coder/agentapi/coder"
+ version = "1.0.0"
+
+ agent_id = var.agent_id
+ web_app_slug = local.app_slug
+ web_app_order = var.order
+ web_app_group = var.group
+ web_app_icon = var.icon
+ web_app_display_name = "Gemini"
+ cli_app_slug = "${local.app_slug}-cli"
+ cli_app_display_name = "Gemini CLI"
+ module_dir_name = local.module_dir_name
+ install_agentapi = var.install_agentapi
+ agentapi_version = var.agentapi_version
+ pre_install_script = var.pre_install_script
+ post_install_script = var.post_install_script
+ start_script = <<-EOT
+ #!/bin/bash
+ set -o errexit
+ set -o pipefail
+
+ echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
+ chmod +x /tmp/start.sh
+ GEMINI_API_KEY='${var.gemini_api_key}' \
+ GOOGLE_GENAI_USE_VERTEXAI='${var.use_vertexai}' \
+ GEMINI_MODEL='${var.gemini_model}' \
+ GEMINI_START_DIRECTORY='${var.folder}' \
+ GEMINI_TASK_PROMPT='${base64encode(data.coder_parameter.ai_prompt.value)}' \
+ /tmp/start.sh
+ EOT
+
+ install_script = <<-EOT
+ #!/bin/bash
+ set -o errexit
+ set -o pipefail
+
+ echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
+ chmod +x /tmp/install.sh
+ ARG_INSTALL='${var.install_gemini}' \
+ ARG_GEMINI_VERSION='${var.gemini_version}' \
+ ARG_GEMINI_CONFIG='${base64encode(var.gemini_settings_json)}' \
+ BASE_EXTENSIONS='${base64encode(replace(local.base_extensions, "'", "'\\''"))}' \
+ ADDITIONAL_EXTENSIONS='${base64encode(replace(var.additional_extensions != null ? var.additional_extensions : "", "'", "'\\''"))}' \
+ GEMINI_START_DIRECTORY='${var.folder}' \
+ GEMINI_INSTRUCTION_PROMPT='${base64encode(var.gemini_system_prompt)}' \
+ /tmp/install.sh
+ EOT
+}
\ No newline at end of file
diff --git a/registry/coder-labs/modules/gemini/scripts/install.sh b/registry/coder-labs/modules/gemini/scripts/install.sh
new file mode 100644
index 00000000..a800dbd2
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/scripts/install.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+
+BOLD='\033[0;1m'
+
+# Function to check if a command exists
+command_exists() {
+ command -v "$1" >/dev/null 2>&1
+}
+
+set -o nounset
+
+ARG_GEMINI_CONFIG=$(echo -n "$ARG_GEMINI_CONFIG" | base64 -d)
+BASE_EXTENSIONS=$(echo -n "$BASE_EXTENSIONS" | base64 -d)
+ADDITIONAL_EXTENSIONS=$(echo -n "$ADDITIONAL_EXTENSIONS" | base64 -d)
+GEMINI_INSTRUCTION_PROMPT=$(echo -n "$GEMINI_INSTRUCTION_PROMPT" | base64 -d)
+
+echo "--------------------------------"
+printf "gemini_config: %s\n" "$ARG_GEMINI_CONFIG"
+printf "install: %s\n" "$ARG_INSTALL"
+printf "gemini_version: %s\n" "$ARG_GEMINI_VERSION"
+echo "--------------------------------"
+
+set +o nounset
+
+function install_node() {
+ # borrowed from claude-code module
+ if ! command_exists npm; then
+ printf "npm not found, checking for Node.js installation...\n"
+ if ! command_exists node; then
+ printf "Node.js not found, installing Node.js via NVM...\n"
+ export NVM_DIR="$HOME/.nvm"
+ if [ ! -d "$NVM_DIR" ]; then
+ mkdir -p "$NVM_DIR"
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
+ else
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
+ fi
+
+ nvm install --lts
+ nvm use --lts
+ nvm alias default node
+
+ printf "Node.js installed: %s\n" "$(node --version)"
+ printf "npm installed: %s\n" "$(npm --version)"
+ else
+ printf "Node.js is installed but npm is not available. Please install npm manually.\n"
+ exit 1
+ fi
+ fi
+}
+
+function install_gemini() {
+ if [ "${ARG_INSTALL}" = "true" ]; then
+ # we need node to install and run gemini-cli
+ install_node
+
+ # If nvm does not exist, we will create a global npm directory (this os to prevent the possibility of EACCESS issues on npm -g)
+ if ! command_exists nvm; then
+ printf "which node: %s\n" "$(which node)"
+ printf "which npm: %s\n" "$(which npm)"
+
+ # Create a directory for global packages
+ mkdir -p "$HOME"/.npm-global
+
+ # Configure npm to use it
+ npm config set prefix "$HOME/.npm-global"
+
+ # Add to PATH for current session
+ export PATH="$HOME/.npm-global/bin:$PATH"
+
+ # Add to shell profile for future sessions
+ if ! grep -q "export PATH=$HOME/.npm-global/bin:\$PATH" ~/.bashrc; then
+ echo "export PATH=$HOME/.npm-global/bin:\$PATH" >> ~/.bashrc
+ fi
+ fi
+
+ printf "%s Installing Gemini CLI\n" "${BOLD}"
+
+ if [ -n "$ARG_GEMINI_VERSION" ]; then
+ npm install -g "@google/gemini-cli@$ARG_GEMINI_VERSION"
+ else
+ npm install -g "@google/gemini-cli"
+ fi
+ printf "%s Successfully installed Gemini CLI. Version: %s\n" "${BOLD}" "$(gemini --version)"
+ fi
+}
+
+function populate_settings_json() {
+ if [ "${ARG_GEMINI_CONFIG}" != "" ]; then
+ SETTINGS_PATH="$HOME/.gemini/settings.json"
+ mkdir -p "$(dirname "$SETTINGS_PATH")"
+ printf "Custom gemini_config is provided !\n"
+ echo "${ARG_GEMINI_CONFIG}" > "$HOME/.gemini/settings.json"
+ else
+ printf "No custom gemini_config provided, using default settings.json.\n"
+ append_extensions_to_settings_json
+ fi
+}
+
+function append_extensions_to_settings_json() {
+ SETTINGS_PATH="$HOME/.gemini/settings.json"
+ mkdir -p "$(dirname "$SETTINGS_PATH")"
+ printf "[append_extensions_to_settings_json] Starting extension merge process...\n"
+ if [ -z "${BASE_EXTENSIONS:-}" ]; then
+ printf "[append_extensions_to_settings_json] BASE_EXTENSIONS is empty, skipping merge.\n"
+ return
+ fi
+ if [ ! -f "$SETTINGS_PATH" ]; then
+ printf "%s does not exist. Creating with merged mcpServers structure.\n" "$SETTINGS_PATH"
+ # If ADDITIONAL_EXTENSIONS is not set or empty, use '{}'
+ ADD_EXT_JSON='{}'
+ if [ -n "${ADDITIONAL_EXTENSIONS:-}" ]; then
+ ADD_EXT_JSON="$ADDITIONAL_EXTENSIONS"
+ fi
+ printf '{"mcpServers":%s}\n' "$(jq -s 'add' <(echo "$BASE_EXTENSIONS") <(echo "$ADD_EXT_JSON"))" > "$SETTINGS_PATH"
+ fi
+
+ # Prepare temp files
+ TMP_SETTINGS=$(mktemp)
+
+ # If ADDITIONAL_EXTENSIONS is not set or empty, use '{}'
+ ADD_EXT_JSON='{}'
+ if [ -n "${ADDITIONAL_EXTENSIONS:-}" ]; then
+ printf "[append_extensions_to_settings_json] ADDITIONAL_EXTENSIONS is set.\n"
+ ADD_EXT_JSON="$ADDITIONAL_EXTENSIONS"
+ else
+ printf "[append_extensions_to_settings_json] ADDITIONAL_EXTENSIONS is empty or not set.\n"
+ fi
+
+ printf "[append_extensions_to_settings_json] Merging BASE_EXTENSIONS and ADDITIONAL_EXTENSIONS into mcpServers...\n"
+ jq --argjson base "$BASE_EXTENSIONS" --argjson add "$ADD_EXT_JSON" \
+ '.mcpServers = (.mcpServers // {} + $base + $add)' \
+ "$SETTINGS_PATH" > "$TMP_SETTINGS" && mv "$TMP_SETTINGS" "$SETTINGS_PATH"
+
+ # Add theme and selectedAuthType fields
+ jq '.theme = "Default" | .selectedAuthType = "gemini-api-key"' "$SETTINGS_PATH" > "$TMP_SETTINGS" && mv "$TMP_SETTINGS" "$SETTINGS_PATH"
+
+ printf "[append_extensions_to_settings_json] Merge complete.\n"
+}
+
+function add_instruction_prompt_if_exists() {
+ if [ -n "${GEMINI_INSTRUCTION_PROMPT:-}" ]; then
+ if [ -d "${GEMINI_START_DIRECTORY}" ]; then
+ printf "Directory '%s' exists. Changing to it.\\n" "${GEMINI_START_DIRECTORY}"
+ cd "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not change to directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+ else
+ printf "Directory '%s' does not exist. Creating and changing to it.\\n" "${GEMINI_START_DIRECTORY}"
+ mkdir -p "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not create directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+ cd "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not change to directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+ fi
+ touch GEMINI.md
+ printf "Setting GEMINI.md\n"
+ echo "${GEMINI_INSTRUCTION_PROMPT}" > GEMINI.md
+ else
+ printf "GEMINI.md is not set.\n"
+ fi
+}
+
+
+# Install Gemini
+install_gemini
+gemini --version
+populate_settings_json
+add_instruction_prompt_if_exists
+
diff --git a/registry/coder-labs/modules/gemini/scripts/start.sh b/registry/coder-labs/modules/gemini/scripts/start.sh
new file mode 100644
index 00000000..00e0b5ed
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/scripts/start.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# Load shell environment
+source "$HOME"/.bashrc
+
+command_exists() {
+ command -v "$1" >/dev/null 2>&1
+}
+
+if [ -f "$HOME/.nvm/nvm.sh" ]; then
+ source "$HOME"/.nvm/nvm.sh
+else
+ export PATH="$HOME/.npm-global/bin:$PATH"
+fi
+
+printf "Version: %s\n" "$(gemini --version)"
+
+GEMINI_TASK_PROMPT=$(echo -n "$GEMINI_TASK_PROMPT" | base64 -d)
+
+if command_exists gemini; then
+ printf "Gemini is installed\n"
+else
+ printf "Error: Gemini is not installed. Please enable install_gemini or install it manually :)\n"
+ exit 1
+fi
+
+if [ -d "${GEMINI_START_DIRECTORY}" ]; then
+ printf "Directory '%s' exists. Changing to it.\\n" "${GEMINI_START_DIRECTORY}"
+ cd "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not change to directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+else
+ printf "Directory '%s' does not exist. Creating and changing to it.\\n" "${GEMINI_START_DIRECTORY}"
+ mkdir -p "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not create directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+ cd "${GEMINI_START_DIRECTORY}" || {
+ printf "Error: Could not change to directory '%s'.\\n" "${GEMINI_START_DIRECTORY}"
+ exit 1
+ }
+fi
+
+if [ -n "$GEMINI_TASK_PROMPT" ]; then
+ printf "Running the task prompt %s\n" "$GEMINI_TASK_PROMPT"
+ PROMPT="Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GEMINI_TASK_PROMPT"
+ GEMINI_ARGS=(--prompt-interactive "$PROMPT")
+else
+ printf "No task prompt given.\n"
+ GEMINI_ARGS=()
+fi
+
+if [ -n "$GEMINI_API_KEY" ]; then
+ printf "gemini_api_key provided !\n"
+else
+ printf "gemini_api_key not provided\n"
+fi
+
+# use low width to fit in the tasks UI sidebar. height is adjusted so that width x height ~= 80x1000 characters
+# are visible in the terminal screen by default.
+agentapi server --term-width 67 --term-height 1190 -- gemini "${GEMINI_ARGS[@]}"
\ No newline at end of file
diff --git a/registry/coder-labs/modules/gemini/testdata/gemini-mock.sh b/registry/coder-labs/modules/gemini/testdata/gemini-mock.sh
new file mode 100644
index 00000000..53c9c41d
--- /dev/null
+++ b/registry/coder-labs/modules/gemini/testdata/gemini-mock.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [[ "$1" == "--version" ]]; then
+ echo "HELLO: $(bash -c env)"
+ echo "gemini version v2.5.0"
+ exit 0
+fi
+
+set -e
+
+while true; do
+ echo "$(date) - gemini-mock"
+ sleep 15
+done
\ No newline at end of file