-
Notifications
You must be signed in to change notification settings - Fork 4
feat: inherit OpenCode prompts for Build+ and Plan+ agents #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Build+: Remove redundant inherited content (OpenCode auto-injects base prompts) - Plan+: Add placeholder for dynamic plan.txt injection from OpenCode binary - Add extract-opencode-prompts.sh to extract prompts from OpenCode binary - Update setup.sh to extract prompts before deployment and inject into Plan+ - Disable default 'build' and 'plan' agents in favor of Build+ and Plan+ When users update OpenCode and run setup.sh, Plan+ automatically gets the latest plan.txt system-reminder content, ensuring compatibility with OpenCode updates.
|
Caution Review failedThe pull request is closed. WalkthroughThese changes introduce prompt extraction automation and agent configuration updates. A new utility script extracts OpenCode model-specific prompts to a cache directory; setup automation injects extracted content into Plan+ and reorders agent precedence, with legacy agents disabled by default. Changes
Sequence DiagramsequenceDiagram
participant Setup as setup.sh
participant Extract as extract-opencode-prompts.sh
participant OpenCode as opencode binary
participant Cache as ~/.aidevops/cache
participant PlanPlus as plan-plus.md
Setup->>Setup: Main sequence begins
Setup->>Extract: Call extract_opencode_prompts()
Extract->>Extract: Locate opencode binary
Extract->>OpenCode: Query --version
OpenCode-->>Extract: Return version
Extract->>Extract: Extract prompts from binary<br/>(plan_default, build_switch_default)
Extract->>Cache: Write prompts, version, timestamp
Extract-->>Setup: Return success (non-fatal on error)
Setup->>Setup: Continue setup flow
Setup->>PlanPlus: Inject plan-reminder content<br/>(if placeholder exists)
PlanPlus->>PlanPlus: Replace OPENCODE-PLAN-REMINDER-INJECT
Setup->>Setup: Complete setup with injected agents
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Heterogeneous changes spanning documentation updates, new utility script, agent configuration reordering, and setup automation with conditional injection logic. The prompt extraction and injection flows introduce new logic requiring careful review of path handling, cache management, and awk-based string replacement. Poem
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @marcusquinn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Mon Dec 22 22:48:00 UTC 2025 Generated by AI DevOps Framework Code Review Monitoring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a mechanism to dynamically inherit prompts from the OpenCode binary for the Build+ and Plan+ agents. This is achieved by a new script that extracts prompts from the binary during setup, and another script modification to inject this content. My review focuses on the robustness and maintainability of these new scripts. I've identified a few areas for improvement in the new shell scripts, particularly concerning the fragility of the prompt extraction logic and potential data corruption during content injection. I've provided suggestions to make these scripts more robust and portable.
| strings "$OPENCODE_BIN" | \ | ||
| grep -A 500 "^${start_marker}" | \ | ||
| head -n 100 | \ | ||
| sed "s/^${start_marker}//" | \ | ||
| sed '/^var init_/q' | \ | ||
| sed '/^var init_/d' | \ | ||
| sed 's/`$//' \ | ||
| > "$CACHE_DIR/$output_file" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This extraction logic is very brittle as it relies on parsing the string table of the compiled opencode binary. This approach can easily break with:
- Future versions of OpenCode.
- Changes in Go compiler versions.
- Different build flags.
- Simple refactoring of variable names in the OpenCode source.
The script's assumptions about variable names (plan_default, init_...) and their order are risky.
For long-term stability, a more robust solution would be for OpenCode to provide a command to export these prompts (e.g., opencode internal export-prompts). While that's likely outside the scope of this PR, I strongly recommend adding a comment to this script highlighting the fragility of this approach for future maintainers.
| local reminder_content | ||
| reminder_content=$(cat "$plan_reminder") | ||
| # Use awk to replace the placeholder section | ||
| awk -v content="$reminder_content" ' | ||
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-START -->/ { print; print content; skip=1; next } | ||
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-END -->/ { skip=0 } | ||
| !skip { print } | ||
| ' "$plan_plus" > "$plan_plus.tmp" && mv "$plan_plus.tmp" "$plan_plus" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using awk -v content="$reminder_content" where reminder_content is read from a file can be risky. The content of the variable is interpreted as a string by awk, and any backslash escape sequences will be processed. This can lead to data corruption if the prompt text contains backslashes (e.g., in file paths or regular expressions).
A more robust method is to have awk read the content directly from the reminder file. This avoids any shell or awk variable interpolation issues.
| local reminder_content | |
| reminder_content=$(cat "$plan_reminder") | |
| # Use awk to replace the placeholder section | |
| awk -v content="$reminder_content" ' | |
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-START -->/ { print; print content; skip=1; next } | |
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-END -->/ { skip=0 } | |
| !skip { print } | |
| ' "$plan_plus" > "$plan_plus.tmp" && mv "$plan_plus.tmp" "$plan_plus" | |
| # Use awk to replace the placeholder section, reading content from the file directly to avoid issues with special characters. | |
| awk -v reminder_file="$plan_reminder" ' | |
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-START -->/ { | |
| while ((getline line < reminder_file) > 0) { | |
| print line | |
| } | |
| close(reminder_file) | |
| skip=1 | |
| next | |
| } | |
| /<!-- OPENCODE-PLAN-REMINDER-INJECT-END -->/ { skip=0 } | |
| !skip { print } | |
| ' "$plan_plus" > "$plan_plus.tmp" && mv "$plan_plus.tmp" "$plan_plus" |
| find_opencode_binary() { | ||
| local locations=( | ||
| "$HOME/.bun/install/global/node_modules/opencode-darwin-arm64/bin/opencode" | ||
| "$HOME/.bun/install/global/node_modules/opencode-darwin-x64/bin/opencode" | ||
| "$HOME/.bun/install/global/node_modules/opencode-linux-x64/bin/opencode" | ||
| "$HOME/.bun/install/global/node_modules/opencode-linux-arm64/bin/opencode" | ||
| "/usr/local/bin/opencode" | ||
| "$HOME/.local/bin/opencode" | ||
| ) | ||
|
|
||
| for loc in "${locations[@]}"; do | ||
| if [[ -f "$loc" ]]; then | ||
| OPENCODE_BIN="$loc" | ||
| return 0 | ||
| fi | ||
| done | ||
|
|
||
| # Try which as fallback | ||
| if command -v opencode &>/dev/null; then | ||
| local bin_path | ||
| bin_path=$(which opencode) | ||
| # Follow symlinks to find actual binary | ||
| if [[ -L "$bin_path" ]]; then | ||
| bin_path=$(readlink -f "$bin_path" 2>/dev/null || readlink "$bin_path") | ||
| fi | ||
| if [[ -f "$bin_path" ]]; then | ||
| OPENCODE_BIN="$bin_path" | ||
| return 0 | ||
| fi | ||
| fi | ||
|
|
||
| return 1 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function find_opencode_binary has a side effect of modifying the global variable OPENCODE_BIN. While this works, it's generally better practice to avoid modifying global state from within functions to improve modularity and make the code easier to reason about.
Consider refactoring this function to print the found path to standard output. The calling function (main) can then capture this output into a variable. This makes the data flow explicit and the function more reusable. For example, you would change lines like OPENCODE_BIN="$loc" to echo "$loc" and then in main you would call it like OPENCODE_BIN=$(find_opencode_binary).
| bin_path=$(which opencode) | ||
| # Follow symlinks to find actual binary | ||
| if [[ -L "$bin_path" ]]; then | ||
| bin_path=$(readlink -f "$bin_path" 2>/dev/null || readlink "$bin_path") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of readlink -f is not portable to macOS, where it's part of coreutils and not installed by default. The fallback readlink "$bin_path" is not a full replacement, as it only resolves one level of symbolic links, whereas -f resolves them recursively. This could cause the script to fail in finding the opencode binary if it's located behind multiple nested symlinks. For better portability, consider a loop to resolve symlinks until a real file is found.



Summary
plan.txtfrom OpenCode binary during setupbuildandplanagents disabled to avoid Tab cycle confusionChanges
plan.txtinjectionHow it works
When users update OpenCode and run
./setup.sh:~/.aidevops/cache/opencode-prompts/plan.txtcontent injected automaticallySummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.