diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..988e705
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,42 @@
+name: Test Ralph Extension
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y jq
+
+ - name: Make scripts executable
+ run: |
+ chmod +x scripts/*.sh
+ chmod +x hooks/*.sh
+ chmod +x tests/*.sh
+
+ - name: Run setup tests
+ run: bash tests/setup_test.sh
+
+ - name: Run hook tests
+ run: bash tests/hook_test.sh
+
+ - name: Run status tests
+ run: bash tests/status_test.sh
+
+ - name: Validate scripts
+ run: |
+ bash -n scripts/setup.sh
+ bash -n scripts/cancel.sh
+ bash -n scripts/status.sh
+ bash -n scripts/validate.sh
+ bash -n hooks/stop-hook.sh
diff --git a/README.md b/README.md
index 0a3dc53..4820fcc 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,14 @@ Install the extension directly from GitHub:
gemini extensions install https://github.com/gemini-cli-extensions/ralph --auto-update
```
+### Verify Installation
+
+After installing, validate your setup:
+
+```bash
+bash ~/.gemini/extensions/ralph/scripts/validate.sh
+```
+
## Configuration
To use Ralph, you must enable hooks and preview features in your `~/.gemini/settings.json`:
@@ -60,6 +68,7 @@ Start a loop by using the `/ralph:loop` command followed by your task.
### Manual Controls
+- `/ralph:status`: Check the current status of an active loop.
- `/ralph:cancel`: Stops an active loop and cleans up all state files.
- `/ralph:help`: Displays detailed usage information and configuration tips.
diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md
new file mode 100644
index 0000000..4fcf1c4
--- /dev/null
+++ b/TROUBLESHOOTING.md
@@ -0,0 +1,85 @@
+# Troubleshooting Ralph
+
+## Common Issues
+
+### Loop Won't Start
+
+**Symptom**: Running `/ralph:loop` doesn't start the loop.
+
+**Solutions**:
+1. Verify hooks are enabled in `~/.gemini/settings.json`:
+ ```json
+ {
+ "hooksConfig": {
+ "enabled": true
+ }
+ }
+ ```
+
+2. Check that the extension directory is included:
+ ```json
+ {
+ "context": {
+ "includeDirectories": ["~/.gemini/extensions/ralph"]
+ }
+ }
+ ```
+
+3. Ensure `jq` is installed: `brew install jq`
+
+### Loop Won't Stop
+
+**Symptom**: Loop continues even after completion promise is output.
+
+**Solutions**:
+1. Verify the promise format is exact: `YOUR_TEXT`
+2. Check the state file: `cat .gemini/ralph/state.json`
+3. Manually cancel: `/ralph:cancel`
+
+### Ghost Loop
+
+**Symptom**: Old loop interferes with new tasks.
+
+**Solution**: The hook should auto-detect this, but you can manually clean up:
+```bash
+rm -rf .gemini/ralph
+```
+
+### Permission Errors
+
+**Symptom**: Scripts fail with permission denied.
+
+**Solution**: Make scripts executable:
+```bash
+chmod +x ~/.gemini/extensions/ralph/scripts/*.sh
+chmod +x ~/.gemini/extensions/ralph/hooks/*.sh
+```
+
+## Debugging
+
+### Check Loop Status
+```bash
+/ralph:status
+```
+
+### View State File
+```bash
+cat .gemini/ralph/state.json | jq
+```
+
+### Enable Debug Logging
+Add to your prompt:
+```
+Before each action, output the current iteration number and your plan.
+```
+
+## Getting Help
+
+If you encounter issues not covered here:
+1. Check the [README](README.md) for configuration details
+2. Review test files in `tests/` for expected behavior
+3. Open an issue on GitHub with:
+ - Your `~/.gemini/settings.json` (redact sensitive info)
+ - The command you ran
+ - Contents of `.gemini/ralph/state.json` (if exists)
+ - Error messages
diff --git a/commands/ralph/help.toml b/commands/ralph/help.toml
index b311eb9..7b346ce 100644
--- a/commands/ralph/help.toml
+++ b/commands/ralph/help.toml
@@ -4,10 +4,26 @@ Display the Ralph help documentation. Do NOT use any other subagent for this. Es
Summarize the available commands for the user:
- `/ralph:loop [OPTIONS]`: Start a Ralph loop.
+- `/ralph:status`: Check the current status of an active loop.
- `/ralph:cancel`: Cancel an active Ralph loop and clean up all temporary files.
- `/ralph:help`: Show this message.
**Options:**
- `--max-iterations `: Stop after N iterations (default: 5).
- `--completion-promise `: Only stop when the agent outputs `TEXT`.
+
+**Examples:**
+```bash
+# Basic loop with iteration limit
+/ralph:loop "Build a REST API" --max-iterations 10
+
+# Loop with completion promise
+/ralph:loop "Fix all linting errors" --completion-promise "ALL_CLEAN"
+
+# Combined options
+/ralph:loop "Implement feature X" --max-iterations 15 --completion-promise "FEATURE_COMPLETE"
+```
+
+**Troubleshooting:**
+For common issues and solutions, see TROUBLESHOOTING.md in the extension directory.
"""
diff --git a/commands/ralph/status.toml b/commands/ralph/status.toml
new file mode 100644
index 0000000..b92feb1
--- /dev/null
+++ b/commands/ralph/status.toml
@@ -0,0 +1,9 @@
+description = "Check the status of the current Ralph loop."
+prompt = """
+You are checking the Ralph loop status.
+
+Run the status script to display the current loop state:
+```bash
+bash "${extensionPath}/scripts/status.sh"
+```
+"""
diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh
new file mode 100755
index 0000000..03e09c4
--- /dev/null
+++ b/scripts/bump-version.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Bump version in gemini-extension.json
+
+if [[ $# -ne 1 ]]; then
+ echo "Usage: $0 "
+ echo "Example: $0 1.1.0"
+ exit 1
+fi
+
+NEW_VERSION="$1"
+
+if [[ ! "$NEW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+ echo "Error: Version must be in format X.Y.Z"
+ exit 1
+fi
+
+jq --arg version "$NEW_VERSION" '.version = $version' gemini-extension.json > gemini-extension.json.tmp
+mv gemini-extension.json.tmp gemini-extension.json
+
+echo "✅ Version bumped to $NEW_VERSION"
diff --git a/scripts/setup.sh b/scripts/setup.sh
index 15a6276..be61f60 100755
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -41,11 +41,23 @@ fi
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
+ --max-iterations=*)
+ VALUE="${1#*=}"
+ [[ "$VALUE" =~ ^[0-9]+$ ]] || die "Invalid iteration limit: '$VALUE'"
+ MAX_ITERATIONS="$VALUE"
+ shift
+ ;;
--max-iterations)
[[ "${2:-}" =~ ^[0-9]+$ ]] || die "Invalid iteration limit: '${2:-}'"
MAX_ITERATIONS="$2"
shift 2
;;
+ --completion-promise=*)
+ VALUE="${1#*=}"
+ [[ -n "$VALUE" ]] || die "Missing promise text."
+ COMPLETION_PROMISE="$VALUE"
+ shift
+ ;;
--completion-promise)
[[ -n "${2:-}" ]] || die "Missing promise text."
COMPLETION_PROMISE="$2"
diff --git a/scripts/status.sh b/scripts/status.sh
new file mode 100755
index 0000000..213fa22
--- /dev/null
+++ b/scripts/status.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+STATE_FILE=".gemini/ralph/state.json"
+
+if [[ ! -f "$STATE_FILE" ]]; then
+ echo "Ralph: I'm not doing anything right now!" >&2
+ exit 0
+fi
+
+echo "🔄 Ralph Loop Status" >&2
+echo "===================" >&2
+echo "" >&2
+
+ACTIVE=$(jq -r '.active' "$STATE_FILE")
+CURRENT=$(jq -r '.current_iteration' "$STATE_FILE")
+MAX=$(jq -r '.max_iterations' "$STATE_FILE")
+PROMISE=$(jq -r '.completion_promise' "$STATE_FILE")
+PROMPT=$(jq -r '.original_prompt' "$STATE_FILE")
+STARTED=$(jq -r '.started_at' "$STATE_FILE")
+
+echo "Status: $([ "$ACTIVE" = "true" ] && echo "🟢 Active" || echo "🔴 Inactive")" >&2
+echo "Iteration: $CURRENT / $MAX" >&2
+echo "Started: $STARTED" >&2
+echo "Task: $PROMPT" >&2
+
+if [[ -n "$PROMISE" ]]; then
+ echo "Completion Promise: $PROMISE" >&2
+fi
+
+echo "" >&2
diff --git a/scripts/validate.sh b/scripts/validate.sh
new file mode 100755
index 0000000..370e062
--- /dev/null
+++ b/scripts/validate.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Validate Ralph prerequisites
+
+echo "🔍 Validating Ralph prerequisites..."
+
+# Check for jq
+if ! command -v jq &> /dev/null; then
+ echo "❌ Error: jq is not installed. Install it with: brew install jq"
+ exit 1
+fi
+
+# Check for bash version (need 4.0+)
+if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
+ echo "⚠️ Warning: Bash version ${BASH_VERSION} detected. Bash 4.0+ recommended."
+fi
+
+# Check hooks configuration
+SETTINGS_FILE="$HOME/.gemini/settings.json"
+if [[ -f "$SETTINGS_FILE" ]]; then
+ HOOKS_ENABLED=$(jq -r '.hooksConfig.enabled // false' "$SETTINGS_FILE")
+ if [[ "$HOOKS_ENABLED" != "true" ]]; then
+ echo "⚠️ Warning: Hooks are not enabled in ~/.gemini/settings.json"
+ echo " Add: \"hooksConfig\": { \"enabled\": true }"
+ fi
+else
+ echo "⚠️ Warning: ~/.gemini/settings.json not found"
+fi
+
+echo "✅ Validation complete!"
diff --git a/tests/status_test.sh b/tests/status_test.sh
new file mode 100755
index 0000000..4d68f2d
--- /dev/null
+++ b/tests/status_test.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2026 Google LLC
+# Licensed under the Apache License, Version 2.0
+
+STATE_FILE=".gemini/ralph/state.json"
+STATE_DIR=".gemini/ralph"
+STATUS_SCRIPT="./scripts/status.sh"
+
+setup() {
+ mkdir -p "$STATE_DIR"
+}
+
+cleanup() {
+ rm -f "$STATE_FILE"
+ if [[ -d "$STATE_DIR" ]]; then
+ rmdir "$STATE_DIR" 2>/dev/null || true
+ fi
+}
+
+trap cleanup EXIT
+
+echo "Running Test 1: No active loop..."
+setup
+OUTPUT=$("$STATUS_SCRIPT" 2>&1)
+if [[ "$OUTPUT" != *"not doing anything"* ]]; then
+ echo "FAIL: Expected 'not doing anything' message"
+ exit 1
+fi
+
+echo "Running Test 2: Active loop status..."
+setup
+jq -n '{
+ active: true,
+ current_iteration: 3,
+ max_iterations: 10,
+ completion_promise: "DONE",
+ original_prompt: "Test task",
+ started_at: "2026-01-27T12:00:00Z"
+}' > "$STATE_FILE"
+
+OUTPUT=$("$STATUS_SCRIPT" 2>&1)
+if [[ "$OUTPUT" != *"Active"* ]] || [[ "$OUTPUT" != *"3 / 10"* ]]; then
+ echo "FAIL: Expected active status with iteration count"
+ exit 1
+fi
+
+echo "PASS: All tests passed!"