Last active
January 22, 2026 05:28
-
-
Save fripSide/a722305eaad1b8e0c8c53cbb161193ed to your computer and use it in GitHub Desktop.
Make OpenCode work forever
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| PROCESS_NAME="opencode" | |
| BIN_PATH="/root/.opencode/bin/opencode" | |
| CHECK_INTERVAL=180 | |
| FILE_CHECK_MINUTES=10 | |
| SIGNALS_APP_DIR="3-signals-app" | |
| USER_TASK="Work now..." | |
| WORKING_PID="" | |
| # Template with placeholder that will be replaced dynamically | |
| read -r -d '' RALPH_LOOP_TEMPLATE << 'EOF' || true | |
| [search-mode] | |
| MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL: | |
| - explore agents (codebase patterns, file structures, ast-grep) | |
| - librarian agents (remote repos, official docs, GitHub examples) | |
| Plus direct tools: Grep, ripgrep (rg), ast-grep (sg) | |
| NEVER stop at first result - be exhaustive. | |
| <command-instruction> | |
| You are starting a Ralph Loop - a self-referential development loop that runs until task completion. | |
| ## How Ralph Loop Works | |
| 1. You will work on the task continuously | |
| 2. When you believe the task is FULLY complete, output: `<promise>{{COMPLETION_PROMISE}}</promise>` | |
| 3. If you don't output the promise, the loop will automatically inject another prompt to continue | |
| 4. Maximum iterations: Configurable (default 100) | |
| ## Rules | |
| - Focus on completing the task fully, not partially | |
| - Don't output the completion promise until the task is truly done | |
| - Each iteration should make meaningful progress toward the goal | |
| - If stuck, try different approaches | |
| - Use todos to track your progress | |
| ## Exit Conditions | |
| 1. **Completion**: Output `<promise>DONE</promise>` (or custom promise text) when fully complete | |
| 2. **Max Iterations**: Loop stops automatically at limit | |
| 3. **Cancel**: User runs `/cancel-ralph` command | |
| ## Your Task | |
| Parse the arguments below and begin working on the task. The format is: | |
| `"task description" [--completion-promise=TEXT] [--max-iterations=N]` | |
| Default completion promise is "DONE" and default max iterations is 100. | |
| </command-instruction> | |
| <user-task> | |
| __USER_TASK_PLACEHOLDER__ | |
| </user-task> | |
| EOF | |
| get_ralph_loop() { | |
| echo "${RALPH_LOOP_TEMPLATE//__USER_TASK_PLACEHOLDER__/$USER_TASK}" | |
| } | |
| working() { | |
| local task="Check requirements in @Plan.md @Requriements.md . Redesign the solution, and implement the requirements. \ | |
| After completing each task, git add/commit/push the code to origin master. \ | |
| Then, repeat this process without stopping until 24 hours have passed." | |
| local prompts=( | |
| "Please check if there are better implementation methods" | |
| "There are still bugs in the project, please fix them" | |
| "The current code is too complex, can you simplify it" | |
| "Are you sure all features are fully implemented? Please check again" | |
| "Please submit the code to git via commit and push" | |
| ) | |
| local random_index=$((RANDOM % ${#prompts[@]})) | |
| USER_TASK="${task} ${prompts[$random_index]}" | |
| echo "$(date): Working..." | |
| COMMAND="$(get_ralph_loop)" | |
| "$BIN_PATH" run "'$COMMAND'" &> /dev/null | |
| echo "$(date): Working completed" | |
| } | |
| kill_opencode() { | |
| echo "$(date): Killing $PROCESS_NAME..." | |
| if pkill -x "$PROCESS_NAME" 2>/dev/null; then | |
| echo "$(date): $PROCESS_NAME killed successfully" | |
| else | |
| echo "$(date): $PROCESS_NAME is not running" | |
| fi | |
| } | |
| is_working_running() { | |
| [ -n "$WORKING_PID" ] && kill -0 "$WORKING_PID" 2>/dev/null | |
| } | |
| check_recent_file_changes() { | |
| if [ ! -d "$SIGNALS_APP_DIR" ]; then | |
| return 0 | |
| fi | |
| local recent_files=$(find "$SIGNALS_APP_DIR"/ -type f -not -path "*/\.git/*" -mmin -$FILE_CHECK_MINUTES 2>/dev/null) | |
| if [ -z "$recent_files" ]; then | |
| echo "$(date): No file changes in $SIGNALS_APP_DIR/ for more than $FILE_CHECK_MINUTES minutes, restarting OpenCode..." | |
| return 1 | |
| else | |
| echo "$(date): Recent file changes detected, OpenCode is working" | |
| return 0 | |
| fi | |
| } | |
| start_working_async() { | |
| if is_working_running; then | |
| echo "$(date): Working function is already running (PID: $WORKING_PID)" | |
| return | |
| fi | |
| echo "$(date): $PROCESS_NAME is not running. Starting process..." | |
| working & | |
| WORKING_PID=$! | |
| echo "$(date): Working function started asynchronously (PID: $WORKING_PID)" | |
| } | |
| kill_opencode | |
| while true; do | |
| if pgrep -x "$PROCESS_NAME" > /dev/null; then | |
| if ! check_recent_file_changes; then | |
| kill_opencode | |
| start_working_async | |
| fi | |
| else | |
| start_working_async | |
| fi | |
| sleep $CHECK_INTERVAL | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment