feat: inherit OpenCode prompts for Build+ and Plan+ agents#7
feat: inherit OpenCode prompts for Build+ and Plan+ agents#7marcusquinn merged 1 commit intomainfrom
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.
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.
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.
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.
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.
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.
Add prompt injection scanning references to three core files: - build-plus.md: scanning guidance in Fetch URLs step + external content table - build.txt: security rule #7 for untrusted content scanning via scan-stdin - opsec.md: T6 threat tier + Prompt Injection Defense section + cross-ref Tool-agnostic approach using prompt-guard-helper.sh scan-stdin. References prompt-injection-defender.md (t1375.2) for full threat model.
* docs: wire prompt injection scanning into agent guidance (t1375.3) Add prompt injection scanning references to three core files: - build-plus.md: scanning guidance in Fetch URLs step + external content table - build.txt: security rule #7 for untrusted content scanning via scan-stdin - opsec.md: T6 threat tier + Prompt Injection Defense section + cross-ref Tool-agnostic approach using prompt-guard-helper.sh scan-stdin. References prompt-injection-defender.md (t1375.2) for full threat model. * fix: replace non-existent scan-stdin with actual prompt-guard-helper.sh API The docs referenced 'prompt-guard-helper.sh scan-stdin' which does not exist. The actual API is 'prompt-guard-helper.sh scan "$content"' (positional arg) or 'prompt-guard-helper.sh scan-file <file>' for file-based content. Resolves CodeRabbit CHANGES_REQUESTED on PR #2710. * docs: add scan-file and scan-stdin variants to prompt injection guidance Address CodeRabbit review requesting file-based scanner variant documentation. The code block now shows all three subcommands: - scan: small inline strings (shell variables, short text) - scan-file: large/file-based content (downloads, uploads, PR diffs) - scan-stdin: piped content in pipelines (added by t1375.1 / PR #2715) Also updates the external content lookup table to reference all variants. * fix: add version dependency note for scan-stdin and clarify scanner variants Address CodeRabbit CHANGES_REQUESTED on PR #2710: - build-plus.md: add version note (v1.x+) for scan-stdin pipeline variant - build.txt: clarify scan (small strings) vs scan-file (large/file payloads) and note scan-stdin requires prompt-guard-helper.sh v1.x+ (added by t1375.1) * feat: add scan-stdin, check-stdin, sanitize-stdin subcommands to prompt-guard-helper.sh Implement stdin-reading variants so docs references to 'scan-stdin' are valid without waiting for PR #2715 to merge. Each reads piped content via cat and delegates to the existing cmd_scan/cmd_check/cmd_sanitize functions. Also removes the 'requires v1.x+' caveat from build-plus.md and build.txt since the subcommand now exists on this branch.
- config-helper.sh: detect malformed user config instead of silently
falling back to {} — emit error to stderr in _merge_configs, cmd_list,
cmd_set, and cmd_reset (missing file is still OK, parse failure is not)
- config-helper.sh cmd_validate: add JSON Schema validation using
ajv-cli or python3 jsonschema when available, with safe argv passing
- shared-constants.sh _load_config: guard JSONC mode on config_get and
config_enabled function availability, not just jq + defaults file
Issues #1 (eval→printf -v), #3 (jq --arg for strings), #4 (sourced vs
executed detection), and #7 (deterministic exit 1) were already fixed
in the prior commit.
* feat: replace feature-toggles.conf with namespaced JSONC config system Replace the flat key=value feature-toggles.conf with a fully comprehensive namespaced JSONC configuration file (aidevops.defaults.jsonc). Every configurable opinion in the codebase is now properly namespaced under semantic categories: updates, integrations, orchestration, safety, ui, models, quality, verification, and paths. New files: - .agents/configs/aidevops.defaults.jsonc — all defaults with comments - .agents/configs/aidevops-config.schema.json — JSON Schema for validation - .agents/scripts/config-helper.sh — JSONC reader/writer (jq-based) Key design decisions: - JSONC format supports comments, schema refs, and object values - User config at ~/.config/aidevops/config.jsonc overrides defaults - Automatic migration from legacy feature-toggles.conf on first use - Full backward compatibility: get_feature_toggle/is_feature_enabled still work with flat keys, mapped to new dotpaths internally - Falls back to legacy .conf parsing when jq is not available - Environment variables still take highest priority Updated scripts: - shared-constants.sh: loads JSONC config, backward-compatible API - feature-toggle-helper.sh: delegates to config-helper.sh - aidevops.sh: config command prefers config-helper.sh - setup.sh, setup-modules/config.sh, auto-update-helper.sh: updated comments to reference new namespaced dotpaths Closes #2730 * fix: address CodeRabbit security and robustness review on JSONC config - Replace eval with printf -v in _load_feature_toggles_legacy (shared-constants.sh) - Guard set -euo pipefail to only apply when executed directly, not sourced (config-helper.sh) - Propagate _strip_jsonc failures instead of silently returning {} (config-helper.sh) - Fix gsub for multiple /* */ block comments on same line via while loop (config-helper.sh) - Use jq --arg/--argjson for all dotpath and value passing to prevent shell injection (config-helper.sh) - Add _validate_dotpath to reject dotpaths with unsafe characters (config-helper.sh) - Remove misleading legacy fallback in feature-toggle-helper.sh, fail deterministically - Read numeric interval values via get_feature_toggle instead of raw env vars (auto-update-helper.sh) * fix: address remaining CodeRabbit/Gemini review issues on JSONC config - config-helper.sh: detect malformed user config instead of silently falling back to {} — emit error to stderr in _merge_configs, cmd_list, cmd_set, and cmd_reset (missing file is still OK, parse failure is not) - config-helper.sh cmd_validate: add JSON Schema validation using ajv-cli or python3 jsonschema when available, with safe argv passing - shared-constants.sh _load_config: guard JSONC mode on config_get and config_enabled function availability, not just jq + defaults file Issues #1 (eval→printf -v), #3 (jq --arg for strings), #4 (sourced vs executed detection), and #7 (deterministic exit 1) were already fixed in the prior commit. * fix(config-helper): propagate malformed user config error in _merge_configs * fix(config-helper): check _strip_jsonc exit status in cmd_validate * fix: surface auto-migration failures instead of swallowing errors Replace '|| true' with explicit error handling that warns users when auto-migration from legacy config fails. Both config-helper.sh main() and shared-constants.sh _load_config() now emit a stderr warning with actionable guidance ('aidevops config migrate') instead of silently continuing with no user config applied. Addresses CodeRabbit CHANGES_REQUESTED review on PR #2731. * fix(config-helper): address final CodeRabbit review issues Log jq deep-merge failures in _merge_configs instead of silently falling back to defaults. Addresses CodeRabbit nitpick from the post-fix review (2026-03-02T21:24:32Z). Previous commits already addressed the two CHANGES_REQUESTED issues: - f4cfcba: propagate malformed user config error (return 1) - d093867: check _strip_jsonc exit status in cmd_validate - 4e6e046: surface auto-migration failures * fix(config-helper): capture stderr and exit code from auto-migration The _migrate_conf_to_jsonc call in main() swallowed both stderr and the exit status (2>/dev/null). Now captures stderr separately for diagnostic logging, preserves the exit code, and touches ~/.aidevops/migrate_failed on failure so the CLI can surface 'auto-migration failed' to the user. On success, removes the flag file. Closes #2730 * fix: surface remaining silent failures flagged by CodeRabbit review - config-helper.sh _merge_configs(): capture jq stderr and include it in the error log when deep merge fails, instead of suppressing with 2>/dev/null - shared-constants.sh _load_config(): stop suppressing migration stderr so users see the actual error from _migrate_conf_to_jsonc - auto-update-helper.sh cmd_enable(): use get_feature_toggle for update_interval instead of direct env var access, matching the pattern used by all other numeric config values - auto-update-helper.sh cmd_status(): use get_feature_toggle for tool_idle_hours instead of direct env var access
- Fix data corruption in cmd_archive/cmd_remove: collect all section headers into an immutable snapshot before any deletions, then delete in reverse order so earlier line offsets remain valid (fixes #1) - Fix sed error suppression: remove '|| true', capture exit status, only increment archived/removed counters on success (fixes #2) - Fix check_todo_completed: remove '|| echo 0' fallback that caused duplicate zero output; grep -c already returns 0 on no match (fixes #3) - Fix agent-deploy.sh: remove 2>/dev/null suppression on plans_cleanup invocation, log failures via print_warn instead of silencing (fixes #4) - Fix agent-deploy.sh: pass explicit PLANS_FILE/ARCHIVE_FILE/TODO_FILE env vars so plans_cleanup targets the repo dir, not cwd; use deployed copy of script from target_dir (fixes #5) - Fix setup.sh: gate standalone archive confirm_step to only run when deploy_aidevops_agents was skipped; deploy already runs cleanup internally, so running it again would be a double-run (fixes #6) - Fix PLANS.md: change 'MERGED' to 'CLOSED' for issue references in Issues summary line (fixes #7)
…5355) * chore: archive completed plans from PLANS.md and add cleanup helper All 16 plans in PLANS.md had Status: Planning but all their tasks were completed and issues closed upstream. Updated status to Completed. Added plans-cleanup-helper.sh to automate detection and archiving of completed plans. Wired into setup.sh and agent-deploy.sh so new installs get a clean PLANS.md with only active work. Commands: - check: show completion status of all plans - archive: move completed plans to PLANS-ARCHIVE.md - remove: delete completed plans entirely - status: JSON summary Fixes stale 'Planning' status for: - Restore OpenAI Codex (t1483, GH#4656) - Agent Runtime Sync (t1453, GH#4205) - gh Mutation Fix (t1434, GH#4122) - Grith Security (t1428, GH#4025) - Convos Agent (t1414, GH#3126) - URL Skill Updates (t1415, GH#3131) - Recursive Decomposition (t1408, GH#2983) - LLM Evaluation Suite (t1393-1396) - Runaway Memory Fix (t1398, GH#2854) - Prompt Injection Scanner (t1375) - Vector Search Agent (t1370) - UI/UX Inspiration (t1371-1374) - PaddleOCR (t1369) - Multi-Model Orchestration (t1364) - Mission System (t1357) - Conversational Memory (t1363) * fix: address CodeRabbit review findings on plans-cleanup PR #5355 - Fix data corruption in cmd_archive/cmd_remove: collect all section headers into an immutable snapshot before any deletions, then delete in reverse order so earlier line offsets remain valid (fixes #1) - Fix sed error suppression: remove '|| true', capture exit status, only increment archived/removed counters on success (fixes #2) - Fix check_todo_completed: remove '|| echo 0' fallback that caused duplicate zero output; grep -c already returns 0 on no match (fixes #3) - Fix agent-deploy.sh: remove 2>/dev/null suppression on plans_cleanup invocation, log failures via print_warn instead of silencing (fixes #4) - Fix agent-deploy.sh: pass explicit PLANS_FILE/ARCHIVE_FILE/TODO_FILE env vars so plans_cleanup targets the repo dir, not cwd; use deployed copy of script from target_dir (fixes #5) - Fix setup.sh: gate standalone archive confirm_step to only run when deploy_aidevops_agents was skipped; deploy already runs cleanup internally, so running it again would be a double-run (fixes #6) - Fix PLANS.md: change 'MERGED' to 'CLOSED' for issue references in Issues summary line (fixes #7) --------- Co-authored-by: Rob M <robi@MacBookPro.attlocal.net> Co-authored-by: marcusquinn <6428977+marcusquinn@users.noreply.github.com>
The model was skipping or hardcoding the gh-signature-helper.sh footer when composing gh issue comment/create/pr create calls directly. The existing instruction at line 188 was correct but buried in prose. Added a numbered procedural checkpoint (#7) in the Error Prevention section — same pattern as the other 'before X, do Y' rules — making it a two-step procedure that's harder to skip. Renumbered prompt injection from #7 to #8 under Security Rules.
…cement The signature footer instruction was buried in build.txt prose and the model was skipping or hardcoding it when composing gh commands directly. - Move full signature footer procedure from build.txt to AGENTS.md 'GitHub Comment Signature Footer' section (operational, not strategic) - Two-step procedure: generate with helper, append to body — every time - build.txt retains a one-line pointer to AGENTS.md - Restore Error Prevention numbering (prompt injection back to #7)
- extract.py: new extract_instruction_candidates() pass with conservative detection (high precision over recall). Filters task-specific directions (file refs, PR refs, one-off commands). Scores by signal pattern count and infers target file (build.txt vs AGENTS.md) from content keywords. - compress.py: new compress_instruction_candidates() deduplicates and groups by target file, ranked by confidence. Adds instruction_candidates key to compressed_signals.json output. - session-miner-pulse.sh: generate_summary() and generate_feedback_actions() now include an 'Instruction Candidates' section when candidates are found. - signal-mining.md: adds source #7 instruction-to-save with detection criteria, finding format, bash query examples, and filtering key. Closes #16896
- extract.py: new extract_instruction_candidates() pass with conservative detection (high precision over recall). Filters task-specific directions (file refs, PR refs, one-off commands). Scores by signal pattern count and infers target file (build.txt vs AGENTS.md) from content keywords. - compress.py: new compress_instruction_candidates() deduplicates and groups by target file, ranked by confidence. Adds instruction_candidates key to compressed_signals.json output. - session-miner-pulse.sh: generate_summary() and generate_feedback_actions() now include an 'Instruction Candidates' section when candidates are found. - signal-mining.md: adds source #7 instruction-to-save with detection criteria, finding format, bash query examples, and filtering key. Closes #16896



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.