Skip to content
Open
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
42 changes: 42 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Expand Down Expand Up @@ -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.

Expand Down
85 changes: 85 additions & 0 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -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: `<promise>YOUR_TEXT</promise>`
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
16 changes: 16 additions & 0 deletions commands/ralph/help.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 <PROMPT> [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 <N>`: Stop after N iterations (default: 5).
- `--completion-promise <TEXT>`: Only stop when the agent outputs `<promise>TEXT</promise>`.

**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.
"""
9 changes: 9 additions & 0 deletions commands/ralph/status.toml
Original file line number Diff line number Diff line change
@@ -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"
```
"""
34 changes: 34 additions & 0 deletions scripts/bump-version.sh
Original file line number Diff line number Diff line change
@@ -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 <new_version>"
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"
12 changes: 12 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
43 changes: 43 additions & 0 deletions scripts/status.sh
Original file line number Diff line number Diff line change
@@ -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
43 changes: 43 additions & 0 deletions scripts/validate.sh
Original file line number Diff line number Diff line change
@@ -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!"
47 changes: 47 additions & 0 deletions tests/status_test.sh
Original file line number Diff line number Diff line change
@@ -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!"