Rewrite plan-refine for clipboard-based workflow

Oracle browser automation has macOS Keychain issues that prevent
cookie-based auth. Replaced with a two-command clipboard workflow:

  plan-refine <file>              # copies ChatGPT prompt to clipboard
  plan-refine <file> --integrate  # Claude CLI integrates feedback

Step 1 uses Oracle --render --copy (no browser needed) to bundle
the evaluation prompt with plan content. Step 2 uses claude -p
for headless integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-02-07 16:04:35 -05:00
parent c0409579ac
commit d776a266a8

View File

@@ -1,6 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# plan-refine — Run one full ChatGPT + Claude integration iteration on a plan # plan-refine — One-command plan iteration: ChatGPT review + Claude integration
# Usage: plan-refine <plan-file> [options] # Usage: plan-refine <plan-file> [options]
#
# Step 1: Assembles evaluation prompt + plan content, copies to clipboard.
# User pastes into ChatGPT, copies response, saves to feedback file.
# Step 2: Claude CLI integrates feedback back into the plan file.
set -euo pipefail set -euo pipefail
@@ -17,32 +21,29 @@ PROMPTS_DIR="$SCRIPT_DIR/prompts"
source "$SCRIPT_DIR/lib/frontmatter.sh" source "$SCRIPT_DIR/lib/frontmatter.sh"
# Defaults # Defaults
MODEL_STRATEGY="current"
ORACLE_MODEL=""
CLAUDE_MODEL="" CLAUDE_MODEL=""
DRY_RUN=false DRY_RUN=false
NO_INTEGRATE=false NO_INTEGRATE=false
BROWSER_TIMEOUT="1200s"
PLAN_FILE="" PLAN_FILE=""
INIT_ONLY=false INIT_ONLY=false
STEP=""
usage() { usage() {
cat <<'EOF' cat <<'EOF'
plan-refine — One-command plan iteration: ChatGPT review + Claude integration plan-refine — Semi-automated plan iteration: ChatGPT review + Claude integration
Usage: plan-refine <plan-file> [options] Usage: plan-refine <plan-file> [options]
Runs both steps automatically: Workflow per iteration:
1. Oracle sends plan to ChatGPT for adversarial review 1. plan-refine <file> Copies ChatGPT prompt to clipboard
2. Claude CLI integrates feedback back into the plan file 2. Paste into ChatGPT, copy response, save to <file>.feedback-N.md
3. plan-refine <file> --integrate Claude integrates feedback into plan
Options: Options:
--dry-run Preview what would run without executing --integrate Run Claude integration (Step 2)
--no-integrate Only run ChatGPT step, skip Claude integration --no-integrate Skip Claude integration, just update frontmatter
--model <model> Force Oracle/ChatGPT model (e.g. gpt-5.2-pro) --claude-model <m> Claude model for integration (default: your default)
--model-strategy <s> Browser model strategy: current|select|ignore (default: current) --dry-run Preview what would happen
--claude-model <m> Claude model for integration (default: uses your default)
--timeout <duration> Browser timeout (default: 1200s)
--init Add plan frontmatter to file without running anything --init Add plan frontmatter to file without running anything
-h, --help Show this help -h, --help Show this help
EOF EOF
@@ -51,12 +52,10 @@ EOF
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--dry-run) DRY_RUN=true; shift ;; --integrate) STEP="integrate"; shift ;;
--no-integrate) NO_INTEGRATE=true; shift ;; --no-integrate) NO_INTEGRATE=true; shift ;;
--model) ORACLE_MODEL="$2"; shift 2 ;; --dry-run) DRY_RUN=true; shift ;;
--model-strategy) MODEL_STRATEGY="$2"; shift 2 ;;
--claude-model) CLAUDE_MODEL="$2"; shift 2 ;; --claude-model) CLAUDE_MODEL="$2"; shift 2 ;;
--timeout) BROWSER_TIMEOUT="$2"; shift 2 ;;
--init) INIT_ONLY=true; shift ;; --init) INIT_ONLY=true; shift ;;
-h|--help) usage ;; -h|--help) usage ;;
-*) echo "Unknown option: $1" >&2; exit 2 ;; -*) echo "Unknown option: $1" >&2; exit 2 ;;
@@ -100,6 +99,14 @@ ITERATION=$(get_frontmatter "$PLAN_FILE" "iteration" "0")
TARGET=$(get_frontmatter "$PLAN_FILE" "target_iterations" "8") TARGET=$(get_frontmatter "$PLAN_FILE" "target_iterations" "8")
STATUS=$(get_frontmatter "$PLAN_FILE" "status" "drafting") STATUS=$(get_frontmatter "$PLAN_FILE" "status" "drafting")
NEXT_ITERATION=$((ITERATION + 1)) NEXT_ITERATION=$((ITERATION + 1))
PLAN_DIR=$(dirname "$PLAN_FILE")
# Build paths
FEEDBACK_FILE="${PLAN_FILE%.md}.feedback-${NEXT_ITERATION}.md"
# Read prompts
EVAL_PROMPT=$(cat "$PROMPTS_DIR/chatgpt-eval.md")
INTEGRATE_PROMPT=$(cat "$PROMPTS_DIR/claude-integrate.md")
# Status check # Status check
if [[ "$STATUS" == "ready" || "$STATUS" == "implementing" || "$STATUS" == "completed" ]]; then if [[ "$STATUS" == "ready" || "$STATUS" == "implementing" || "$STATUS" == "completed" ]]; then
@@ -109,129 +116,56 @@ if [[ "$STATUS" == "ready" || "$STATUS" == "implementing" || "$STATUS" == "compl
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && exit 0 [[ "$confirm" != "y" && "$confirm" != "Y" ]] && exit 0
fi fi
# Build paths # ──────────────────────────────────────────────
FEEDBACK_FILE="${PLAN_FILE%.md}.feedback-${NEXT_ITERATION}.md" # Route to the right step
PLAN_DIR=$(dirname "$PLAN_FILE") # ──────────────────────────────────────────────
# Read prompts if [[ "$STEP" == "integrate" ]]; then
EVAL_PROMPT=$(cat "$PROMPTS_DIR/chatgpt-eval.md") # ──────────────────────────────────────────
INTEGRATE_PROMPT=$(cat "$PROMPTS_DIR/claude-integrate.md") # Step 2: Claude integration
# ──────────────────────────────────────────
# Build Oracle model args # Find the latest feedback file
ORACLE_MODEL_ARGS=() if [[ -f "$FEEDBACK_FILE" ]]; then
if [[ -n "$ORACLE_MODEL" ]]; then FOUND_FEEDBACK="$FEEDBACK_FILE"
ORACLE_MODEL_ARGS+=(--model "$ORACLE_MODEL") else
fi # Search for any feedback file for the current iteration
FOUND_FEEDBACK=$(ls -t "${PLAN_FILE%.md}".feedback-*.md 2>/dev/null | head -1)
fi
# Build Claude model args if [[ -z "$FOUND_FEEDBACK" || ! -f "$FOUND_FEEDBACK" ]]; then
CLAUDE_MODEL_ARGS=() echo "Error: No feedback file found." >&2
if [[ -n "$CLAUDE_MODEL" ]]; then echo "Expected: $FEEDBACK_FILE" >&2
CLAUDE_MODEL_ARGS+=(--model "$CLAUDE_MODEL") echo "" >&2
fi echo "Run step 1 first: plan-refine $PLAN_FILE" >&2
echo "Then save ChatGPT's response to: $FEEDBACK_FILE" >&2
exit 1
fi
echo "=== plan-refine ===" echo "=== plan-refine --integrate ==="
echo " Plan: $(basename "$PLAN_FILE")" echo " Plan: $(basename "$PLAN_FILE")"
echo " Status: $STATUS" echo " Feedback: $(basename "$FOUND_FEEDBACK")"
echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)" echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)"
echo " Feedback: $(basename "$FEEDBACK_FILE")" echo ""
if [[ "$NO_INTEGRATE" == "true" ]]; then
echo " Mode: ChatGPT review only (--no-integrate)"
else
echo " Mode: Full cycle (ChatGPT review + Claude integration)"
fi
echo ""
if [[ "$DRY_RUN" == "true" ]]; then if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ===" echo "=== DRY RUN ==="
echo "" echo "Would run:"
echo "Step 1: Oracle -> ChatGPT"
echo " oracle --engine browser \\"
echo " --browser-manual-login \\"
echo " --browser-model-strategy $MODEL_STRATEGY \\"
echo " --browser-timeout $BROWSER_TIMEOUT \\"
[[ -n "$ORACLE_MODEL" ]] && echo " --model $ORACLE_MODEL \\"
echo " -p \"$(echo "$EVAL_PROMPT" | head -c 80)...\" \\"
echo " --file \"$PLAN_FILE\" \\"
echo " --write-output \"$FEEDBACK_FILE\""
echo ""
if [[ "$NO_INTEGRATE" != "true" ]]; then
echo "Step 2: Claude CLI -> Integration"
echo " claude -p <integration-prompt> \\" echo " claude -p <integration-prompt> \\"
echo " --allowedTools \"Read,Edit,Write\" \\" echo " --allowedTools \"Read,Edit,Write\" \\"
echo " --permission-mode acceptEdits \\" echo " --permission-mode acceptEdits \\"
echo " --add-dir \"$PLAN_DIR\"" echo " --add-dir \"$PLAN_DIR\""
[[ -n "$CLAUDE_MODEL" ]] && echo " --model $CLAUDE_MODEL" [[ -n "$CLAUDE_MODEL" ]] && echo " --model $CLAUDE_MODEL"
fi
echo ""
echo "=== ChatGPT PROMPT ==="
echo "$EVAL_PROMPT"
echo ""
echo "=== Claude INTEGRATION PROMPT ==="
echo "$INTEGRATE_PROMPT"
exit 0 exit 0
fi
# ──────────────────────────────────────────────
# Step 1: ChatGPT evaluation via Oracle
# ──────────────────────────────────────────────
echo "[Step 1/2] Sending to ChatGPT via Oracle..."
echo "(Oracle will automate the browser. This may take a few minutes.)"
echo ""
oracle --engine browser \
--browser-manual-login \
--browser-model-strategy "$MODEL_STRATEGY" \
--browser-timeout "$BROWSER_TIMEOUT" \
"${ORACLE_MODEL_ARGS[@]}" \
-p "$EVAL_PROMPT" \
--file "$PLAN_FILE" \
--write-output "$FEEDBACK_FILE"
ORACLE_EXIT=$?
if [[ $ORACLE_EXIT -ne 0 ]]; then
echo "Error: Oracle exited with code $ORACLE_EXIT" >&2
exit $ORACLE_EXIT
fi
if [[ ! -f "$FEEDBACK_FILE" ]]; then
echo "Error: Expected feedback file not found: $FEEDBACK_FILE" >&2
exit 1
fi
echo ""
echo "ChatGPT feedback saved to: $FEEDBACK_FILE"
# ──────────────────────────────────────────────
# Step 2: Claude integration
# ──────────────────────────────────────────────
if [[ "$NO_INTEGRATE" == "true" ]]; then
# Clipboard fallback for manual integration
if command -v pbcopy &>/dev/null; then
CLIPBOARD_CONTENT="Read the plan at: $PLAN_FILE
Read ChatGPT's feedback at: $FEEDBACK_FILE
${INTEGRATE_PROMPT}
Write the updated plan back to: $PLAN_FILE"
echo "$CLIPBOARD_CONTENT" | pbcopy
echo ""
echo "Integration prompt copied to clipboard. Paste into Claude Code."
else
echo ""
echo "Skipped integration. Run manually:"
echo " Plan: $PLAN_FILE"
echo " Feedback: $FEEDBACK_FILE"
fi fi
else
echo "" if [[ "$NO_INTEGRATE" == "true" ]]; then
echo "[Step 2/2] Claude integrating feedback into plan..." echo "Skipping Claude integration (--no-integrate)."
else
echo "Claude integrating feedback into plan..."
CLAUDE_PROMPT="Read the original plan at: ${PLAN_FILE} CLAUDE_PROMPT="Read the original plan at: ${PLAN_FILE}
Read ChatGPT's feedback at: ${FEEDBACK_FILE} Read ChatGPT's feedback at: ${FOUND_FEEDBACK}
${INTEGRATE_PROMPT} ${INTEGRATE_PROMPT}
@@ -241,6 +175,11 @@ Important instructions:
- Only modify the content below the frontmatter. - Only modify the content below the frontmatter.
- Do NOT output the plan to stdout. Write it directly to the file." - Do NOT output the plan to stdout. Write it directly to the file."
CLAUDE_MODEL_ARGS=()
if [[ -n "$CLAUDE_MODEL" ]]; then
CLAUDE_MODEL_ARGS+=(--model "$CLAUDE_MODEL")
fi
claude -p "$CLAUDE_PROMPT" \ claude -p "$CLAUDE_PROMPT" \
--allowedTools "Read,Edit,Write" \ --allowedTools "Read,Edit,Write" \
--permission-mode acceptEdits \ --permission-mode acceptEdits \
@@ -251,29 +190,80 @@ Important instructions:
if [[ $CLAUDE_EXIT -ne 0 ]]; then if [[ $CLAUDE_EXIT -ne 0 ]]; then
echo "Error: Claude CLI exited with code $CLAUDE_EXIT" >&2 echo "Error: Claude CLI exited with code $CLAUDE_EXIT" >&2
echo "Feedback is still available at: $FEEDBACK_FILE" echo "Feedback is still available at: $FOUND_FEEDBACK" >&2
echo "You can integrate manually in Claude Code." echo "You can integrate manually in Claude Code." >&2
exit $CLAUDE_EXIT exit $CLAUDE_EXIT
fi fi
echo "Integration complete. Plan updated." echo "Integration complete. Plan updated."
fi fi
# ────────────────────────────────────────────── # Update frontmatter
# Update frontmatter set_frontmatter "$PLAN_FILE" "iteration" "$NEXT_ITERATION"
# ────────────────────────────────────────────── set_frontmatter "$PLAN_FILE" "updated" "$(date +%Y-%m-%d)"
if [[ "$STATUS" == "drafting" ]]; then
set_frontmatter "$PLAN_FILE" "iteration" "$NEXT_ITERATION"
set_frontmatter "$PLAN_FILE" "updated" "$(date +%Y-%m-%d)"
if [[ "$STATUS" == "drafting" ]]; then
set_frontmatter "$PLAN_FILE" "status" "iterating" set_frontmatter "$PLAN_FILE" "status" "iterating"
fi fi
echo "" echo ""
echo "=== Iteration $NEXT_ITERATION/$TARGET complete ===" echo "=== Iteration $NEXT_ITERATION/$TARGET complete ==="
if [[ $NEXT_ITERATION -ge $TARGET ]]; then if [[ $NEXT_ITERATION -ge $TARGET ]]; then
echo "" echo ""
echo "Target iterations reached. Plan may be ready for bead splitting." echo "Target iterations reached. Plan may be ready for bead splitting."
echo "To advance status: set 'status: splitting' in the frontmatter." echo "To advance status: set 'status: splitting' in the frontmatter."
fi
else
# ──────────────────────────────────────────
# Step 1: Prepare ChatGPT prompt
# ──────────────────────────────────────────
echo "=== plan-refine ==="
echo " Plan: $(basename "$PLAN_FILE")"
echo " Status: $STATUS"
echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)"
echo ""
# Use Oracle's --render --copy to bundle prompt + file content
if command -v oracle &>/dev/null; then
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo "Would run: oracle --render --copy -p <eval-prompt> --file $PLAN_FILE"
echo ""
echo "=== PROMPT ==="
echo "$EVAL_PROMPT"
exit 0
fi
oracle --render --copy \
-p "$EVAL_PROMPT" \
--file "$PLAN_FILE" 2>/dev/null
echo "ChatGPT prompt copied to clipboard (assembled by Oracle)."
else
# Fallback: manual clipboard assembly
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo "Would copy evaluation prompt + plan content to clipboard."
exit 0
fi
PLAN_CONTENT=$(cat "$PLAN_FILE")
CLIPBOARD="${EVAL_PROMPT}
---
${PLAN_CONTENT}"
echo "$CLIPBOARD" | pbcopy
echo "ChatGPT prompt copied to clipboard."
fi
echo ""
echo "Next steps:"
echo " 1. Paste into ChatGPT (Cmd+V)"
echo " 2. Wait for response"
echo " 3. Copy ChatGPT's full response"
echo " 4. Save it to: $FEEDBACK_FILE"
echo " 5. Run: plan-refine $(basename "$PLAN_FILE") --integrate"
fi fi