Skip to content

Instantly share code, notes, and snippets.

@rjcorwin
Last active February 22, 2026 23:18
Show Gist options
  • Select an option

  • Save rjcorwin/334de4970af7c9a026ad78f6ad1606f5 to your computer and use it in GitHub Desktop.

Select an option

Save rjcorwin/334de4970af7c9a026ad78f6ad1606f5 to your computer and use it in GitHub Desktop.
Prompt less, Automate Research-Plan-Implement (arpi, pronounced like Archie)
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERROR: Script failed at line $LINENO (exit code $?)" >&2' ERR
# arpi: Automates the RPI (Research-Plan-Implement) workflow using Claude Code.
#
# Usage:
# arpi new "Your feature ask here"
# arpi research <slug>
# arpi plan <slug>
# arpi implement <slug>
# arpi yolo "Your feature ask here"
#
# Commands:
# new "ask text" Create a new plan directory with ask.md
# research <slug> Run the research phase (AI:Work + AI:Review + AI:Gate)
# plan <slug> Run the plan phase (AI:Work + AI:Review + AI:Gate)
# implement <slug> Run the implement phase (AI:Work + AI:Review + AI:Gate + pr.md)
# yolo "ask text" Run all phases sequentially (new + research + plan + implement)
#
# Options:
# --permissions Require permissions for Claude calls (default: skip)
# --iterations N Max review iterations (default: 3)
# --model MODEL Claude model to use (default: opus)
# --name NAME Override feature name (for 'new' command)
# --code CODE Override 3-char code (for 'new' command)
# -h, --help Show this help
#
# Examples:
# arpi new "Add ship inventory"
# arpi research a7z-add-ship-inventory
# arpi plan a7z-add-ship-inventory
# arpi implement a7z-add-ship-inventory
# arpi new --skip-permissions --iterations 3 "Add ship inventory"
# arpi yolo --skip-permissions "Add ship inventory"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# Defaults
SKIP_PERMISSIONS="--dangerously-skip-permissions"
ITERATIONS=3
MODEL="opus"
FEATURE_NAME=""
PLAN_CODE=""
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
log_phase() { echo -e "\n${BOLD}${BLUE}══════════════════════════════════════${NC}"; echo -e "${BOLD}${BLUE} $1${NC}"; echo -e "${BOLD}${BLUE}══════════════════════════════════════${NC}\n"; }
log_step() { echo -e "${CYAN}▸ $1${NC}"; }
log_ok() { echo -e "${GREEN}✓ $1${NC}"; }
log_warn() { echo -e "${YELLOW}⚠ $1${NC}"; }
log_err() { echo -e "${RED}✗ $1${NC}"; }
usage() {
sed -n '/^# arpi:/,/^$/s/^# \?//p' "$0"
exit 0
}
# Parse args — extract command first, then options
COMMAND=""
POSITIONAL=""
args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--permissions) SKIP_PERMISSIONS=""; shift ;;
--skip-permissions) shift ;; # already default, kept for backwards compat
--iterations) ITERATIONS="$2"; shift 2 ;;
--model) MODEL="$2"; shift 2 ;;
--name) FEATURE_NAME="$2"; shift 2 ;;
--code) PLAN_CODE="$2"; shift 2 ;;
-h|--help) usage ;;
-*) log_err "Unknown option: $1"; usage ;;
*) args+=("$1"); shift ;;
esac
done
if [[ ${#args[@]} -lt 1 ]]; then
usage
fi
COMMAND="${args[0]}"
POSITIONAL="${args[1]:-}"
# Help after subcommand: arpi research --help
if [[ "$POSITIONAL" == "--help" || "$POSITIONAL" == "-h" ]]; then
usage
fi
# Validate command
case "$COMMAND" in
help) usage ;;
new|research|plan|implement|yolo) ;;
*) log_err "Unknown command: $COMMAND"; usage ;;
esac
run_claude() {
local prompt="$1"
local output
log_step "Running Claude..."
if output=$(cd "$PROJECT_ROOT" && claude --model "$MODEL" $SKIP_PERMISSIONS --print "$prompt" 2>&1); then
echo "$output"
return 0
else
log_err "Claude exited with error"
echo "$output"
return 1
fi
}
# Gate check: ask Claude whether to proceed or iterate
# Returns 0 if proceed, 1 if iterate
gate_check() {
local review_file="$1"
local phase_name="$2"
local iteration="$3"
local max_iterations="$4"
log_step "Gate check: should we proceed past ${phase_name} or iterate? (iteration ${iteration}/${max_iterations})"
local verdict
verdict=$(cd "$PROJECT_ROOT" && claude --model "$MODEL" $SKIP_PERMISSIONS --print \
"Read the review file at ${review_file} and the plan directory at ${PLAN_DIR}.
You are a gate-check reviewer. Based on the review, determine if the ${phase_name} phase is ready to proceed to the next phase, or if another iteration is needed.
Respond with EXACTLY one line:
- PROCEED: [brief reason] — if the review approves or issues are minor/trivial
- ITERATE: [brief reason] — if the review identifies significant issues that must be addressed before moving on
Do not write anything else. Just that one line." 2>&1)
echo " Gate verdict: $verdict"
if echo "$verdict" | grep -qi "^PROCEED"; then
return 0
else
return 1
fi
}
# ─────────────────────────────────────────────────
# Command: new
# ─────────────────────────────────────────────────
cmd_new() {
local ask_text="$1"
if [[ -z "$ask_text" ]]; then
log_err "No ask text provided. Usage: arpi new \"Your feature ask here\""
exit 1
fi
# Generate plan code if needed
if [[ -z "$PLAN_CODE" ]]; then
PLAN_CODE=$(head -c 100 /dev/urandom | LC_ALL=C tr -dc 'a-hjk-np-z' | head -c1)
PLAN_CODE+=$(head -c 100 /dev/urandom | LC_ALL=C tr -dc '0-9' | head -c1)
PLAN_CODE+=$(head -c 100 /dev/urandom | LC_ALL=C tr -dc 'a-hjk-np-z' | head -c1)
fi
# Generate feature name from ask if needed
if [[ -z "$FEATURE_NAME" ]]; then
FEATURE_NAME=$(echo "$ask_text" | head -1 | tr '[:upper:]' '[:lower:]' | \
sed 's/[^a-z0-9 ]//g' | tr ' ' '-' | cut -c1-40 | sed 's/-$//')
fi
local slug="${PLAN_CODE}-${FEATURE_NAME}"
local plan_dir="$PROJECT_ROOT/plans/$slug"
mkdir -p "$plan_dir"
cat > "$plan_dir/ask.md" <<ASKEOF
# Ask: ${FEATURE_NAME}
## Original Request
${ask_text}
## Date
$(date +%Y-%m-%d)
ASKEOF
log_ok "Created ${plan_dir}/ask.md"
echo -e "\n Slug: ${CYAN}${slug}${NC}"
echo -e " Next: ${CYAN}./scripts/arpi research ${slug}${NC}\n"
# Export for yolo command
NEW_SLUG="$slug"
}
# ─────────────────────────────────────────────────
# Resolve slug to plan directory
# ─────────────────────────────────────────────────
resolve_plan() {
local slug="$1"
if [[ -z "$slug" ]]; then
log_err "No plan slug provided."
exit 1
fi
PLAN_SLUG="$slug"
PLAN_DIR="$PROJECT_ROOT/plans/$slug"
if [[ ! -d "$PLAN_DIR" ]]; then
log_err "Plan directory not found: $PLAN_DIR"
exit 1
fi
}
# ─────────────────────────────────────────────────
# Command: research
# ─────────────────────────────────────────────────
cmd_research() {
resolve_plan "$1"
log_phase "Research: ${PLAN_SLUG}"
if [[ ! -f "$PLAN_DIR/ask.md" ]]; then
log_err "No ask.md found in ${PLAN_DIR}. Run 'arpi new' first."
exit 1
fi
local ask_text
ask_text="$(cat "$PLAN_DIR/ask.md")"
# Generate research.md if it doesn't exist
if [[ ! -f "$PLAN_DIR/research.md" ]]; then
log_step "Generating research.md"
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for workflow context.
A new feature has been requested. Here is the ask:
---
${ask_text}
---
The plan directory is: ${PLAN_DIR}
The plan slug is: ${PLAN_SLUG}
Your task for the RESEARCH phase:
1. Read the relevant codebase files to understand the systems this feature touches
2. Read any relevant existing plans in plans/
3. Write a thorough research.md file at ${PLAN_DIR}/research.md following the template in CONTRIBUTING.md
4. Include: requirements, system architecture analysis, constraints, prior art, and open questions
5. The open questions should identify decisions that need to be made in the Plan phase
Write the research.md file now."
if [[ -f "$PLAN_DIR/research.md" ]]; then
log_ok "research.md created"
else
log_err "research.md was not created"
exit 1
fi
else
log_ok "research.md already exists"
fi
# Research review iterations
local iteration=1
while [[ $iteration -le $ITERATIONS ]]; do
log_step "Research review iteration ${iteration}/${ITERATIONS}"
local review_num
review_num=$(printf "%03d" "$iteration")
local review_file="${PLAN_DIR}/research-review-${review_num}.md"
if [[ -f "$review_file" ]]; then
log_ok "research-review-${review_num}.md already exists, checking gate"
else
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for context.
Plan directory: ${PLAN_DIR}
Your task: Write a thorough research review.
1. Read ALL files in ${PLAN_DIR}/ — ask.md, research.md, and any previous research-review-*.md files
2. Read the relevant source code referenced in research.md
3. Write a detailed review at ${review_file}
The review should cover:
- Completeness: Are all relevant systems and components identified?
- Accuracy: Does the architecture analysis match the actual codebase?
- Open questions: Are the right questions being asked? Are any missing?
- Constraints: Are all technical and architectural constraints captured?
- Prior art: Is the analysis of existing implementations thorough?
- A clear verdict: Ready for planning, or Needs more research
If previous reviews exist, verify that their issues were addressed.
Write the review file now."
if [[ ! -f "$review_file" ]]; then
log_err "Research review file was not created"
exit 1
fi
log_ok "research-review-${review_num}.md created"
fi
# Gate check
if gate_check "$review_file" "research" "$iteration" "$ITERATIONS"; then
log_ok "Research approved — ready for human review"
break
else
if [[ $iteration -ge $ITERATIONS ]]; then
log_warn "Max iterations (${ITERATIONS}) reached — stopping for human review"
break
fi
log_warn "Research needs revision — running iteration $((iteration + 1))"
run_claude \
"Plan directory: ${PLAN_DIR}
Read the latest research review at ${review_file}. It identified issues that need to be addressed.
Your task:
1. Read all files in ${PLAN_DIR}/
2. Address every issue raised in the review by updating research.md
3. For each issue addressed, add a 'Resolution' note at the bottom of the review file explaining what was changed
4. Do NOT create a new review — just fix the issues in research.md and annotate the review
Fix all issues now."
log_ok "Research updated based on review feedback"
fi
iteration=$((iteration + 1))
done
echo ""
echo -e " ${BOLD}Next steps:${NC}"
echo -e " 1. Review files in ${CYAN}${PLAN_DIR}/${NC}"
echo -e " 2. When ready: ${CYAN}./scripts/arpi plan ${PLAN_SLUG}${NC}"
}
# ─────────────────────────────────────────────────
# Command: plan
# ─────────────────────────────────────────────────
cmd_plan() {
resolve_plan "$1"
log_phase "Plan: ${PLAN_SLUG}"
if [[ ! -f "$PLAN_DIR/research.md" ]]; then
log_err "No research.md found in ${PLAN_DIR}. Run 'arpi research ${PLAN_SLUG}' first."
exit 1
fi
# Generate plan.md if it doesn't exist
if [[ ! -f "$PLAN_DIR/plan.md" ]]; then
log_step "Generating plan.md"
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for workflow context.
Plan directory: ${PLAN_DIR}
Plan slug: ${PLAN_SLUG}
Read the research.md file at ${PLAN_DIR}/research.md carefully.
Your task for the PLAN phase:
1. For each open question identified in research.md, write a decision-XXX-name.md file in ${PLAN_DIR}/ following the ADR template from CONTRIBUTING.md. Use 3-digit numbers starting from 001.
2. Write a comprehensive plan.md at ${PLAN_DIR}/plan.md following the template in CONTRIBUTING.md
3. The plan should reference the decisions and incorporate them
4. Include a detailed Technical Design and Implementation Approach
5. Set the plan Status to 'Draft'
Write all files now."
if [[ -f "$PLAN_DIR/plan.md" ]]; then
log_ok "plan.md created"
else
log_err "plan.md was not created"
exit 1
fi
else
log_ok "plan.md already exists"
fi
# Plan review iterations
local iteration=1
while [[ $iteration -le $ITERATIONS ]]; do
log_step "Plan review iteration ${iteration}/${ITERATIONS}"
local review_num
review_num=$(printf "%03d" "$iteration")
local review_file="${PLAN_DIR}/plan-review-${review_num}.md"
if [[ -f "$review_file" ]]; then
log_ok "plan-review-${review_num}.md already exists, checking gate"
else
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for context.
Plan directory: ${PLAN_DIR}
Your task: Write a thorough plan review.
1. Read ALL files in ${PLAN_DIR}/ — research.md, plan.md, all decision-*.md files, and any previous plan-review-*.md files
2. Read the relevant source code that the plan references
3. Write a detailed review at ${review_file}
The review should cover:
- Overall assessment
- Strengths of the plan
- Issues found (with severity: Critical / Medium / Low / Trivial)
- Questions for the author
- Recommendations (before implementation, during, after)
- A clear verdict: Approved, Approved with minor changes, or Needs revision
If previous reviews exist, verify that their issues were addressed.
Write the review file now."
if [[ ! -f "$review_file" ]]; then
log_err "Plan review file was not created"
exit 1
fi
log_ok "plan-review-${review_num}.md created"
fi
# Gate check
if gate_check "$review_file" "plan" "$iteration" "$ITERATIONS"; then
log_ok "Plan approved — ready for human review"
run_claude \
"Read ${PLAN_DIR}/plan.md and change the Status field from 'Draft' to 'Approved'. Only change the status line, nothing else. Write the updated file." > /dev/null 2>&1 || true
break
else
if [[ $iteration -ge $ITERATIONS ]]; then
log_warn "Max iterations (${ITERATIONS}) reached — stopping for human review"
break
fi
log_warn "Plan needs revision — running iteration $((iteration + 1))"
run_claude \
"Plan directory: ${PLAN_DIR}
Read the latest plan review at ${review_file}. It identified issues that need to be addressed.
Your task:
1. Read all files in ${PLAN_DIR}/
2. Address every issue raised in the review by updating the relevant files (plan.md, decision-*.md, etc.)
3. For each issue addressed, add a 'Resolution' note at the bottom of the review file explaining what was changed
4. Do NOT create a new review — just fix the issues in the plan files and annotate the review
Fix all issues now."
log_ok "Plan updated based on review feedback"
fi
iteration=$((iteration + 1))
done
echo ""
echo -e " ${BOLD}Next steps:${NC}"
echo -e " 1. Review files in ${CYAN}${PLAN_DIR}/${NC}"
echo -e " 2. When ready: ${CYAN}./scripts/arpi implement ${PLAN_SLUG}${NC}"
}
# ─────────────────────────────────────────────────
# Command: implement
# ─────────────────────────────────────────────────
cmd_implement() {
resolve_plan "$1"
log_phase "Implement: ${PLAN_SLUG}"
if [[ ! -f "$PLAN_DIR/plan.md" ]]; then
log_err "No plan.md found in ${PLAN_DIR}. Run 'arpi plan ${PLAN_SLUG}' first."
exit 1
fi
# Count existing devlogs to know which iteration we're on
local existing_devlogs
existing_devlogs=$(find "$PLAN_DIR" -name 'devlog-*.md' 2>/dev/null | wc -l)
if [[ $existing_devlogs -eq 0 ]]; then
log_step "Initial implementation"
# Create branch
local branch_name="${PLAN_SLUG}"
log_step "Creating branch: ${branch_name}"
(cd "$PROJECT_ROOT" && git checkout -b "$branch_name" 2>/dev/null || git checkout "$branch_name" 2>/dev/null || true)
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for context.
Plan directory: ${PLAN_DIR}
Your task: IMPLEMENT the plan.
1. Read ALL files in ${PLAN_DIR}/ thoroughly — especially plan.md and all decision-*.md files
2. Read the relevant source code files referenced in the plan
3. Implement the feature according to the plan's Technical Design and Implementation Approach
4. After implementation, write a devlog at ${PLAN_DIR}/devlog-001.md following the template in CONTRIBUTING.md
5. The devlog should summarize what was implemented, tricky parts, and any decisions made during implementation
6. Stage and commit your changes with a descriptive commit message
Implement the feature now."
log_ok "Initial implementation complete"
else
log_ok "Implementation already started (${existing_devlogs} devlog(s) found)"
fi
# Code review iterations
local iteration=1
while [[ $iteration -le $ITERATIONS ]]; do
log_step "Code review iteration ${iteration}/${ITERATIONS}"
local review_num
review_num=$(printf "%03d" "$iteration")
local review_file="${PLAN_DIR}/code-review-${review_num}.md"
if [[ -f "$review_file" ]]; then
log_ok "code-review-${review_num}.md already exists, checking gate"
else
run_claude \
"Read CONTRIBUTING.md and CLAUDE.md for context.
Plan directory: ${PLAN_DIR}
Branch: ${PLAN_SLUG}
Your task: Write a thorough code review.
1. Read ALL files in ${PLAN_DIR}/ — plan.md, decisions, devlogs, and any previous code-review-*.md files
2. Run 'git diff main...HEAD' to see all changes made on this branch
3. Read the changed source files carefully
4. Check that the implementation matches the plan
5. Look for: bugs, missing error handling, architectural violations, performance issues, missing tests, spec inconsistencies
6. Write a detailed review at ${review_file}
The review should include:
- Overall assessment
- Issues found (with severity: Critical / Medium / Low / Trivial, and file:line references)
- Positive observations
- Summary table of issues
- Verdict: Merge-ready, Merge-ready after minor fixes, or Needs revision
If previous code reviews exist, verify their issues were addressed.
Write the review file now."
if [[ ! -f "$review_file" ]]; then
log_err "Code review file was not created"
exit 1
fi
log_ok "code-review-${review_num}.md created"
fi
# Gate check
if gate_check "$review_file" "implementation" "$iteration" "$ITERATIONS"; then
log_ok "Code approved — generating pr.md"
break
else
if [[ $iteration -ge $ITERATIONS ]]; then
log_warn "Max iterations (${ITERATIONS}) reached — generating pr.md anyway"
break
fi
log_warn "Code needs revision — running iteration $((iteration + 1))"
local next_devlog_num
next_devlog_num=$(printf "%03d" $((existing_devlogs + iteration + 1)))
run_claude \
"Plan directory: ${PLAN_DIR}
Read the latest code review at ${review_file}. It identified issues that need to be addressed.
Your task:
1. Read the code review and all files in ${PLAN_DIR}/
2. Fix every issue raised in the review (especially Critical and Medium severity)
3. Write a devlog at ${PLAN_DIR}/devlog-${next_devlog_num}.md summarizing what was fixed
4. Stage and commit the fixes with a descriptive commit message
Fix all issues now."
log_ok "Code updated based on review feedback"
fi
iteration=$((iteration + 1))
done
# Generate pr.md
log_step "Generating pr.md"
if [[ ! -f "$PLAN_DIR/pr.md" ]]; then
run_claude \
"Read CONTRIBUTING.md for the pr.md template.
Plan directory: ${PLAN_DIR}
Branch: ${PLAN_SLUG}
Your task: Write the PR description.
1. Read ALL files in ${PLAN_DIR}/ — plan.md, decisions, devlogs, code reviews
2. Run 'git diff main...HEAD' and 'git log main..HEAD --oneline' to see all changes
3. Write ${PLAN_DIR}/pr.md following the template in CONTRIBUTING.md
4. Include: summary paragraph, decisions made, code walkthrough (recommended reading order), and testing instructions
5. Stage and commit pr.md
Write pr.md now."
log_ok "pr.md created"
else
log_ok "pr.md already exists"
fi
echo ""
echo -e " ${BOLD}Done!${NC}"
echo -e " Plan directory: ${CYAN}${PLAN_DIR}${NC}"
echo -e " Branch: ${CYAN}${PLAN_SLUG}${NC}"
echo ""
echo -e " ${BOLD}Next steps:${NC}"
echo -e " 1. Review files in ${CYAN}${PLAN_DIR}/${NC}"
echo -e " 2. Create PR: ${CYAN}gh pr create --title '${PLAN_SLUG}' --body-file ${PLAN_DIR}/pr.md${NC}"
}
# ─────────────────────────────────────────────────
# Command: yolo
# ─────────────────────────────────────────────────
cmd_yolo() {
local ask_text="$1"
if [[ -z "$ask_text" ]]; then
log_err "No ask text provided. Usage: arpi yolo \"Your feature ask here\""
exit 1
fi
cmd_new "$ask_text"
cmd_research "$NEW_SLUG"
cmd_plan "$NEW_SLUG"
cmd_implement "$NEW_SLUG"
}
# ─────────────────────────────────────────────────
# Dispatch
# ─────────────────────────────────────────────────
echo -e "${BOLD}arpi${NC} — ${COMMAND}"
echo -e " Model: ${MODEL}"
echo -e " Iterations: ${ITERATIONS}"
if [[ -n "$SKIP_PERMISSIONS" ]]; then
echo -e " Permissions: ${YELLOW}skipped${NC}"
else
echo -e " Permissions: enabled"
fi
echo ""
case "$COMMAND" in
new) cmd_new "$POSITIONAL" ;;
research) cmd_research "$POSITIONAL" ;;
plan) cmd_plan "$POSITIONAL" ;;
implement) cmd_implement "$POSITIONAL" ;;
yolo) cmd_yolo "$POSITIONAL" ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment