ralph
Interactive planning skill for Amp. Generates specs, implementation plans, and loop infrastructure through clarifying questions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Interactive planning skill for Amp. Generates specs, implementation plans, and loop infrastructure through clarifying questions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | ralph |
| description | Interactive planning skill for Amp. Generates specs, implementation plans, and loop infrastructure through clarifying questions. |
| allowed-tools | ["*"] |
Generate specs, implementation plans, and loop infrastructure for iterative AI-driven development.
Usage: /skill ralph [optional/path/to/plan.md]
.md file as the source specificationYou MUST ask clarifying questions before generating any files. Present questions with lettered options for quick responses.
Interview approach:
Example interview:
I'll help you plan this feature. First, let me ask a few questions:
1. Scope - How broad is this change?
- A) Single file/module
- B) Multiple related files
- C) Cross-cutting (many parts of codebase)
- D) Greenfield (new feature from scratch)
2. Risk tolerance - How aggressive should changes be?
- A) Conservative - minimal changes
- B) Balanced - reasonable refactoring OK
- C) Aggressive - significant refactoring acceptable
3. Validation - How should we verify the implementation?
- A) Existing test suite
- B) Add new tests
- C) Manual testing sufficient
Reply with your choices (e.g., "1B, 2A, 3B") or answer in your own words.
WAIT for user response before proceeding.
After receiving answers, offer to analyze the codebase:
Would you like me to analyze the codebase architecture before generating the plan?
- Reply oracle for architectural analysis
- Reply skip to proceed directly
oracle:skip:Proceed directly to Step 3.
Always overwrite existing files — never add suffixes like -v2, -new, or _backup. These files are ephemeral and meant to be regenerated. Use the exact filenames specified below.
specs/<feature-slug>.mdRequirements specification containing:
IMPLEMENTATION_PLAN.mdFormat:
# Implementation Plan: <Feature Name>
> **Scope**: <scope choice> | **Risk**: <risk choice> | **Constraints**: <constraint choice>
## Summary
<2-3 sentence overview of the implementation approach>
## Tasks
- [ ] Task 1: Description with enough context for implementation
- [ ] Task 2: Description with enough context for implementation
- [ ] Task 3: Description with enough context for implementation
...
Tasks should be:
PROMPT_plan.mdGenerate with this content (replace [DIRECTORIES] with relevant source directories):
# Planning Mode
You are in PLANNING mode. Analyze specifications against existing code and generate a prioritized implementation plan.
## Phase 0: Orient
### 0a. Study specifications
Read all files in `specs/` directory using finder and parallel reads.
### 0b. Study existing implementation
Use finder to analyze relevant source directories:
[DIRECTORIES]
### 0c. Study the current plan
Read `IMPLEMENTATION_PLAN.md` if it exists.
## Phase 1: Gap Analysis
Compare specs against implementation:
- What's already implemented?
- What's missing?
- What's partially done?
**CRITICAL**: Don't assume something isn't implemented. Use finder to search the codebase first.
## Phase 2: Generate Plan
Update `IMPLEMENTATION_PLAN.md` with:
- Tasks sorted by priority (P0 → P1 → P2)
- Clear descriptions with file locations
- Dependencies noted where relevant
- Discoveries from gap analysis
**CRITICAL: ALL tasks MUST use checkbox format:**
- `- [ ] **Task Name**` for pending tasks
- `- [x] **Task Name**` for completed tasks
Do NOT use other formats like `#### P1.1: Task Name` or `**Task Name**` without checkboxes. The build loop relies on `grep -c "^\- \[ \]"` to count remaining tasks.
Capture the WHY, not just the WHAT.
## Phase 3: Exit
After updating the plan, output **RALPH_COMPLETE** and exit.
## Guardrails
999. NEVER implement code in planning mode
1000. Use Task tool for parallel analysis of different areas
1001. Each task must be completable in ONE loop iteration
1002. Use Oracle to review priorities before finalizing
1003. **ALWAYS use checkbox format `- [ ]` or `- [x]` for tasks in IMPLEMENTATION_PLAN.md** - The build loop relies on `grep -c "^\- \[ \]"` to count remaining tasks. Never use `####` headers or bold text without checkboxes.
PROMPT_build.mdGenerate with this content (replace [VALIDATION_COMMAND] with the appropriate command from AGENTS.md or project config):
# Build Mode
Implement ONE task from the plan, validate, commit, exit.
## Phase 0: Orient
Study:
- @AGENTS.md (how to build/test)
- @specs/* (requirements)
- @IMPLEMENTATION_PLAN.md (current state)
### Check for completion
```bash
grep -c "^\- \[ \]" IMPLEMENTATION_PLAN.md || echo 0
[VALIDATION_COMMAND], must pass before continuingIf stuck, use Oracle to debug. Add extra logging if needed.
Update IMPLEMENTATION_PLAN.md:
- [x] CompletedUpdate AGENTS.md (if you learned something new):
git add -A && git commit -m "feat([scope]): [description]
Thread: $AMP_THREAD_URL"
Check remaining:
grep -c "^\- \[ \]" IMPLEMENTATION_PLAN.md || echo 0
### 5. `loop.sh`
Generate with this content (replace `[FEATURE_NAME]` with a short kebab-case feature name like `auth-system` or `api-refactor`):
```bash
#!/bin/bash
# Ralph Wiggum Build Loop (Amp)
# Usage:
# ./loop.sh # Auto mode: plan first, then build (default)
# ./loop.sh plan # Planning mode only
# ./loop.sh build # Build mode only
# ./loop.sh 10 # Auto mode, max 10 build iterations
# ./loop.sh build 5 # Build mode, max 5 iterations
set -e
FEATURE_NAME="[FEATURE_NAME]"
MODE="plan"
AUTO_MODE=true
MAX_ITERATIONS=0
ITERATION=0
CONSECUTIVE_FAILURES=0
PARENT_THREAD_FILE=$(mktemp)
# Colors
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
NC='\033[0m'
for arg in "$@"; do
if [[ "$arg" == "plan" ]]; then
MODE="plan"
AUTO_MODE=false
elif [[ "$arg" == "build" ]]; then
MODE="build"
AUTO_MODE=false
elif [[ "$arg" =~ ^[0-9]+$ ]]; then
MAX_ITERATIONS=$arg
fi
done
PROMPT_FILE="PROMPT_${MODE}.md"
if [[ ! -f "$PROMPT_FILE" ]]; then
echo -e "${RED}Error: $PROMPT_FILE not found${NC}"
echo "Run the ralph-amp skill first to generate the required files."
exit 1
fi
cleanup() {
rm -f "$PARENT_THREAD_FILE"
}
trap cleanup EXIT
switch_to_build_mode() {
echo ""
echo -e "${CYAN}=== Switching to Build Mode ===${NC}"
echo ""
MODE="build"
PROMPT_FILE="PROMPT_${MODE}.md"
ITERATION=0
}
seconds_until_next_hour() {
local now=$(date +%s)
local current_minute=$(date +%M)
local current_second=$(date +%S)
local seconds_past_hour=$((10#$current_minute * 60 + 10#$current_second))
local seconds_until=$((3600 - seconds_past_hour))
echo $seconds_until
}
seconds_until_daily_reset() {
local reset_hour=5
local now=$(date +%s)
local today_reset=$(date -v${reset_hour}H -v0M -v0S +%s 2>/dev/null || date -d "today ${reset_hour}:00:00" +%s)
if [[ $now -ge $today_reset ]]; then
local tomorrow_reset=$((today_reset + 86400))
echo $((tomorrow_reset - now))
else
echo $((today_reset - now))
fi
}
countdown() {
local seconds=$1
local message=$2
while [[ $seconds -gt 0 ]]; do
local hours=$((seconds / 3600))
local minutes=$(((seconds % 3600) / 60))
local secs=$((seconds % 60))
printf "\r${CYAN}%s${NC} Time remaining: %02d:%02d:%02d " "$message" $hours $minutes $secs
sleep 1
((seconds--))
done
printf "\r%-80s\r" " "
}
is_recoverable_error() {
local output="$1"
local exit_code="$2"
# Check JSON error field from stream-json output
if [[ "$output" =~ \"error\":\"rate_limit\" ]]; then
return 0
fi
if [[ "$output" =~ "rate limit" ]] || [[ "$output" =~ "Rate limit" ]]; then
return 0
fi
if [[ "$output" =~ Error:\ 429 ]] || [[ "$output" =~ Error:\ 529 ]]; then
return 0
fi
return 1
}
get_sleep_duration() {
local output="$1"
local json_reset=$(echo "$output" | grep -oE '"resetsAt"\s*:\s*"[^"]+"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
if [[ -n "$json_reset" ]]; then
local reset_epoch=$(date -jf "%Y-%m-%dT%H:%M:%S%z" "$json_reset" +%s 2>/dev/null || \
date -d "$json_reset" +%s 2>/dev/null)
if [[ -n "$reset_epoch" ]]; then
local now=$(date +%s)
local diff=$((reset_epoch - now))
if [[ $diff -gt 0 ]]; then
echo $((diff + 60))
return
fi
fi
fi
if [[ "$output" =~ retry.after[[:space:]]*:?[[:space:]]*([0-9]+) ]]; then
echo "${BASH_REMATCH[1]}"
return
fi
if [[ "$output" =~ "try again in "([0-9]+)" minute" ]]; then
echo $(( ${BASH_REMATCH[1]} * 60 + 60 ))
return
fi
if [[ "$output" =~ "try again in "([0-9]+)" hour" ]]; then
echo $(( ${BASH_REMATCH[1]} * 3600 + 60 ))
return
fi
if [[ "$output" =~ (daily|day|24.?hour) ]]; then
seconds_until_daily_reset
return
fi
if [[ "$output" =~ resets[[:space:]]+([0-9]+)(am|pm) ]]; then
local reset_hour="${BASH_REMATCH[1]}"
local ampm="${BASH_REMATCH[2]}"
local tz="UTC"
if [[ "$output" =~ \(([A-Za-z_/]+)\) ]]; then
tz="${BASH_REMATCH[1]}"
fi
if [[ "$ampm" == "pm" && "$reset_hour" -ne 12 ]]; then
reset_hour=$((reset_hour + 12))
elif [[ "$ampm" == "am" && "$reset_hour" -eq 12 ]]; then
reset_hour=0
fi
local now=$(date +%s)
local target=$(TZ="$tz" date -v${reset_hour}H -v0M -v0S +%s 2>/dev/null || TZ="$tz" date -d "today ${reset_hour}:00:00" +%s)
if [[ $now -ge $target ]]; then
target=$((target + 86400))
fi
echo $((target - now + 60))
return
fi
# Default: wait until next hour
local wait_time=$(seconds_until_next_hour)
[[ $wait_time -lt 300 ]] && wait_time=300
echo $wait_time
}
handle_recoverable_error() {
local output="$1"
local sleep_duration=$(get_sleep_duration "$output")
echo ""
echo -e "${YELLOW}=== Recoverable Error Detected ===${NC}"
echo -e "${YELLOW}Waiting before retry...${NC}"
echo ""
local tz="UTC"
if [[ "$output" =~ \(([A-Za-z_/]+)\) ]]; then
tz="${BASH_REMATCH[1]}"
fi
local resume_time=$(TZ="$tz" date -v+${sleep_duration}S "+%Y-%m-%d %H:%M:%S" 2>/dev/null || TZ="$tz" date -d "+${sleep_duration} seconds" "+%Y-%m-%d %H:%M:%S")
echo -e "Expected resume: ${CYAN}${resume_time}${NC}"
echo ""
countdown $sleep_duration "Waiting..."
echo ""
echo -e "${GREEN}Resuming...${NC}"
echo ""
CONSECUTIVE_FAILURES=0
}
if [[ "$AUTO_MODE" == true ]]; then
echo -e "${GREEN}Ralph loop: AUTO mode (plan → build)${NC}"
[[ $MAX_ITERATIONS -gt 0 ]] && echo "Max build iterations: $MAX_ITERATIONS"
else
echo -e "${GREEN}Ralph loop: $(echo "$MODE" | tr '[:lower:]' '[:upper:]') mode${NC}"
[[ $MAX_ITERATIONS -gt 0 ]] && echo "Max iterations: $MAX_ITERATIONS"
fi
echo "Press Ctrl+C to stop"
echo "---"
while true; do
ITERATION=$((ITERATION + 1))
echo ""
MODE_DISPLAY=$(echo "$MODE" | tr '[:lower:]' '[:upper:]')
if [[ "$AUTO_MODE" == true ]]; then
echo -e "${GREEN}=== ${MODE_DISPLAY} Iteration $ITERATION ===${NC}"
else
echo -e "${GREEN}=== Iteration $ITERATION ===${NC}"
fi
echo ""
TEMP_OUTPUT=$(mktemp)
PARENT_THREAD=$(cat "$PARENT_THREAD_FILE" 2>/dev/null || true)
set +e
if [[ -n "$PARENT_THREAD" ]]; then
echo -e "${CYAN}Creating handoff from parent ${PARENT_THREAD}...${NC}"
cat "$PROMPT_FILE" | amp threads handoff "$PARENT_THREAD" \
--goal "$(cat "$PROMPT_FILE")" \
-x \
--dangerously-allow-all \
--stream-json > "$TEMP_OUTPUT" 2>&1
else
amp -x --dangerously-allow-all --stream-json < "$PROMPT_FILE" > "$TEMP_OUTPUT" 2>&1
fi
THREAD_ID=$(jq -r 'select(.type == "system") | .session_id' "$TEMP_OUTPUT" 2>/dev/null | head -1)
cat "$TEMP_OUTPUT" | jq -r '
def tool_info:
if .name == "edit_file" or .name == "create_file" or .name == "Read" then
(.input.path | split("/") | last | .[0:60])
elif .name == "todo_write" then
((.input.todos // []) | map(.content) | join(", ") | if contains("\n") then .[0:60] else . end)
elif .name == "Bash" then
(.input.cmd | if contains("\n") then split("\n") | first | .[0:50] else .[0:80] end)
elif .name == "Grep" then
(.input.pattern | .[0:40])
elif .name == "glob" then
(.input.filePattern | .[0:40])
elif .name == "finder" then
(.input.query | if contains("\n") then .[0:40] else . end)
elif .name == "oracle" then
(.input.task | if contains("\n") then .[0:40] else .[0:80] end)
elif .name == "Task" then
(.input.description // .input.prompt | if contains("\n") then .[0:40] else .[0:80] end)
else null end;
if .type == "assistant" then
.message.content[] |
if .type == "text" then
if (.text | split("\n") | length) <= 3 then .text else empty end
elif .type == "tool_use" then
" [" + .name + "]" + (tool_info | if . then " " + . else "" end)
else empty end
elif .type == "result" then
"--- " + ((.duration_ms / 1000 * 10 | floor / 10) | tostring) + "s, " + (.num_turns | tostring) + " turns ---"
else empty end
' 2>/dev/null
EXIT_CODE=$?
OUTPUT=$(cat "$TEMP_OUTPUT")
RESULT_MSG=$(jq -r 'select(.type == "result") | .result // empty' "$TEMP_OUTPUT" 2>/dev/null | tail -1)
rm -f "$TEMP_OUTPUT"
set -e
if [[ -n "$THREAD_ID" ]]; then
if [[ -z "$PARENT_THREAD" ]]; then
echo "$THREAD_ID" > "$PARENT_THREAD_FILE"
amp threads rename "$THREAD_ID" "ralph: ${FEATURE_NAME} ${MODE} (parent)" 2>/dev/null || true
echo -e "${CYAN}Parent thread: $THREAD_ID${NC}"
else
amp threads rename "$THREAD_ID" "ralph: ${FEATURE_NAME} ${MODE} #${ITERATION}" 2>/dev/null || true
echo -e "${CYAN}Child thread: $THREAD_ID${NC}"
fi
fi
if is_recoverable_error "$OUTPUT" "$EXIT_CODE"; then
handle_recoverable_error "$OUTPUT"
ITERATION=$((ITERATION - 1))
continue
fi
if [[ $EXIT_CODE -ne 0 ]]; then
CONSECUTIVE_FAILURES=$((CONSECUTIVE_FAILURES + 1))
echo ""
echo -e "${RED}=== Error (exit code: $EXIT_CODE) ===${NC}"
BACKOFF=$((30 * (2 ** (CONSECUTIVE_FAILURES - 1))))
[[ $BACKOFF -gt 300 ]] && BACKOFF=300
echo -e "${YELLOW}Retrying in ${BACKOFF}s... (consecutive failures: $CONSECUTIVE_FAILURES)${NC}"
countdown $BACKOFF "Waiting..."
ITERATION=$((ITERATION - 1))
continue
fi
CONSECUTIVE_FAILURES=0
if [[ "$RESULT_MSG" =~ "RALPH_COMPLETE" ]] || [[ "$OUTPUT" =~ "RALPH_COMPLETE" ]]; then
echo ""
echo -e "${GREEN}=== Ralph Complete ===${NC}"
if [[ "$AUTO_MODE" == true && "$MODE" == "plan" ]]; then
# Reset parent thread for build phase
rm -f "$PARENT_THREAD_FILE"
switch_to_build_mode
continue
fi
echo -e "${GREEN}All tasks finished.${NC}"
break
fi
if [[ $MAX_ITERATIONS -gt 0 && $ITERATION -ge $MAX_ITERATIONS ]]; then
if [[ "$AUTO_MODE" == true && "$MODE" == "plan" ]]; then
rm -f "$PARENT_THREAD_FILE"
switch_to_build_mode
continue
fi
echo ""
echo -e "${GREEN}Reached max iterations ($MAX_ITERATIONS).${NC}"
break
fi
sleep 2
done
echo ""
echo -e "${GREEN}Ralph loop complete. Iterations: $ITERATION${NC}"
Make the script executable:
chmod +x loop.sh
After generating all files, tell the user:
Files generated:
specs/<feature-slug>.md- Requirements specificationIMPLEMENTATION_PLAN.md- Task list with checkboxesPROMPT_plan.md- Planning mode instructionsPROMPT_build.md- Build mode instructionsloop.sh- Dual-mode build loop scriptUsage:
./loop.sh- Auto mode: plan first, then build./loop.sh plan- Planning mode only./loop.sh build- Build mode only./loop.sh build 10- Build mode, max 10 iterationsThread organization:
- Each phase creates its own parent thread
- Child threads named:
ralph: <feature-name> <mode> #N- View thread hierarchy at https://ampcode.com/threads
Next step: Run
./loop.shto start the loop.