Created
May 14, 2026 19:30
-
-
Save chrisregner/dab44c1ee367b3e84daee90da7ed06f4 to your computer and use it in GitHub Desktop.
Claude Code CLI Wrapper to allow auto start new session with next prompt when printing <<<LOOP_RESTART prompt-here>>>
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
| #!/usr/bin/env bash | |
| set -u | |
| set -o pipefail | |
| # Force C locale so ASCII byte ranges in regexes ([@-~] etc.) behave. | |
| export LC_ALL=C | |
| raw_file="${TMPDIR:-/tmp}/claude-loop.$$.raw" | |
| payload_file="${TMPDIR:-/tmp}/claude-loop.$$.payload" | |
| trap 'rm -f "$raw_file" "$payload_file"' EXIT | |
| max_iters=50 | |
| iter=0 | |
| keep_raw=0 | |
| claude_flags=() | |
| next_cmd="" | |
| pty_helper="$(dirname "$(readlink -f "$0")")/claude-loop-pty" | |
| if [[ ! -x "$pty_helper" ]]; then | |
| printf '[claude-loop] missing helper: %s\n' "$pty_helper" >&2 | |
| exit 3 | |
| fi | |
| for arg in "$@"; do | |
| if [[ "$arg" == "--keep-raw" ]]; then | |
| keep_raw=1 | |
| elif [[ "$arg" == -* ]]; then | |
| claude_flags+=("$arg") | |
| elif [[ -z "$next_cmd" ]]; then | |
| next_cmd="$arg" | |
| else | |
| printf '[claude-loop] unexpected extra positional arg: %s\n' "$arg" >&2 | |
| exit 2 | |
| fi | |
| done | |
| export CLAUDE_LOOP_RAW="$raw_file" | |
| export CLAUDE_LOOP_PAYLOAD_OUT="$payload_file" | |
| while (( iter < max_iters )); do | |
| (( iter++ )) | |
| rm -f "$raw_file" "$payload_file" | |
| cmd=(claude "${claude_flags[@]}") | |
| if [[ -n "$next_cmd" ]]; then | |
| cmd+=(-- "$next_cmd") | |
| fi | |
| printf '[claude-loop] (%d/%d) launching: %s\n' \ | |
| "$iter" "$max_iters" "${cmd[*]}" | |
| "$pty_helper" "${cmd[@]}" | |
| rc=$? | |
| if (( keep_raw )); then | |
| debug_path="${TMPDIR:-/tmp}/claude-loop.debug.$$.iter${iter}.raw" | |
| cp "$raw_file" "$debug_path" 2>/dev/null && \ | |
| printf '[claude-loop] kept raw transcript: %s\n' "$debug_path" >&2 | |
| fi | |
| # Recover terminal state (TUI + nested PTYs sometimes leave it weird). | |
| stty sane 2>/dev/null || true | |
| printf '\033[?1049l\033[?25h\033[?2004l\033[?1000l\033[?1002l\033[?1003l\033[?1006l' | |
| if (( rc == 42 )) && [[ -s "$payload_file" ]]; then | |
| next_cmd=$(cat "$payload_file") | |
| printf '\n[claude-loop] trigger detected, restarting with: %s\n\n' "$next_cmd" | |
| else | |
| printf '\n[claude-loop] claude exited without a trigger (rc=%d), stopping.\n' "$rc" | |
| exit 0 | |
| fi | |
| done | |
| printf '\n[claude-loop] hit max_iters=%d, stopping to avoid runaway loop.\n' "$max_iters" >&2 | |
| exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment