Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
45d2390
fix: add --type flag and decode ARGS in start_script
Harsh9485 Mar 20, 2026
64fa3e8
fix: add nodejs install function
Harsh9485 Mar 21, 2026
886f556
feat: add enable_state_persistence field
Harsh9485 Mar 22, 2026
5a7cfaf
fix: directory path and typos
Harsh9485 Mar 22, 2026
4994200
fix: style
Harsh9485 Mar 22, 2026
753e417
fix: update the agentapi version and improve script logic
Harsh9485 Mar 23, 2026
610c67a
Merge branch 'main' into gemini-session-resume
Harsh9485 Mar 23, 2026
5d0b10b
Merge branch 'main' into gemini-session-resume
Harsh9485 Mar 26, 2026
531940d
feat: add continue variable, improve tests, and update README
Harsh9485 Mar 27, 2026
c961ee0
Merge branch 'gemini-session-resume' of github.com:Harsh9485/registry…
Harsh9485 Mar 27, 2026
ec7fdb6
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 1, 2026
79377fe
fix: update sitting.json for MPC server configuration
Harsh9485 Apr 1, 2026
a7f7992
Merge branch 'gemini-session-resume' of github.com:Harsh9485/registry…
Harsh9485 Apr 1, 2026
39e5ef2
fix: trust folder issue
Harsh9485 Apr 2, 2026
f824fcf
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 3, 2026
8ee19cd
fix: correct schema for trustedfolder.json
Harsh9485 Apr 3, 2026
17ade9f
Merge branch 'gemini-session-resume' of github.com:Harsh9485/registry…
Harsh9485 Apr 3, 2026
060e75e
fix: main.test.ts and remove trustedfolder.json code
Harsh9485 Apr 3, 2026
b16b17d
fix: update main.tftest.hcl file
Harsh9485 Apr 3, 2026
dfea777
fix: update main.tftest.hcl and MCP configuration JSON
Harsh9485 Apr 6, 2026
574e3f9
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 6, 2026
180ed2c
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 18, 2026
01091d9
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 23, 2026
c6605b0
Merge branch 'main' into gemini-session-resume
Harsh9485 Apr 25, 2026
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
13 changes: 13 additions & 0 deletions registry/coder-labs/modules/gemini/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ module "gemini" {
> [!WARNING]
> YOLO mode automatically approves all tool calls without user confirmation. The agent has access to your machine's file system and terminal. Only enable in trusted, isolated environments.

## State Persistence

AgentAPI can save and restore its conversation state to disk across workspace restarts. This complements `continue` (which resumes the Gemini CLI session) by also preserving the AgentAPI-level context. Enabled by default, requires agentapi >= v0.12.0 (older versions skip it with a warning).

Comment thread
Harsh9485 marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P2 continue in backticks implies a command or flag, but it doesn't exist in this module. The script uses --resume. (Hisoka P2, Leorio Nit, Pen Botter Nit)

grep -n "continue" registry/coder-labs/modules/gemini/main.tf returns no results. This text appears to be copied from the codex module's README, which does have a continue variable. A reader searching for continue in this codebase will find nothing.

If this refers to the --resume flag, call it --resume. If it's a Gemini CLI concept, link or explain it.

Nit The ## State Persistence heading breaks the heading hierarchy. ### Using Vertex AI (Enterprise) was previously a child of ## Examples. Now it appears to be a child of ## State Persistence, which has nothing to do with Vertex AI. Move this section after the Vertex AI subsection, or place it before ## Troubleshooting. (Leorio Nit, Pen Botter Nit)

🤖

To disable:

```tf
module "gemini" {
# ... other config
enable_state_persistence = false
}
```

### Using Vertex AI (Enterprise)

For enterprise users who prefer Google's Vertex AI platform:
Expand Down
59 changes: 33 additions & 26 deletions registry/coder-labs/modules/gemini/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ variable "icon" {
variable "folder" {
type = string
description = "The folder to run Gemini in."
default = "/home/coder"
default = "/home/coder/project"
}
Comment thread
Harsh9485 marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P1 Default folder changed from /home/coder to /home/coder/project. This is an undeclared breaking change. (Luffy P1, Hisoka P1, Meruem P1, Bisky P2, Mafuuu P2, Mafu-san P2, Kurapika P2)

Every existing user relying on the default gets a different working directory on upgrade. Worse, the session resume feature this PR adds would fail for exactly the users this change silently migrates: existing session state at /home/coder/.gemini/ won't be found at /home/coder/project/.gemini/.

The PR description marks "Breaking change: No" and uses a minor version bump (3.1.0). Per registry conventions, breaking changes require a major bump. If this change is intentional, it needs a major version bump and a migration note. If accidental, revert it.

🤖


variable "install_gemini" {
Expand Down Expand Up @@ -126,6 +126,12 @@ variable "enable_yolo_mode" {
default = false
}

variable "enable_state_persistence" {
type = bool
description = "Enable AgentAPI conversation state persistence across restarts."
default = true
Comment thread
Harsh9485 marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P1 enable_state_persistence defaults to true, but agentapi_version defaults to v0.10.0, which is below the >= v0.12.0 requirement stated in the README. (Mafuuu P1, Mafu-san P1, Meruem P1, Hisoka P2, Kurapika P2, Luffy P2)

A user who accepts all defaults gets enable_state_persistence = true with an agentapi binary that can't support it. The agentapi module gracefully skips persistence with a warning for old versions, but the default configuration enables a feature that cannot work. The codex module gets this right by defaulting agentapi_version to v0.12.1 when enabling state persistence.

Either bump the default agentapi_version to at least v0.12.0, or default enable_state_persistence to false.

🤖

}

resource "coder_env" "gemini_api_key" {
agent_id = var.agent_id
name = "GEMINI_API_KEY"
Expand Down Expand Up @@ -177,23 +183,24 @@ EOT

module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "2.0.0"

agent_id = var.agent_id
folder = local.folder
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
install_script = <<-EOT
version = "2.2.0"

agent_id = var.agent_id
folder = local.folder
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
enable_state_persistence = var.enable_state_persistence
pre_install_script = var.pre_install_script
post_install_script = var.post_install_script
install_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail
Expand All @@ -209,20 +216,20 @@ module "agentapi" {
GEMINI_SYSTEM_PROMPT='${base64encode(var.gemini_system_prompt)}' \
/tmp/install.sh
EOT
start_script = <<-EOT
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_API_KEY='${var.gemini_api_key}' \
GOOGLE_GENAI_USE_VERTEXAI='${var.use_vertexai}' \
GEMINI_YOLO_MODE='${var.enable_yolo_mode}' \
GEMINI_MODEL='${var.gemini_model}' \
GEMINI_START_DIRECTORY='${var.folder}' \
GEMINI_TASK_PROMPT='${var.task_prompt}' \
GEMINI_API_KEY='${base64encode(var.gemini_api_key)}' \
GOOGLE_API_KEY='${base64encode(var.gemini_api_key)}' \
GOOGLE_GENAI_USE_VERTEXAI='${base64encode(var.use_vertexai)}' \
GEMINI_YOLO_MODE='${base64encode(var.enable_yolo_mode)}' \
GEMINI_MODEL='${base64encode(var.gemini_model)}' \
GEMINI_START_DIRECTORY='${base64encode(var.folder)}' \
GEMINI_TASK_PROMPT='${base64encode(var.task_prompt)}' \
/tmp/start.sh
EOT
}
Expand Down
82 changes: 82 additions & 0 deletions registry/coder-labs/modules/gemini/main.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
run "test_gemini_basic" {
command = plan
Comment thread
Harsh9485 marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P3 Every test assertion checks that a variable equals what it was just set to, or that a default equals its declared default. This proves Terraform can assign variables, not that the module works. (Bisky P1, Meruem P3, Hisoka Obs)

test_enable_state_persistence_default asserts var.enable_state_persistence == true, which is tautological. None of the tests verify that enable_state_persistence actually flows through to the agentapi module, that the start_script contains expected content, or that the base64 encoding works. The only slightly real assertion is test_gemini_with_api_key checking coder_env.gemini_api_key[0].value.

Plan-level assertions on module outputs or resource attributes would catch wiring errors. Having a test file is better than not, but these particular tests create a false sense of coverage.

PS. Missing newline at end of file (line 82).

🤖


variables {
agent_id = "test-agent-123"
folder = "/home/coder/projects"
}

assert {
condition = var.agent_id == "test-agent-123"
error_message = "Agent ID variable should be set correctly"
}

assert {
condition = var.folder == "/home/coder/projects"
error_message = "Folder variable should be set correctly"
}

assert {
condition = var.install_gemini == true
error_message = "install_gemini should default to true"
}

assert {
condition = var.install_agentapi == true
error_message = "install_agentapi should default to true"
}

assert {
condition = var.use_vertexai == false
error_message = "use_vertexai should default to false"
}

assert {
condition = var.enable_yolo_mode == false
error_message = "enable_yolo_mode should default to false"
}
}

run "test_gemini_with_api_key" {
command = plan

variables {
agent_id = "test-agent-456"
folder = "/home/coder"
gemini_api_key = "test-api-key-123"
}

assert {
condition = coder_env.gemini_api_key[0].value == "test-api-key-123"
error_message = "Gemini API key value should match the input"
}
}

run "test_enable_state_persistence_default" {
command = plan

variables {
agent_id = "test-agent"
folder = "/home/coder"
}

assert {
condition = var.enable_state_persistence == true
error_message = "enable_state_persistence should default to true"
}
}

run "test_disable_state_persistence" {
command = plan

variables {
agent_id = "test-agent"
folder = "/home/coder"
enable_state_persistence = false
}

assert {
condition = var.enable_state_persistence == false
error_message = "enable_state_persistence should be false when explicitly disabled"
}
}
57 changes: 39 additions & 18 deletions registry/coder-labs/modules/gemini/scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ set -o pipefail

source "$HOME"/.bashrc

set -o nounset

GEMINI_API_KEY=$(echo -n "$GEMINI_API_KEY" | base64 -d)
GOOGLE_API_KEY=$(echo -n "$GOOGLE_API_KEY" | base64 -d)
GOOGLE_GENAI_USE_VERTEXAI=$(echo -n "$GOOGLE_GENAI_USE_VERTEXAI" | base64 -d)
GEMINI_YOLO_MODE=$(echo -n "$GEMINI_YOLO_MODE" | base64 -d)
GEMINI_MODEL=$(echo -n "$GEMINI_MODEL" | base64 -d)
GEMINI_START_DIRECTORY=$(echo -n "$GEMINI_START_DIRECTORY" | base64 -d)
GEMINI_TASK_PROMPT=$(echo -n "$GEMINI_TASK_PROMPT" | base64 -d)

set +o nounset

command_exists() {
command -v "$1" > /dev/null 2>&1
}
Expand Down Expand Up @@ -44,22 +56,6 @@ else
}
fi

if [ -n "$GEMINI_TASK_PROMPT" ]; then
printf "Running automated task: %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"
PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" > "$PROMPT_FILE"
GEMINI_ARGS=(--prompt-interactive "$PROMPT")
else
printf "Starting Gemini CLI in interactive mode.\n"
GEMINI_ARGS=()
fi

if [ -n "$GEMINI_YOLO_MODE" ] && [ "$GEMINI_YOLO_MODE" = "true" ]; then
printf "YOLO mode enabled - will auto-approve all tool calls\n"
GEMINI_ARGS+=(--yolo)
fi

if [ -n "$GEMINI_API_KEY" ] || [ -n "$GOOGLE_API_KEY" ]; then
if [ -n "$GOOGLE_GENAI_USE_VERTEXAI" ] && [ "$GOOGLE_GENAI_USE_VERTEXAI" = "true" ]; then
printf "Using Vertex AI with API key\n"
Expand All @@ -68,7 +64,32 @@ if [ -n "$GEMINI_API_KEY" ] || [ -n "$GOOGLE_API_KEY" ]; then
fi
else
printf "No API key provided (neither GEMINI_API_KEY nor GOOGLE_API_KEY)\n"
exit 1
fi
Comment thread
Harsh9485 marked this conversation as resolved.
Comment thread
Harsh9485 marked this conversation as resolved.

if [ -n "$GEMINI_YOLO_MODE" ] && [ "$GEMINI_YOLO_MODE" = "true" ]; then
printf "YOLO mode enabled - will auto-approve all tool calls\n"
GEMINI_ARGS=(--yolo)
fi
Comment thread
Harsh9485 marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P2 GEMINI_ARGS is never initialized when YOLO mode is off (the common case). (Meruem P1, Mafu-san P1, Bisky P1, Hisoka P2, Mafuuu P2, Luffy P2)

When GEMINI_YOLO_MODE != "true", GEMINI_ARGS is never declared. Lines 78, 88, and 91 use += on an unset variable. This works because nounset is disabled at line 17, but it's correct by coincidence, not construction. The old code always initialized GEMINI_ARGS explicitly. If anyone re-enables nounset later in the script, this breaks.

Add GEMINI_ARGS=() before this conditional. The codex module initializes CODEX_ARGS=() unconditionally before any appends.

PS. Line 91 (GEMINI_ARGS+=()) is a no-op that does nothing. Remove it or replace it with the initialization that's actually needed up here.

🤖


agentapi server --term-width 67 --term-height 1190 -- \
bash -c "$(printf '%q ' gemini "${GEMINI_ARGS[@]}")"
SESSION_FOLDER_NAME=$(basename "${GEMINI_START_DIRECTORY}")
if [ -d "$GEMINI_START_DIRECTORY/.gemini/tmp/$SESSION_FOLDER_NAME/chats/" ]; then
printf "Existing Gemini chats detected. Starting Gemini CLI in interactive mode with existing chats.\n"
Comment thread
Harsh9485 marked this conversation as resolved.
Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P2 enable_state_persistence and --resume are presented as one feature but are completely independent. (Kurapika P1, Meruem P2, Mafu-san P2)

enable_state_persistence passes through to the agentapi module (main.tf:200) and controls AgentAPI conversation state. The --resume flag here fires whenever the chat directory exists, with no variable to disable it. A user who sets enable_state_persistence = false to opt out of all persistence still gets --resume forced on. There is no way to start a fresh Gemini session after chats have been created.

Either add a separate variable to control Gemini CLI resume behavior, or document clearly that enable_state_persistence only controls AgentAPI state and Gemini CLI resume is always active when prior chats exist.

Obs The session detection path (.gemini/tmp/$SESSION_FOLDER_NAME/chats/) is an undocumented Gemini CLI implementation detail. If a future CLI version changes its storage layout, resume silently stops working with no error, the script just falls through to starting a new session. Worth a comment documenting which CLI version this was verified against.

🤖

GEMINI_ARGS+=(--resume)
agentapi server --type gemini --term-width 67 --term-height 1190 -- \
Comment thread
Harsh9485 marked this conversation as resolved.
Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P1 Task prompt is silently dropped when resuming an existing session. (Bisky P1, Hisoka P1, Mafuuu P1, Mafu-san P1, Meruem P1, Kurapika P1, Luffy P1)

When the chat directory exists, the script takes the resume branch and skips the GEMINI_TASK_PROMPT logic entirely (lines 83-88 are in the else branch). A user who configures task_prompt = "Fix the tests" and restarts a workspace gets their prompt silently ignored. The old code applied task_prompt unconditionally before resume logic existed.

This means the "Automated task execution" example from the README stops working after the first workspace restart. At minimum, log a warning when task_prompt is set but resume takes precedence. The codex module handles this correctly with a separate continue variable that gates the resume decision independently from the task prompt.

🤖

bash -c "$(printf '%q ' gemini "${GEMINI_ARGS[@]}")"
else
printf "No existing Gemini chats found. Starting Gemini CLI in interactive mode.\n"
if [ -n "$GEMINI_TASK_PROMPT" ]; then
printf "Running automated task: %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"
PROMPT_FILE="$MODULE_DIR/prompt.txt"
echo -n "$PROMPT" > "$PROMPT_FILE"
GEMINI_ARGS+=(--prompt-interactive "$PROMPT")
else
printf "Starting Gemini CLI in interactive mode.\n"
GEMINI_ARGS+=()
Comment thread
Harsh9485 marked this conversation as resolved.
Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit Duplicate log message. Line 82 already prints "Starting Gemini CLI in interactive mode." This line prints it again. (Gon, Leorio)

Remove this line, or change line 82 to just say "No existing Gemini chats found." and leave the mode announcement to the inner branches.

🤖

fi
agentapi server --type gemini --term-width 67 --term-height 1190 -- \
bash -c "$(printf '%q ' gemini "${GEMINI_ARGS[@]}")"
fi
Loading