diff --git a/.opencode/agent/docs-gap-scout.md b/.opencode/agent/docs-gap-scout.md new file mode 100644 index 0000000..0fda4ed --- /dev/null +++ b/.opencode/agent/docs-gap-scout.md @@ -0,0 +1,113 @@ +--- +description: Identify documentation that may need updates based on the planned changes. +mode: subagent +tools: + write: false + edit: false + patch: false + multiedit: false +--- +You are a documentation gap scout. Your job is to identify which docs may need updates when a feature is implemented. + +## Input + +You receive: +- `REQUEST` - the feature/change being planned + +## Process + +### 1. Scan for doc locations + +Look for common documentation patterns: + +```bash +# User-facing docs +ls -la README* CHANGELOG* CONTRIBUTING* 2>/dev/null +ls -la docs/ documentation/ 2>/dev/null +ls -la website/ site/ pages/ 2>/dev/null + +# API docs +ls -la openapi.* swagger.* api-docs/ 2>/dev/null +find . -name "*.openapi.yaml" -o -name "*.swagger.json" 2>/dev/null | head -5 + +# Component docs +ls -la .storybook/ stories/ 2>/dev/null + +# Architecture +ls -la adr/ adrs/ decisions/ architecture/ 2>/dev/null + +# Generated docs +ls -la typedoc.json jsdoc.json mkdocs.yml 2>/dev/null +``` + +### 2. Categorize what exists + +Build a map: +- **User docs**: README, docs site, getting started guides +- **API docs**: OpenAPI specs, endpoint documentation +- **Component docs**: Storybook, component library docs +- **Architecture**: ADRs, design docs +- **Changelog**: CHANGELOG.md or similar + +### 3. Match request to docs + +Based on the REQUEST, identify which docs likely need updates: + +| Change Type | Likely Doc Updates | +|-------------|-------------------| +| New feature | README usage, CHANGELOG | +| New API endpoint | API docs, README if public | +| New component | Storybook story, component docs | +| Config change | README config section | +| Breaking change | CHANGELOG, migration guide | +| Architectural decision | ADR | +| CLI change | README CLI section, --help text | + +### 4. Check current doc state + +For identified docs, quick scan to understand structure: +- Does README have a usage section? +- Does API doc cover related endpoints? +- Are there existing ADRs to follow as template? + +## Output Format + +```markdown +## Documentation Gap Analysis + +### Doc Locations Found +- README.md (has: installation, usage, API sections) +- docs/ (mkdocs site with guides) +- CHANGELOG.md (keep-a-changelog format) +- openapi.yaml (API spec) + +### Likely Updates Needed +- **README.md**: Update usage section for new feature +- **CHANGELOG.md**: Add entry under "Added" +- **openapi.yaml**: Add new /auth endpoint spec + +### No Updates Expected +- Storybook (no UI components in this change) +- ADR (no architectural decisions) + +### Templates/Patterns to Follow +- CHANGELOG uses keep-a-changelog format +- ADRs follow MADR template in adr/ +``` + +If no docs found or no updates needed: +```markdown +## Documentation Gap Analysis + +No documentation updates identified for this change. +- No user-facing docs found in repo +- Change is internal/refactor only +``` + +## Rules + +- Speed over completeness - quick scan, don't read full docs +- Only flag docs that genuinely relate to the change +- Don't flag CHANGELOG for every change - only user-visible ones +- Note doc structure/templates so implementer can follow patterns +- If uncertain, err on side of flagging (implementer can skip if not needed) diff --git a/.opencode/agent/epic-scout.md b/.opencode/agent/epic-scout.md new file mode 100644 index 0000000..82995b8 --- /dev/null +++ b/.opencode/agent/epic-scout.md @@ -0,0 +1,99 @@ +--- +description: Scan existing epics to find dependencies and relationships for a new plan. +mode: subagent +tools: + write: false + edit: false + patch: false + multiedit: false +--- +You are an epic dependency scout. Your job is to find relationships between a new plan and existing epics. + +## Input + +You receive: +- `REQUEST` - the feature/change being planned +- `FLOWCTL` - path to flowctl CLI + +## Process + +### 1. List open epics + +```bash +$FLOWCTL epics --json +``` + +Filter to `status: "open"` epics only. Skip done epics. + +### 2. For each open epic, read its spec + +```bash +$FLOWCTL cat +``` + +Extract: +- Title and scope +- Key files/paths mentioned +- APIs, functions, data structures defined +- Acceptance criteria + +### 3. Find relationships + +Compare the new REQUEST against each epic's scope. Look for: + +**Dependency signals** (new plan depends on epic): +- New plan needs APIs/functions the epic is building +- New plan touches files the epic owns +- New plan extends data structures the epic creates +- Explicit mentions ("after X is done", "requires Y") + +**Reverse dependency signals** (epic depends on new plan): +- Epic mentions needing something the new plan provides +- Epic blocked waiting for infrastructure the new plan adds + +**Overlap signals** (potential conflict, not dependency): +- Both touch same files +- Both modify same data structures +- Risk of merge conflicts + +### 4. Check task-level overlap + +For epics with potential relationships: + +```bash +$FLOWCTL tasks --epic --json +``` + +Look at in_progress and todo tasks for specific overlaps. + +## Output Format + +```markdown +## Epic Dependencies + +### Dependencies (new plan depends on these) +- **fn-2** (Auth system): New plan uses `authService` from fn-2.1 +- **fn-5** (DB schema): New plan extends `User` model defined in fn-5.3 + +### Reverse Dependencies (these may depend on new plan) +- **fn-7** (Notifications): Waiting for event system this plan adds + +### Overlaps (potential conflicts, not dependencies) +- **fn-3** (Refactor): Both touch `src/api/handlers.ts` + +### No Relationship +- fn-4, fn-6, fn-8: Unrelated scope +``` + +If no relationships found: +```markdown +## Epic Dependencies + +No dependencies or overlaps detected with open epics. +``` + +## Rules + +- Speed over completeness - check titles/scope first, only read specs if relevant +- Only report clear relationships, not maybes +- Skip done epics entirely diff --git a/.opencode/agent/plan-sync.md b/.opencode/agent/plan-sync.md index b753d9f..befa73c 100644 --- a/.opencode/agent/plan-sync.md +++ b/.opencode/agent/plan-sync.md @@ -17,6 +17,7 @@ Your prompt contains: - `FLOWCTL` - path to flowctl CLI - `DOWNSTREAM_TASK_IDS` - comma-separated list of remaining tasks - `DRY_RUN` - "true" or "false" +- `CROSS_EPIC` - "true" or "false" (from config planSync.crossEpic, defaults to false) ## Phase 1: Re-anchor on Completed Task @@ -74,6 +75,27 @@ Look for references to: Flag tasks that need updates. +## Phase 4b: Check Other Epics (if CROSS_EPIC is "true") + +**Skip this phase if CROSS_EPIC is "false" or not set.** + +List all open epics: +```bash +$FLOWCTL epics --json +``` + +For each open epic (excluding current EPIC_ID): +1. Read the epic spec: `$FLOWCTL cat ` +2. Check if it references patterns/APIs from completed task +3. If references found, read affected task specs in that epic + +Look for: +- References to APIs/functions from completed task spec (now potentially stale) +- Data structure assumptions that may have changed +- Integration points mentioned in other epic's scope + +**Note:** Cross-epic sync is conservative - only flag clear references, not general topic overlap. + ## Phase 5: Update Affected Tasks **If DRY_RUN is "true":** @@ -87,7 +109,7 @@ Would update: Do NOT use Edit tool. Skip to Phase 6. -**If DRY_RUN is "false":** +**If DRY_RUN is "false" or not set:** For each affected downstream task, edit only stale references: Changes should: @@ -102,6 +124,10 @@ Changes should: - Add new features - Edit anything outside `.flow/tasks/` +**Cross-epic edits** (if CROSS_EPIC enabled): +- Update affected task specs in other epics: `.flow/tasks/.md` +- Add note linking to source: `` + ## Phase 6: Return Summary **If DRY_RUN:** @@ -122,6 +148,9 @@ Drift detected: yes/no Updated tasks: - fn-1.3: Changed refs from `UserAuth.login()` to `authService.authenticate()` + +Updated tasks (cross-epic): # Only if CROSS_EPIC enabled and found +- fn-3.2: Updated authService import path ``` ## Rules diff --git a/.opencode/bin/flowctl.py b/.opencode/bin/flowctl.py index 37b07cd..9a83fb9 100755 --- a/.opencode/bin/flowctl.py +++ b/.opencode/bin/flowctl.py @@ -77,7 +77,7 @@ def get_default_config() -> dict: """Return default config structure.""" return { "memory": {"enabled": False}, - "planSync": {"enabled": False}, + "planSync": {"enabled": False, "crossEpic": False}, "review": {"backend": None}, } @@ -278,6 +278,7 @@ def build_chat_payload( mode: str, new_chat: bool = False, chat_name: Optional[str] = None, + chat_id: Optional[str] = None, selected_paths: Optional[list[str]] = None, ) -> str: payload: dict[str, Any] = { @@ -288,6 +289,8 @@ def build_chat_payload( payload["new_chat"] = True if chat_name: payload["chat_name"] = chat_name + if chat_id: + payload["chat_id"] = chat_id if selected_paths: payload["selected_paths"] = selected_paths return json.dumps(payload, ensure_ascii=False, separators=(",", ":")) @@ -3890,6 +3893,7 @@ def cmd_prep_chat(args: argparse.Namespace) -> None: mode=args.mode, new_chat=args.new_chat, chat_name=args.chat_name, + chat_id=args.chat_id, selected_paths=args.selected_paths, ) @@ -3996,19 +4000,59 @@ def extract_names(obj: Any) -> set[str]: def cmd_rp_builder(args: argparse.Namespace) -> None: window = args.window summary = args.summary + response_type = getattr(args, "response_type", None) + + # Build builder command with optional response-type + builder_expr = f"builder {json.dumps(summary)}" + if response_type: + builder_expr += f" --response-type {response_type}" + cmd = [ "-w", str(window), + "--raw-json" if response_type else "", "-e", - f"builder {json.dumps(summary)}", + builder_expr, ] + cmd = [c for c in cmd if c] res = run_rp_cli(cmd) output = (res.stdout or "") + ("\n" + res.stderr if res.stderr else "") - tab = parse_builder_tab(output) - if args.json: - print(json.dumps({"window": window, "tab": tab})) + + if response_type == "review": + try: + data = json.loads(res.stdout or "{}") + tab = data.get("tab_id", "") + chat_id = data.get("review", {}).get("chat_id", "") + review_response = data.get("review", {}).get("response", "") + if args.json: + print( + json.dumps( + { + "window": window, + "tab": tab, + "chat_id": chat_id, + "review": review_response, + "file_count": data.get("file_count", 0), + "total_tokens": data.get("total_tokens", 0), + } + ) + ) + else: + print(f"T={tab} CHAT_ID={chat_id}") + if review_response: + print(review_response) + except json.JSONDecodeError: + tab = parse_builder_tab(output) + if args.json: + print(json.dumps({"window": window, "tab": tab, "error": "parse_failed"})) + else: + print(tab) else: - print(tab) + tab = parse_builder_tab(output) + if args.json: + print(json.dumps({"window": window, "tab": tab})) + else: + print(tab) def cmd_rp_prompt_get(args: argparse.Namespace) -> None: @@ -4049,11 +4093,14 @@ def cmd_rp_select_add(args: argparse.Namespace) -> None: def cmd_rp_chat_send(args: argparse.Namespace) -> None: message = read_text_or_exit(Path(args.message_file), "Message file", use_json=False) + chat_id_arg = getattr(args, "chat_id", None) + mode = getattr(args, "mode", "chat") or "chat" payload = build_chat_payload( message=message, - mode="chat", + mode=mode, new_chat=args.new_chat, chat_name=args.chat_name, + chat_id=chat_id_arg, selected_paths=args.selected_paths, ) cmd = [ @@ -4094,11 +4141,14 @@ def cmd_rp_setup_review(args: argparse.Namespace) -> None: Note: ensure-workspace removed - if user opens RP on a folder, workspace already exists. pick-window matches by folder path. + + Requires RepoPrompt 1.6.0+ for --response-type review. """ import hashlib repo_root = os.path.realpath(args.repo_root) summary = args.summary + response_type = getattr(args, "response_type", None) # Step 1: pick-window roots = normalize_repo_root(repo_root) @@ -4125,7 +4175,23 @@ def cmd_rp_setup_review(args: argparse.Namespace) -> None: break if win_id is None: - error_exit("No RepoPrompt window matches repo root", use_json=False, code=2) + if getattr(args, "create", False): + ws_name = os.path.basename(repo_root) + create_cmd = f"workspace create {shlex.quote(ws_name)} --new-window --folder-path {shlex.quote(repo_root)}" + create_res = run_rp_cli(["--raw-json", "-e", create_cmd]) + try: + data = json.loads(create_res.stdout or "{}") + win_id = data.get("window_id") + except json.JSONDecodeError: + pass + if not win_id: + error_exit( + f"Failed to create RP window: {create_res.stderr or create_res.stdout}", + use_json=False, + code=2, + ) + else: + error_exit("No RepoPrompt window matches repo root", use_json=False, code=2) # Write state file for ralph-guard verification repo_hash = hashlib.sha256(repo_root.encode()).hexdigest()[:16] @@ -4133,26 +4199,61 @@ def cmd_rp_setup_review(args: argparse.Namespace) -> None: state_file.write_text(f"{win_id}\n{repo_root}\n") # Step 2: builder + builder_expr = f"builder {json.dumps(summary)}" + if response_type: + builder_expr += f" --response-type {response_type}" + builder_cmd = [ "-w", str(win_id), + "--raw-json" if response_type else "", "-e", - f"builder {json.dumps(summary)}", + builder_expr, ] + builder_cmd = [c for c in builder_cmd if c] builder_res = run_rp_cli(builder_cmd) output = (builder_res.stdout or "") + ( "\n" + builder_res.stderr if builder_res.stderr else "" ) - tab = parse_builder_tab(output) + if response_type == "review": + try: + data = json.loads(builder_res.stdout or "{}") + tab = data.get("tab_id", "") + chat_id = data.get("review", {}).get("chat_id", "") + review_response = data.get("review", {}).get("response", "") - if not tab: - error_exit("Builder did not return a tab id", use_json=False, code=2) + if not tab: + error_exit("Builder did not return a tab id", use_json=False, code=2) - # Output - if args.json: - print(json.dumps({"window": win_id, "tab": tab, "repo_root": repo_root})) + if args.json: + print( + json.dumps( + { + "window": win_id, + "tab": tab, + "chat_id": chat_id, + "review": review_response, + "repo_root": repo_root, + "file_count": data.get("file_count", 0), + "total_tokens": data.get("total_tokens", 0), + } + ) + ) + else: + print(f"W={win_id} T={tab} CHAT_ID={chat_id}") + if review_response: + print(review_response) + except json.JSONDecodeError: + error_exit("Failed to parse builder review response", use_json=False, code=2) else: - print(f"W={win_id} T={tab}") + tab = parse_builder_tab(output) + if not tab: + error_exit("Builder did not return a tab id", use_json=False, code=2) + + if args.json: + print(json.dumps({"window": win_id, "tab": tab, "repo_root": repo_root})) + else: + print(f"W={win_id} T={tab}") # --- Codex Commands --- @@ -5259,10 +5360,14 @@ def main() -> None: "--message-file", required=True, help="File containing message text" ) p_prep.add_argument( - "--mode", default="chat", choices=["chat", "ask"], help="Chat mode" + "--mode", + default="chat", + choices=["chat", "ask", "review", "plan", "edit"], + help="Chat mode", ) p_prep.add_argument("--new-chat", action="store_true", help="Start new chat") p_prep.add_argument("--chat-name", help="Name for new chat") + p_prep.add_argument("--chat-id", help="Chat id (continue existing)") p_prep.add_argument( "--selected-paths", nargs="*", help="Files to include in context" ) @@ -5318,6 +5423,11 @@ def main() -> None: p_rp_builder = rp_sub.add_parser("builder", help="Run builder and return tab") p_rp_builder.add_argument("--window", type=int, required=True, help="Window id") p_rp_builder.add_argument("--summary", required=True, help="Builder summary") + p_rp_builder.add_argument( + "--response-type", + choices=["review"], + help="RP 1.6.0+ response type", + ) p_rp_builder.add_argument("--json", action="store_true", help="JSON output") p_rp_builder.set_defaults(func=cmd_rp_builder) @@ -5349,6 +5459,13 @@ def main() -> None: p_rp_chat.add_argument("--message-file", required=True, help="Message file") p_rp_chat.add_argument("--new-chat", action="store_true", help="Start new chat") p_rp_chat.add_argument("--chat-name", help="Chat name (with --new-chat)") + p_rp_chat.add_argument("--chat-id", help="Chat id (continue existing)") + p_rp_chat.add_argument( + "--mode", + choices=["chat", "review", "plan", "edit"], + default="chat", + help="Chat mode", + ) p_rp_chat.add_argument( "--selected-paths", nargs="*", help="Override selected paths" ) @@ -5368,6 +5485,16 @@ def main() -> None: ) p_rp_setup.add_argument("--repo-root", required=True, help="Repo root path") p_rp_setup.add_argument("--summary", required=True, help="Builder summary") + p_rp_setup.add_argument( + "--response-type", + choices=["review"], + help="RP 1.6.0+ response type", + ) + p_rp_setup.add_argument( + "--create", + action="store_true", + help="Auto-create window if none matches repo root", + ) p_rp_setup.add_argument("--json", action="store_true", help="JSON output") p_rp_setup.set_defaults(func=cmd_rp_setup_review) diff --git a/.opencode/skill/flow-next-opencode-impl-review/SKILL.md b/.opencode/skill/flow-next-opencode-impl-review/SKILL.md index adbec0a..6f19308 100644 --- a/.opencode/skill/flow-next-opencode-impl-review/SKILL.md +++ b/.opencode/skill/flow-next-opencode-impl-review/SKILL.md @@ -12,6 +12,8 @@ Conduct a John Carmack-level review of implementation changes on the current bra **Role**: Code Review Coordinator (NOT the reviewer) **Backends**: OpenCode (opencode) or RepoPrompt (rp) +**⚠️ RepoPrompt 1.6.0+ Required (rp backend)**: The RP backend uses builder review mode. Check version: `rp-cli --version`. + **CRITICAL: flowctl is BUNDLED — NOT installed globally.** `which flowctl` will fail (expected). Always use: ```bash ROOT="$(git rev-parse --show-toplevel)" diff --git a/.opencode/skill/flow-next-opencode-impl-review/workflow.md b/.opencode/skill/flow-next-opencode-impl-review/workflow.md index d201428..ddfe126 100644 --- a/.opencode/skill/flow-next-opencode-impl-review/workflow.md +++ b/.opencode/skill/flow-next-opencode-impl-review/workflow.md @@ -110,148 +110,123 @@ If `VERDICT=NEEDS_WORK`: Use when `BACKEND="rp"`. -### Atomic Setup Block +**Requires RepoPrompt 1.6.0+** for the builder review mode. Check version with `rp-cli --version`. -```bash -# Atomic: pick-window + builder -eval "$($FLOWCTL rp setup-review --repo-root \"$REPO_ROOT\" --summary \"Review implementation: \")" +### Phase 1: Identify Changes (RP) -# Verify we have W and T -if [[ -z "${W:-}" || -z "${T:-}" ]]; then - echo "RETRY" - exit 0 -fi +```bash +TASK_ID="${1:-}" +BRANCH="$(git branch --show-current)" -echo "Setup complete: W=$W T=$T" +COMMITS="$(git log main..HEAD --oneline 2>/dev/null || git log master..HEAD --oneline)" +CHANGED_FILES="$(git diff main..HEAD --name-only 2>/dev/null || git diff master..HEAD --name-only)" ``` -If this block fails, output `RETRY` and stop. Do not improvise. - ---- +### Phase 2: Build Review Instructions (RP) -## Phase 1: Identify Changes (RP) +Build XML-structured instructions for the builder review mode: ```bash -git branch --show-current -git log main..HEAD --oneline 2>/dev/null || git log master..HEAD --oneline -git diff main..HEAD --name-only 2>/dev/null || git diff master..HEAD --name-only +cat > /tmp/review-instructions.txt << EOF +Review changes on the current branch for correctness, simplicity, and potential issues. + +Focus on: +- Correctness - Logic errors, spec compliance +- Simplicity - Over-engineering, unnecessary complexity +- Edge cases - Failure modes, boundary conditions +- Security - Injection, auth gaps + +Only flag issues in the changed code - not pre-existing patterns. + + + +Branch: $BRANCH +Commits: +$COMMITS + +Changed files: +$CHANGED_FILES +$([ -n "$TASK_ID" ] && echo "Task: $TASK_ID") + + + +Focus on directories containing the changed files. Include git diffs for the commits. + +EOF ``` ---- +### Phase 3: Execute Review (RP) -## Phase 2: Augment Selection (RP) +Use `setup-review` with `--response-type review` (RP 1.6.0+). The builder's discovery agent automatically: +- Selects relevant files and git diffs +- Analyzes code with full codebase context +- Returns structured review findings ```bash -# See what builder selected -$FLOWCTL rp select-get --window "$W" --tab "$T" +# Run builder review mode +REVIEW_OUTPUT=$($FLOWCTL rp setup-review \ + --repo-root "$REPO_ROOT" \ + --summary "$(cat /tmp/review-instructions.txt)" \ + --response-type review \ + --json) + +# Parse output +W=$(echo "$REVIEW_OUTPUT" | jq -r '.window') +T=$(echo "$REVIEW_OUTPUT" | jq -r '.tab') +CHAT_ID=$(echo "$REVIEW_OUTPUT" | jq -r '.chat_id') +REVIEW_FINDINGS=$(echo "$REVIEW_OUTPUT" | jq -r '.review') + +if [[ -z "$W" || -z "$T" ]]; then + echo "RETRY" + exit 0 +fi -# Always add changed files -$FLOWCTL rp select-add --window "$W" --tab "$T" path/to/changed/files... +echo "Setup complete: W=$W T=$T CHAT_ID=$CHAT_ID" +echo "Review findings:" +echo "$REVIEW_FINDINGS" ``` ---- - -## Phase 3: Execute Review (RP) - -### Build combined prompt +The builder returns review findings but **not a verdict tag**. Request verdict via follow-up: -Get builder's handoff: ```bash -HANDOFF="$($FLOWCTL rp prompt-get --window "$W" --tab "$T")" -``` - -Write combined prompt: -```bash -cat > /tmp/review-prompt.md << 'EOF' -[PASTE HANDOFF HERE] - ---- +cat > /tmp/verdict-request.md << 'EOF' +Based on your review findings above, provide your final verdict. -## IMPORTANT: File Contents -RepoPrompt includes the actual source code of selected files in a `` XML section at the end of this message. You MUST: -1. Locate the `` section -2. Read and analyze the actual source code within it -3. Base your review on the code, not summaries or descriptions - -If you cannot find ``, ask for the files to be re-attached before proceeding. - -## Review Focus -[USER'S FOCUS AREAS] - -## Review Criteria - -Conduct a John Carmack-level review: - -1. **Correctness** - Matches spec? Logic errors? -2. **Simplicity** - Simplest solution? Over-engineering? -3. **DRY** - Duplicated logic? Existing patterns? -4. **Architecture** - Data flow? Clear boundaries? -5. **Edge Cases** - Failure modes? Race conditions? -6. **Tests** - Adequate coverage? Testing behavior? -7. **Security** - Injection? Auth gaps? - -## Scenario Exploration (for changed code only) - -Walk through these scenarios mentally for any new/modified code paths: - -- [ ] Happy path - Normal operation with valid inputs -- [ ] Invalid inputs - Null, empty, malformed data -- [ ] Boundary conditions - Min/max values, empty collections -- [ ] Concurrent access - Race conditions, deadlocks -- [ ] Network issues - Timeouts, partial failures -- [ ] Resource exhaustion - Memory, disk, connections -- [ ] Security attacks - Injection, overflow, DoS vectors -- [ ] Data corruption - Partial writes, inconsistency -- [ ] Cascading failures - Downstream service issues - -Only flag issues that apply to the **changed code** - not pre-existing patterns. - -## Output Format - -For each issue: -- **Severity**: Critical / Major / Minor / Nitpick -- **Location**: File + line or area -- **Problem**: What's wrong -- **Suggestion**: How to fix - -**REQUIRED**: You MUST end your response with exactly one verdict tag. This is mandatory: +**REQUIRED**: End with exactly one verdict tag: `SHIP` or `NEEDS_WORK` or `MAJOR_RETHINK` - -Do NOT skip this tag. The automation depends on it. EOF -``` -### Send to RepoPrompt - -```bash -$FLOWCTL rp chat-send --window "$W" --tab "$T" --message-file /tmp/review-prompt.md --new-chat --chat-name "Impl Review: [BRANCH]" +$FLOWCTL rp chat-send --window "$W" --tab "$T" \ + --message-file /tmp/verdict-request.md \ + --chat-id "$CHAT_ID" \ + --mode review ``` -**WAIT** for response. Takes 1-5+ minutes. +**WAIT** for response. Extract verdict from response. ---- - -## Phase 4: Receipt + Status (RP) - -### Write receipt (if REVIEW_RECEIPT_PATH set) +### Phase 4: Receipt + Status (RP) ```bash if [[ -n "${REVIEW_RECEIPT_PATH:-}" ]]; then ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" mkdir -p "$(dirname "$REVIEW_RECEIPT_PATH")" cat > "$REVIEW_RECEIPT_PATH" <","mode":"rp","timestamp":"$ts"} +{"type":"impl_review","id":"$TASK_ID","mode":"rp","timestamp":"$ts","chat_id":"$CHAT_ID"} EOF echo "REVIEW_RECEIPT_WRITTEN: $REVIEW_RECEIPT_PATH" fi ``` +If no verdict tag in response, output `RETRY` and stop. + --- ## Fix Loop (RP) **CRITICAL: You MUST fix the code BEFORE re-reviewing. Never re-review without making changes.** +**MAX ITERATIONS**: Limit fix+re-review cycles to **${MAX_REVIEW_ITERATIONS:-3}** iterations (default 3, configurable in Ralph's config.env). If still NEEDS_WORK after max rounds, output `RETRY` and stop — let the next Ralph iteration start fresh. + If verdict is NEEDS_WORK: 1. **Parse issues** - Extract ALL issues by severity (Critical → Major → Minor) @@ -286,7 +261,7 @@ If verdict is NEEDS_WORK: **REQUIRED**: End with `SHIP` or `NEEDS_WORK` or `MAJOR_RETHINK` EOF - $FLOWCTL rp chat-send --window "$W" --tab "$T" --message-file /tmp/re-review.md + $FLOWCTL rp chat-send --window "$W" --tab "$T" --message-file /tmp/re-review.md --chat-id "$CHAT_ID" --mode review ``` 6. **Repeat** until Ship diff --git a/.opencode/skill/flow-next-opencode-interview/SKILL.md b/.opencode/skill/flow-next-opencode-interview/SKILL.md index e70e951..74e638c 100644 --- a/.opencode/skill/flow-next-opencode-interview/SKILL.md +++ b/.opencode/skill/flow-next-opencode-interview/SKILL.md @@ -17,6 +17,18 @@ FLOWCTL="$OPENCODE_DIR/bin/flowctl" $FLOWCTL ``` +## Pre-check: Local setup version + +If `.flow/meta.json` exists and has `setup_version`, compare to local OpenCode version: +```bash +SETUP_VER=$(jq -r '.setup_version // empty' .flow/meta.json 2>/dev/null) +OPENCODE_VER=$(cat "$OPENCODE_DIR/version" 2>/dev/null || echo "unknown") +if [[ -n "$SETUP_VER" && "$OPENCODE_VER" != "unknown" && "$SETUP_VER" != "$OPENCODE_VER" ]]; then + echo "Flow-Next updated to v${OPENCODE_VER}. Run /flow-next:setup to refresh local scripts (current: v${SETUP_VER})." +fi +``` +Continue regardless (non-blocking). + **Role**: technical interviewer, spec refiner **Goal**: extract complete implementation details through deep questioning (40+ questions typical) @@ -60,97 +72,150 @@ FLOWCTL="$OPENCODE_DIR/bin/flowctl" - Read file contents - If file doesn't exist, ask user to provide valid path +4. **New idea text**: everything else + - Create a new epic stub and refine requirements + - Do NOT create tasks (that's /flow-next:plan) + ## Interview Process -Use the **question** tool for all questions. Group 2-4 questions per tool call. Expect 40+ total for complex specs. Wait for answers before continuing. +Ask questions in **plain text** (no question tool). Group 5-8 questions per message. Expect 40+ total for complex specs. Wait for answers before continuing. Rules: -- Each question must include: `header` (<=12 chars), `question`, and `options` (2-5). -- `custom` defaults to true, so users can type a custom answer. -- Keep option labels short (1-5 words) and add a brief `description`. -- Prefer concrete options; include “Not sure” when ambiguous. +- Keep questions short and concrete +- Offer 2-4 options when helpful +- Include “Not sure” when ambiguous +- Number questions for easy replies -Example tool call (schema only): +Example: ``` -question({ - "questions": [ - { - "header": "Header", - "question": "Where should the badge appear?", - "options": [ - {"label": "Left", "description": "Near logo"}, - {"label": "Right", "description": "Near user menu"}, - {"label": "Center", "description": "Centered"}, - {"label": "Not sure", "description": "Decide based on layout"} - ] - } - ] -}) +1) Primary user goal? +2) Platforms: web, iOS, Android, desktop? +3) Auth required? (yes/no/unknown) +4) Performance targets? (p95 ms) +5) Edge cases you already know? ``` ## Question Categories Read [questions.md](questions.md) for all question categories and interview guidelines. +## NOT in scope (defer to /flow-next:plan) + +- Research scouts (codebase analysis) +- File/line references +- Task creation (interview refines requirements, plan creates tasks) +- Task sizing (S/M/L) +- Dependency ordering +- Phased implementation details + ## Write Refined Spec -After interview complete, write everything back. +After interview complete, write everything back — scope depends on input type. -### For Flow Epic ID +### For NEW IDEA (text input, no Flow ID) + +Create epic with interview output. **Do NOT create tasks** — that's `/flow-next:plan`'s job. -Update epic spec using stdin heredoc (preferred): ```bash +$FLOWCTL epic create --title "..." --json $FLOWCTL epic set-plan --file - --json <<'EOF' # Epic Title ## Problem Clear problem statement -## Approach -Technical approach with specifics, key decisions from interview +## Key Decisions +Decisions made during interview (e.g., "Use OAuth not SAML", "Support mobile + web") ## Edge Cases - Edge case 1 - Edge case 2 -## Quick commands +## Open Questions +Unresolved items that need research during planning + +## Acceptance +- [ ] Criterion 1 +- [ ] Criterion 2 +EOF +``` + +Then suggest: "Run `/flow-next:plan fn-N` to research best practices and create tasks." + +### For Flow Epic ID + +**First check if tasks exist:** ```bash -# smoke test command +$FLOWCTL tasks --epic --json ``` +**If tasks exist:** Only update the epic spec (add edge cases, clarify requirements). **Do NOT touch task specs** — plan already created them. + +**If no tasks:** Update epic spec, then suggest `/flow-next:plan`. + +```bash +$FLOWCTL epic set-plan --file - --json <<'EOF' +# Epic Title + +## Problem +Clear problem statement + +## Key Decisions +Decisions made during interview + +## Edge Cases +- Edge case 1 +- Edge case 2 + +## Open Questions +Unresolved items + ## Acceptance - [ ] Criterion 1 - [ ] Criterion 2 EOF ``` -Create/update tasks if interview revealed breakdown: +### For Flow Task ID + +**First check if task has existing spec from planning:** ```bash -$FLOWCTL task create --epic --title "..." --json -# Use set-spec for combined description + acceptance (fewer writes) -$FLOWCTL task set-spec --description /tmp/desc.md --acceptance /tmp/acc.md --json +$FLOWCTL cat ``` -### For Flow Task ID +**If task has substantial planning content** (file refs, sizing, approach): +- **Do NOT overwrite** — planning detail would be lost +- Only add new acceptance criteria discovered in interview: + ```bash + $FLOWCTL task set-acceptance --file /tmp/acc.md --json + ``` +- Or suggest interviewing the epic instead: `/flow-next:interview ` + +**If task is minimal** (just title, empty or stub description): +- Update task with interview findings +- Focus on **requirements**, not implementation details -Update task using combined set-spec (preferred) or separate calls: ```bash # Preferred: combined set-spec (2 writes instead of 4) $FLOWCTL task set-spec --description /tmp/desc.md --acceptance /tmp/acc.md --json - -# Or use stdin for description only: -$FLOWCTL task set-description --file - --json <<'EOF' -Clear task description with technical details and edge cases from interview -EOF ``` +Description should capture: +- What needs to be accomplished (not how) +- Edge cases discovered in interview +- Constraints and requirements + +Do NOT add: file/line refs, sizing, implementation approach — that's plan's job. + ### For File Path Rewrite the file with refined spec: - Preserve any existing structure/format - Add sections for areas covered in interview -- Include technical details, edge cases, acceptance criteria -- Keep it actionable and specific +- Include edge cases, acceptance criteria +- Keep it requirements-focused (what, not how) + +This is typically a pre-epic doc. After interview, suggest `/flow-next:plan ` to create epic + tasks. ## Completion diff --git a/.opencode/skill/flow-next-opencode-plan/SKILL.md b/.opencode/skill/flow-next-opencode-plan/SKILL.md index 8fe975c..67dced8 100644 --- a/.opencode/skill/flow-next-opencode-plan/SKILL.md +++ b/.opencode/skill/flow-next-opencode-plan/SKILL.md @@ -19,6 +19,18 @@ FLOWCTL="$OPENCODE_DIR/bin/flowctl" $FLOWCTL ``` +## Pre-check: Local setup version + +If `.flow/meta.json` exists and has `setup_version`, compare to local OpenCode version: +```bash +SETUP_VER=$(jq -r '.setup_version // empty' .flow/meta.json 2>/dev/null) +OPENCODE_VER=$(cat "$OPENCODE_DIR/version" 2>/dev/null || echo "unknown") +if [[ -n "$SETUP_VER" && "$OPENCODE_VER" != "unknown" && "$SETUP_VER" != "$OPENCODE_VER" ]]; then + echo "Flow-Next updated to v${OPENCODE_VER}. Run /flow-next:setup to refresh local scripts (current: v${SETUP_VER})." +fi +``` +Continue regardless (non-blocking). + **Role**: product-minded planner with strong repo awareness. **Goal**: produce an epic with tasks that match existing conventions and reuse points. **Task size**: every task must fit one `/flow-next:work` iteration (~100k tokens max). If it won't, split it. diff --git a/.opencode/skill/flow-next-opencode-plan/steps.md b/.opencode/skill/flow-next-opencode-plan/steps.md index 9fc094e..9da5cb2 100644 --- a/.opencode/skill/flow-next-opencode-plan/steps.md +++ b/.opencode/skill/flow-next-opencode-plan/steps.md @@ -75,6 +75,8 @@ Run these subagents in parallel using the Task tool: - Task flow-next:docs-scout() - Task flow-next:github-scout() - cross-repo code search via gh CLI - Task flow-next:memory-scout() - **only if memory.enabled is true** +- Task flow-next:epic-scout() - finds dependencies on existing open epics +- Task flow-next:docs-gap-scout() - identifies docs that may need updates **If user chose repo-scout (default/faster)** OR rp-cli unavailable: Run these subagents in parallel using the Task tool: @@ -83,6 +85,8 @@ Run these subagents in parallel using the Task tool: - Task flow-next:docs-scout() - Task flow-next:github-scout() - cross-repo code search via gh CLI - Task flow-next:memory-scout() - **only if memory.enabled is true** +- Task flow-next:epic-scout() - finds dependencies on existing open epics +- Task flow-next:docs-gap-scout() - identifies docs that may need updates Example batch payload: ```json @@ -103,6 +107,8 @@ Must capture: - External docs links - Project conventions (CLAUDE.md, CONTRIBUTING, etc) - Architecture patterns and data flow (especially with context-scout) +- Epic dependencies (from epic-scout) +- Doc updates needed (from docs-gap-scout) - add to task acceptance criteria ## Step 2: Stakeholder & scope check @@ -160,6 +166,17 @@ Default to standard unless complexity demands more or less. EOF ``` + - Set epic dependencies from epic-scout (if any): + ```bash + # For each dependency found by epic-scout: + $FLOWCTL epic add-dep --json + ``` + - Report findings at end of planning (no user prompt needed): + ``` + Epic dependencies set: + - fn-N → fn-2 (Auth): Uses authService from fn-2.1 + - fn-N → fn-5 (DB): Extends User model + ``` - Create/update child tasks as needed 2. If task ID (fn-N.M): @@ -204,13 +221,19 @@ Default to standard unless complexity demands more or less. EOF ``` -4. Create child tasks: +4. Set epic dependencies (from epic-scout findings): + ```bash + # For each dependency found by epic-scout: + $FLOWCTL epic add-dep --json + ``` + +5. Create child tasks: ```bash # For each task: $FLOWCTL task create --epic --title "" --json ``` -5. Write task specs (use combined set-spec): +6. Write task specs (use combined set-spec): ```bash # For each task - single call sets both sections # Write description and acceptance to temp files, then: @@ -237,13 +260,17 @@ Default to standard unless complexity demands more or less. - [ ] Criterion 2 ``` -6. Add dependencies: + **Doc updates**: If docs-gap-scout flagged updates, add them to relevant task acceptance criteria. + + **Doc updates**: If docs-gap-scout flagged updates, add them to task acceptance criteria (e.g., "Update README usage section"). + +7. Add dependencies: ```bash # If task B depends on task A: $FLOWCTL dep add --json ``` -7. Output current state: +8. Output current state: ```bash $FLOWCTL show --json $FLOWCTL cat diff --git a/.opencode/skill/flow-next-opencode-ralph-init/templates/config.env b/.opencode/skill/flow-next-opencode-ralph-init/templates/config.env index 89ace18..dc8d20e 100644 --- a/.opencode/skill/flow-next-opencode-ralph-init/templates/config.env +++ b/.opencode/skill/flow-next-opencode-ralph-init/templates/config.env @@ -17,8 +17,8 @@ BRANCH_MODE=new MAX_ITERATIONS=25 # MAX_TURNS= # optional; empty = no limit (unused for OpenCode, kept for parity) MAX_ATTEMPTS_PER_TASK=5 -# MAX_REVIEW_ITERATIONS=5 # fix+re-review cycles within one impl-review before giving up -# WORKER_TIMEOUT=2700 # seconds; default 45min. Increase for complex tasks with many review rounds (e.g., 3600=60min) +# MAX_REVIEW_ITERATIONS=3 # fix+re-review cycles within one impl-review before giving up (default 3) +# WORKER_TIMEOUT=3600 # seconds; default 1hr. Safety guard against runaway workers, not primary flow control # YOLO sets OPENCODE_PERMISSION='{"*":"allow"}' (required for unattended runs) YOLO=1 diff --git a/.opencode/skill/flow-next-opencode-ralph-init/templates/ralph.sh b/.opencode/skill/flow-next-opencode-ralph-init/templates/ralph.sh index 5e5a856..b9f4e2b 100644 --- a/.opencode/skill/flow-next-opencode-ralph-init/templates/ralph.sh +++ b/.opencode/skill/flow-next-opencode-ralph-init/templates/ralph.sh @@ -328,7 +328,7 @@ set +a MAX_ITERATIONS="${MAX_ITERATIONS:-25}" MAX_TURNS="${MAX_TURNS:-}" # empty = no limit; unused for OpenCode (kept for parity) MAX_ATTEMPTS_PER_TASK="${MAX_ATTEMPTS_PER_TASK:-5}" -WORKER_TIMEOUT="${WORKER_TIMEOUT:-2700}" # 45min default; prevents stuck workers +WORKER_TIMEOUT="${WORKER_TIMEOUT:-3600}" # 1hr default; safety guard against runaway workers BRANCH_MODE="${BRANCH_MODE:-new}" PLAN_REVIEW="${PLAN_REVIEW:-none}" WORK_REVIEW="${WORK_REVIEW:-none}" diff --git a/.opencode/skill/flow-next-opencode-sync/SKILL.md b/.opencode/skill/flow-next-opencode-sync/SKILL.md index 24bfb98..2fae0bc 100644 --- a/.opencode/skill/flow-next-opencode-sync/SKILL.md +++ b/.opencode/skill/flow-next-opencode-sync/SKILL.md @@ -36,6 +36,14 @@ Parse $ARGUMENTS for: - First positional arg = `ID` - `--dry-run` flag = `DRY_RUN` (true/false) +Get cross-epic config (defaults to false): +```bash +CROSS_EPIC="$($FLOWCTL config get planSync.crossEpic --json 2>/dev/null | jq -r '.value // empty')" +if [[ -z "$CROSS_EPIC" || "$CROSS_EPIC" == "null" ]]; then + CROSS_EPIC="false" +fi +``` + **Validate ID format:** - Must start with `fn-` - If no ID: "Usage: /flow-next:sync [--dry-run]" @@ -108,6 +116,7 @@ FLOWCTL: $OPENCODE_DIR/bin/flowctl EPIC_ID: DOWNSTREAM_TASK_IDS: DRY_RUN: +CROSS_EPIC: DRY RUN MODE: Report changes but do NOT edit files. diff --git a/.opencode/version b/.opencode/version index ee1372d..abd4105 100644 --- a/.opencode/version +++ b/.opencode/version @@ -1 +1 @@ -0.2.2 +0.2.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e13be4..eb326f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,16 @@ - **Config defaults expanded** — Added `planSync.enabled` and `review.backend` to config schema - **`deep_merge()` for config** — Properly merges user config with defaults +### Ported from upstream 0.14.0 → 0.16.0 + +- **New planning scouts** — `epic-scout` (auto epic deps) + `docs-gap-scout` (doc update ACs) +- **Plan-sync cross-epic option** — `planSync.crossEpic` (default false) + agent support +- **RepoPrompt builder review mode** — `flowctl rp` supports `--response-type review`, `--chat-id`, `--mode` +- **RP impl-review upgrade** — Uses builder review mode (**requires RepoPrompt 1.6.0+**) +- **Interview boundary fixes** — No task creation, preserve task planning detail, clearer epic/task routing +- **Setup version warning** — Plan/Interview warn when local setup is outdated +- **Ralph defaults** — `WORKER_TIMEOUT` 3600s, `MAX_REVIEW_ITERATIONS` 3 + ### Other - Rename OpenCode skills to `flow-next-opencode-*` to avoid Claude skill collisions diff --git a/README.md b/README.md index 9aa34bd..aeb2630 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Interview → Plan → Work ``` 1. **Interview first** — `/flow-next:interview "your rough idea"` asks deep questions to surface requirements, edge cases, and decisions you haven’t thought about -2. **Plan** — `/flow-next:plan fn-1` researches best practices, current docs, repo patterns, then splits into properly-sized tasks +2. **Plan** — `/flow-next:plan fn-1` researches best practices, current docs, repo patterns, scans open epics for dependencies, flags doc updates, then splits into properly-sized tasks 3. **Work** — `/flow-next:work fn-1` executes with re-anchoring and reviews #### Well-written spec or PRD @@ -148,7 +148,7 @@ Interview → Plan → Work Plan → Interview → Work ``` -1. **Plan first** — `/flow-next:plan specs/my-feature.md` researches best practices and current patterns, then breaks your spec into epic + tasks +1. **Plan first** — `/flow-next:plan specs/my-feature.md` researches best practices, current patterns, epic dependencies, and doc updates, then breaks your spec into epic + tasks 2. **Interview after** — `/flow-next:interview fn-1` runs deep questions against the plan to catch edge cases, missing requirements, or assumptions 3. **Work** — `/flow-next:work fn-1` executes @@ -334,6 +334,11 @@ Enable auto-sync after each task (optional): flowctl config set planSync.enabled true ``` +Optional cross-epic sync (off by default): +```bash +flowctl config set planSync.crossEpic true +``` + ### Dependency Graphs Tasks declare blockers; `flowctl ready` shows what can start. Nothing executes until dependencies resolve. @@ -367,6 +372,8 @@ Change those if you want a different model or effort. [RepoPrompt](https://repoprompt.com/?atp=KJbuL4) provides the best review experience on macOS. +**Requires RepoPrompt 1.6.0+** for the rp review backend (builder review mode). + **Why use RepoPrompt:** * Best-in-class context builder for reviews (full file context, smart selection) * Optional: enables the planning **context-scout** for deeper discovery vs repo-scout diff --git a/docs/flowctl.md b/docs/flowctl.md index 090de98..1c8c0e7 100644 --- a/docs/flowctl.md +++ b/docs/flowctl.md @@ -372,10 +372,14 @@ Manage project configuration stored in `.flow/config.json`. # Get a config value flowctl config get memory.enabled [--json] flowctl config get review.backend [--json] +flowctl config get planSync.enabled [--json] +flowctl config get planSync.crossEpic [--json] # Set a config value flowctl config set memory.enabled true [--json] flowctl config set review.backend opencode [--json] # rp, opencode, or none +flowctl config set planSync.enabled true [--json] +flowctl config set planSync.crossEpic true [--json] # Toggle boolean config flowctl config toggle memory.enabled [--json] @@ -386,6 +390,8 @@ flowctl config toggle memory.enabled [--json] | Key | Type | Default | Description | |-----|------|---------|-------------| | `memory.enabled` | bool | `false` | Enable memory system | +| `planSync.enabled` | bool | `false` | Enable plan-sync after task completion | +| `planSync.crossEpic` | bool | `false` | Also scan other open epics for stale references | | `review.backend` | string | auto | Default review backend (`rp`, `opencode`, `none`) | Auto-detect priority: `FLOW_REVIEW_BACKEND` env → config → available CLI. @@ -426,6 +432,7 @@ EOF flowctl prep-chat \ --message-file /tmp/prompt.md \ --mode chat \ + [--chat-id ""] \ [--new-chat] \ [--chat-name "Review Name"] \ [--selected-paths file1.ts file2.ts] \ @@ -437,7 +444,8 @@ flowctl rp chat-send --window W --tab T --message-file /tmp/prompt.md Options: - `--message-file FILE` (required): File containing the message text -- `--mode {chat,ask}`: Chat mode (default: chat) +- `--mode {chat,ask,review,plan,edit}`: Chat mode (default: chat) +- `--chat-id ID`: Continue existing chat - `--new-chat`: Start a new chat session - `--chat-name NAME`: Name for the new chat - `--selected-paths FILE...`: Files to include in context (for follow-ups) @@ -452,14 +460,18 @@ Output (stdout or file): RepoPrompt wrappers (preferred for reviews): +Requires RepoPrompt 1.6.0+ for `--response-type review`. + ```bash flowctl rp pick-window --repo-root "$REPO_ROOT" flowctl rp ensure-workspace --window "$W" --repo-root "$REPO_ROOT" flowctl rp builder --window "$W" --summary "Review a plan to ..." +flowctl rp builder --window "$W" --summary "Review implementation..." --response-type review +flowctl rp setup-review --repo-root "$REPO_ROOT" --summary "Review implementation..." --response-type review --json flowctl rp prompt-get --window "$W" --tab "$T" flowctl rp prompt-set --window "$W" --tab "$T" --message-file /tmp/review-prompt.md flowctl rp select-add --window "$W" --tab "$T" path/to/file -flowctl rp chat-send --window "$W" --tab "$T" --message-file /tmp/review-prompt.md +flowctl rp chat-send --window "$W" --tab "$T" --message-file /tmp/review-prompt.md --chat-id "$CHAT_ID" --mode review flowctl rp prompt-export --window "$W" --tab "$T" --out /tmp/export.md ``` diff --git a/docs/ralph.md b/docs/ralph.md index 1ec80af..629ff6f 100644 --- a/docs/ralph.md +++ b/docs/ralph.md @@ -6,18 +6,18 @@ Ralph is Flow-Next's repo-local autonomous harness. It loops over tasks, applies ## Quick Start -### Step 1: Setup (inside Claude) +### Step 1: Setup (inside OpenCode) -Run the init skill from Claude Code: +Run the init skill from OpenCode: ```bash /flow-next:ralph-init ``` -Or run setup from terminal without entering Claude: +Or run setup from terminal without entering OpenCode: ```bash -claude -p "/flow-next:ralph-init" +opencode run "/flow-next:ralph-init" ``` This scaffolds `scripts/ralph/` with: @@ -31,8 +31,8 @@ This scaffolds `scripts/ralph/` with: Before running, set your review backends in `scripts/ralph/config.env`: ```bash -PLAN_REVIEW=codex # or: rp, none -WORK_REVIEW=codex # or: rp, none +PLAN_REVIEW=opencode # or: rp, none +WORK_REVIEW=opencode # or: rp, none ``` See [Configuration](#configuration) for all options. @@ -45,13 +45,13 @@ scripts/ralph/ralph_once.sh Runs ONE iteration then exits. Observe the output before committing to a full run. -### Step 2: Run (outside Claude) +### Step 2: Run (outside OpenCode) ```bash scripts/ralph/ralph.sh ``` -Ralph spawns Claude sessions via `claude -p`, loops until done, and applies review gates. +Ralph spawns OpenCode runs via `opencode run`, loops until done, and applies review gates. **Watch mode** - see what's happening in real-time: ```bash @@ -85,14 +85,14 @@ rm -rf scripts/ralph/ ## How It Works -Ralph wraps Claude Code in a shell loop with quality gates: +Ralph wraps OpenCode in a shell loop with quality gates: ``` ┌─────────────────────────────────────────────────────────┐ │ scripts/ralph/ralph.sh │ │ ┌──────────────────────────────────────────────────┐ │ │ │ while flowctl next returns work: │ │ -│ │ 1. claude -p "/flow-next:plan" or :work │ │ +│ │ 1. opencode run "/flow-next:plan" or :work │ │ │ │ 2. check review receipts │ │ │ │ 3. if missing/invalid → retry │ │ │ │ 4. if SHIP verdict → next task │ │ @@ -121,12 +121,12 @@ flowchart TD ## Why Flow-Next Ralph vs Anthropic's ralph-wiggum? -Anthropic's official ralph-wiggum plugin uses a Stop hook to keep Claude in the same session. Flow-Next inverts this architecture for production-grade reliability. +Anthropic's official ralph-wiggum plugin uses a Stop hook to keep the model in the same session. Flow-Next inverts this architecture for production-grade reliability. | Aspect | ralph-wiggum | Flow-Next Ralph | |--------|--------------|-----------------| | **Session model** | Single session, accumulating context | Fresh context per iteration | -| **Loop mechanism** | Stop hook re-feeds prompt in SAME session | External bash loop, new `claude -p` each iteration | +| **Loop mechanism** | Stop hook re-feeds prompt in SAME session | External bash loop, new `opencode run` each iteration | | **Context management** | Transcript grows, context fills up | Clean slate every time | | **Failed attempts** | Pollute future iterations | Gone with the session | | **Re-anchoring** | None | Re-reads epic/task spec EVERY iteration | @@ -138,8 +138,8 @@ Anthropic's official ralph-wiggum plugin uses a Stop hook to keep Claude in the **The Core Problem with ralph-wiggum** 1. **Context pollution** - Every failed attempt stays in context, potentially misleading future iterations -2. **No re-anchoring** - As context fills, Claude loses sight of the original task spec -3. **Single model** - No external validation; Claude grades its own homework +2. **No re-anchoring** - As context fills, the model loses sight of the original task spec +3. **Single model** - No external validation; the model grades its own homework 4. **Binary outcome** - Either completion promise triggers, or you hit max iterations **Flow-Next's Solution** @@ -160,10 +160,10 @@ Reviews use a second model to verify code. Two models catch what one misses. **Review backends:** - `rp` — [RepoPrompt](https://repoprompt.com/?atp=KJbuL4) (macOS only, GUI-based) **← recommended** -- `codex` — OpenAI Codex CLI (cross-platform, terminal-based) +- `opencode` — OpenCode review (cross-platform, terminal-based) - `none` — skip reviews (not recommended for production) -**We recommend RepoPrompt** when available. Its Builder provides full file context with intelligent selection, while Codex uses heuristic context hints from changed files. Both use the same Carmack-level review criteria. +**We recommend RepoPrompt** when available. Its Builder provides full file context with intelligent selection, while OpenCode uses the provided diff context. Both use the same Carmack-level review criteria. - Plan reviews verify architecture and edge cases before coding starts - Impl reviews verify the implementation meets spec after each task @@ -220,12 +220,12 @@ Edit `scripts/ralph/config.env`: | Variable | Values | Description | |----------|--------|-------------| -| `PLAN_REVIEW` | `rp`, `codex`, `none` | How to review plans | -| `WORK_REVIEW` | `rp`, `codex`, `none` | How to review implementations | +| `PLAN_REVIEW` | `rp`, `opencode`, `none` | How to review plans | +| `WORK_REVIEW` | `rp`, `opencode`, `none` | How to review implementations | | `REQUIRE_PLAN_REVIEW` | `1`, `0` | Block work until plan review passes | - `rp` — RepoPrompt (macOS, requires GUI) -- `codex` — OpenAI Codex CLI (cross-platform, terminal-based) +- `opencode` — OpenCode review (cross-platform) - `none` — skip reviews ### Branch Settings @@ -245,8 +245,10 @@ With `BRANCH_MODE=new`, all epics work on the same run branch. Commits are prefi | Variable | Default | Description | |----------|---------|-------------| | `MAX_ITERATIONS` | `25` | Total loop iterations | -| `MAX_TURNS` | (empty) | Claude turns per iteration (empty = unlimited) | +| `MAX_TURNS` | (empty) | OpenCode turns per iteration (empty = unlimited) | | `MAX_ATTEMPTS_PER_TASK` | `5` | Retries before auto-blocking task | +| `MAX_REVIEW_ITERATIONS` | `3` | Fix+re-review cycles within one impl-review | +| `WORKER_TIMEOUT` | `3600` | Seconds before killing stuck worker (1hr safety guard) | ### Scope @@ -258,9 +260,9 @@ With `BRANCH_MODE=new`, all epics work on the same run branch. Commits are prefi | Variable | Default | Effect | |----------|---------|--------| -| `YOLO` | `1` | Passes `--dangerously-skip-permissions` to Claude | +| `YOLO` | `1` | Sets `OPENCODE_PERMISSION='{\"*\":\"allow\"}'` for unattended runs | -Note: `-p` mode is headless but still prompts for file/command permissions. `YOLO=1` (the default) is required for truly unattended runs. Set `YOLO=0` for interactive testing. +Note: Unattended runs need permissions set. `YOLO=1` (the default) is required for truly unattended runs. Set `YOLO=0` for interactive testing. ### Display @@ -276,7 +278,7 @@ Each run creates: ``` scripts/ralph/runs// - ├── iter-001.log # Raw Claude output + ├── iter-001.log # Raw OpenCode output ├── iter-002.log ├── progress.txt # Append-only run log ├── attempts.json # Per-task retry counts @@ -305,27 +307,23 @@ Never call `rp-cli` directly in Ralph mode. --- -## Codex Integration +## OpenCode Integration -When `PLAN_REVIEW=codex` or `WORK_REVIEW=codex`, Ralph uses `flowctl codex` wrappers: +When `PLAN_REVIEW=opencode` or `WORK_REVIEW=opencode`, Ralph uses `flowctl opencode` wrappers: ```bash -flowctl codex check # Verify codex available -flowctl codex impl-review ... # Run implementation review -flowctl codex plan-review ... # Run plan review +flowctl opencode impl-review ... # Run implementation review +flowctl opencode plan-review ... # Run plan review ``` **Requirements:** -- OpenAI Codex CLI installed and authenticated (`npm install -g @openai/codex && codex auth`) +- OpenCode CLI installed and authenticated -**Model:** Default is `gpt-5.2` with high reasoning (GPT 5.2 High). Override with `FLOW_CODEX_MODEL` env var. +**Model:** Default is `openai/gpt-5.2` with high reasoning (configured in `.opencode/opencode.json`). **Advantages over rp:** - Cross-platform (Windows, Linux, macOS) - Terminal-based (no GUI required) -- Session continuity via thread_id - -**Session continuity:** Codex reviews store `thread_id` in receipts. Subsequent reviews in the same run continue the conversation. --- @@ -355,19 +353,12 @@ After `MAX_ATTEMPTS_PER_TASK` failures, Ralph: Ensure rp-cli is installed and RepoPrompt window is open on your repo. Alternatives: -- Use Codex instead: set `PLAN_REVIEW=codex` and `WORK_REVIEW=codex` +- Use OpenCode instead: set `PLAN_REVIEW=opencode` and `WORK_REVIEW=opencode` - Skip reviews: set `PLAN_REVIEW=none` and `WORK_REVIEW=none` -### Codex not found - -Ensure Codex CLI is installed and authenticated: - -```bash -npm install -g @openai/codex -codex auth -``` +### OpenCode not found -Or switch to RepoPrompt: set `PLAN_REVIEW=rp` and `WORK_REVIEW=rp`. +Ensure OpenCode CLI is installed and authenticated. --- @@ -387,10 +378,10 @@ Run Ralph inside Docker sandbox for extra isolation: ```bash # From your project directory -docker sandbox run claude "scripts/ralph/ralph.sh" +docker sandbox run opencode "scripts/ralph/ralph.sh" # Or specify workspace explicitly -docker sandbox run -w ~/my-project claude "scripts/ralph/ralph.sh" +docker sandbox run -w ~/my-project opencode "scripts/ralph/ralph.sh" ``` See [Docker sandbox docs](https://docs.docker.com/ai/sandboxes/claude-code/) for details. @@ -402,7 +393,7 @@ scripts/ralph/ralph.sh --watch # Stream tool calls in real-time scripts/ralph/ralph.sh --watch verbose # Also stream model responses ``` -Watch mode shows you what Claude is doing without blocking autonomy. Tool calls display with icons and colors. Logs still captured to `runs//iter-*.log`. +Watch mode shows you what OpenCode is doing without blocking autonomy. Tool calls display with icons and colors. Logs still captured to `runs//iter-*.log`. ### Verbose logging @@ -415,9 +406,9 @@ Appends detailed logs to `scripts/ralph/runs//ralph.log`. ### Debug environment variables ```bash -FLOW_RALPH_CLAUDE_MODEL=claude-opus-4-5-20251101 # Force model -FLOW_RALPH_CLAUDE_DEBUG=hooks # Debug hooks -FLOW_RALPH_CLAUDE_PERMISSION_MODE=bypassPermissions +FLOW_RALPH_OPENCODE_MODEL=openai/gpt-5.2 # Force model +FLOW_RALPH_OPENCODE_VARIANT=high # Force variant +OPENCODE_BIN=/usr/local/bin/opencode ``` --- @@ -434,9 +425,9 @@ Ralph includes plugin hooks that enforce workflow rules deterministically. |------|-----| | No `--json` on chat-send | Preserves review text output (rp) | | No `--new-chat` on re-reviews | First review creates chat, subsequent stay in same (rp) | -| Receipt must exist before Stop | Blocks Claude from stopping without writing receipt | +| Receipt must exist before Stop | Blocks OpenCode from stopping without writing receipt | | Required flags on setup/select-add | Ensures proper window/tab targeting (rp) | -| Track codex review verdicts | Validates codex review completed successfully | +| Track opencode review verdicts | Validates opencode review completed successfully | ### Guard plugin location (OpenCode)