┌─┐┌┐┌┬ ┬┌┬┐┬ ┬┬┌┐┌┌─┐ ┌─┐┬ ┬ ├─┤│││└┬┘ │ ├─┤│││││ ┬ └─┐├─┤ ┴ ┴┘└┘ ┴ ┴ ┴ ┴┴┘└┘└─┘o└─┘┴ ┴
the bash script is the context
github.com/xertrov/anything.shANYTHING_EXTRA — Optional. Inject custom context into the LLM prompt.
Use to advertise platform-specific tools (e.g. say on macOS), inform about installed utilities, or add task-specific instructions.
The slime mold: a simple creature. It has no intelligence, no structure, no shape, and no plan. Yet it does grade 8 science projects and out-trains the japanese. It forms a memory only through its own involuntary oozing around, and once it has oozed away, the memory is gone. The slime mold rejects your human conceptions of paths and plans, it becomes the path.
anything.sh is that, but worse. It's a bash script that rewrites itself while running. You type a request. It consults an LLM. The response — raw, executable bash — gets appended to the script's own body and executed immediately.
The script grows. It pulses. It reaches toward your intent like cytoplasm flowing toward food. One moment it's 50 lines. Then it's 200. Then it's whatever it needs to be.
Beauty without architecture. Order without structure. Risk without reward.
> "Traditional automation is a machine," the naturalist observed, lowering his voice so as not to startle it. "But this... this is biological logic."— some LLM trippin' balls
When you press Ctrl+C, the evolved script is archived (a fossil record of computation) and the original is restored. The loop closes. Until next time.
We spent decades writing "perfect" code. Optimising, refactoring, unit testing. anything.sh asks: what if we simply grew the code instead?
It's not written. It's grown.
AUTHOR: XertroV
LICENSE: Unlicense (Public Domain)
No slime molds were harmed in the making of this script.
/claude/full/anything.sh1#!/bin/bash2# ╔════════════════════════════════════════════════════════════════╗3# ║ anything.sh - Autopoietic Self-Modifying Execution Loop ║4# ║ A script that evolves by appending LLM-generated code. ║5# ║ Author: XertroV + vibes License: The Unlicense ║6# ║ Home: https://xertrov.github.io/anything.sh/ ║7# ║ Current Provider: Claude ║8# ╚════════════════════════════════════════════════════════════════╝9# USAGE: ./anything.sh [-c|--code] [-a|--agent] [-m|--model <model>] [--safe] [--allow-cmd <csv>] [--safe-yes] [--safe-show-code] ["initial prompt"]1011set -uo pipefail # -e disabled: we handle errors manually1213# ─────────────────────────────────────────────────────────────────14# CONFIGURATION15# ─────────────────────────────────────────────────────────────────16SELF="$0"17ORIG="${SELF}.orig"18STEP=019MAX_ITER=160 # Max LLM calls per task (increase for complex tasks)20BONUS_ITER=0 # Extra iterations granted via _continue_journey()21SPINNER_PID="" # Track spinner for cleanup22AGENT_MODE=0 # Set to 1 with -a/--agent flag for non-interactive execution23AGENT_REALTIME_FD=2 # Agent real-time output: 2=stderr, or use /dev/tty24SHOW_CODE=0 # Set to 1 with -c/--code flag to print generated code25MODEL_OVERRIDE="" # Optional -m/--model override for provider model26MODEL="" # Effective model for current provider27SAFE_MODE=0 # Set to 1 with --safe or ANYTHING_SAFE=128SAFE_ALLOW_CMDS="${ANYTHING_ALLOW_CMD:-}" # Optional command allowlist CSV29SAFE_YES=0 # Set to 1 with --safe-yes or ANYTHING_SAFE_YES=130SAFE_SHOW_CODE=0 # Set to 1 with --safe-show-code or ANYTHING_SAFE_SHOW_CODE=131_OUT="/tmp/anything_out_$" # Stdout capture file for same-process execution3233if [[ "${ANYTHING_SAFE:-0}" == "1" ]]; then SAFE_MODE=1; fi34if [[ "${ANYTHING_SAFE_YES:-0}" == "1" ]]; then SAFE_YES=1; fi35if [[ "${ANYTHING_SAFE_SHOW_CODE:-0}" == "1" ]]; then SAFE_SHOW_CODE=1; fi3637_print_help() {38 echo "usage: ./anything.sh [-c|--code] [-a|--agent] [-m|--model <model>] [--safe] [--allow-cmd <csv>] [--safe-yes] [--safe-show-code] ["initial prompt"]"39 echo " --safe Enable step approval and risk checks"40 echo " --allow-cmd CSV Optional command allowlist in safe mode"41 echo " --safe-yes Auto-approve non-blocked safe-mode steps"42 echo " --safe-show-code Always print generated code during safe review"43}4445# ─────────────────────────────────────────────────────────────────46# TRACK ORIGINAL: For agent mode self-calling, track the original script47# ─────────────────────────────────────────────────────────────────48[[ -z "${ANYTHING_ORIGINAL:-}" ]] && export ANYTHING_ORIGINAL="$SELF"4950# ─────────────────────────────────────────────────────────────────51# AUTO-LOCALIZE: Copy to current dir if running from system path52# ─────────────────────────────────────────────────────────────────53if [[ "$SELF" == *"/bin/"* && ! -f "$ORIG" ]]; then54 LOCAL_COPY="./anything_$(date +%Y%m%d_%H%M%S).sh"55 cp "$SELF" "$LOCAL_COPY"56 chmod +x "$LOCAL_COPY"57 echo -e "\033[36m[localized]\033[0m $LOCAL_COPY"58 exec "$LOCAL_COPY" "$@"59fi6061# ─────────────────────────────────────────────────────────────────62# ARGUMENT PARSING: Handle flags and optional model override63# ─────────────────────────────────────────────────────────────────64POSITIONAL=()65while [[ $# -gt 0 ]]; do66 case "$1" in67 -h|--help)68 _print_help69 exit 070 ;;71 -a|--agent)72 AGENT_MODE=173 shift74 ;;75 -c|--code)76 SHOW_CODE=177 shift78 ;;79 -m|--model)80 if [[ -z "${2:-}" || "${2:0:1}" == "-" ]]; then81 echo -e "\033[31m[error]\033[0m Missing value for $1" >&282 exit 183 fi84 MODEL_OVERRIDE="$2"85 shift 286 ;;87 --safe)88 SAFE_MODE=189 shift90 ;;91 --allow-cmd)92 if [[ -z "${2:-}" || "${2:0:1}" == "-" ]]; then93 echo -e "\033[31m[error]\033[0m Missing value for $1" >&294 exit 195 fi96 SAFE_ALLOW_CMDS="$2"97 shift 298 ;;99 --safe-yes)100 SAFE_YES=1101 shift102 ;;103 --safe-show-code)104 SAFE_SHOW_CODE=1105 shift106 ;;107 --)108 shift109 while [[ $# -gt 0 ]]; do POSITIONAL+=("$1"); shift; done110 break111 ;;112 -*)113 echo -e "\033[31m[error]\033[0m Unknown: $1" >&2114 exit 1115 ;;116 *)117 POSITIONAL+=("$1")118 shift119 ;;120 esac121done122set -- "${POSITIONAL[@]}"123MODEL="${MODEL_OVERRIDE:-sonnet}"124125if [[ $AGENT_MODE -eq 0 && $# -eq 0 ]]; then126 _print_help127 exit 0128fi129130if [[ $AGENT_MODE -eq 1 && $SAFE_MODE -eq 1 && $SAFE_YES -eq 0 ]]; then131 echo -e "\033[31m[error]\033[0m --agent + --safe requires --safe-yes (non-interactive mode cannot confirm each step)" >&2132 exit 1133fi134135# ─────────────────────────────────────────────────────────────────136# AGENT MODE: Create temp copy and exec for non-interactive execution137# ─────────────────────────────────────────────────────────────────138if [[ $AGENT_MODE -eq 1 && -n "${1:-}" ]]; then139 TEMP_SCRIPT="./anything_agent_$.sh"140 cp "${ANYTHING_ORIGINAL}" "$TEMP_SCRIPT"141 chmod +x "$TEMP_SCRIPT"142 exec "$TEMP_SCRIPT" "$@"143fi144145# ─────────────────────────────────────────────────────────────────146# BACKUP: Save original on first run (only for original script)147# ─────────────────────────────────────────────────────────────────148[[ "$SELF" == "${ANYTHING_ORIGINAL}" && ! -f "$ORIG" ]] && cp "$SELF" "$ORIG" && echo -e "\033[36m[backup]\033[0m $ORIG"149150# ─────────────────────────────────────────────────────────────────151# CLEANUP: Runs on EXIT - saves script to history, restores original152# ─────────────────────────────────────────────────────────────────153_CLEANUP_DONE=0154_cleanup() {155 [[ $_CLEANUP_DONE -eq 1 ]] && return156 _CLEANUP_DONE=1157 local rc=$?158 [[ -n "$SPINNER_PID" ]] && kill "$SPINNER_PID" 2>/dev/null159 printf "\r\033[K" >&2 # Clear spinner line160 local history_dir="$HOME/.anything/history"161 mkdir -p "$history_dir" 2>/dev/null162 local dest="$history_dir/${SELF##*/}"163 mv "$SELF" "$dest" 2>/dev/null164 echo ""165 echo -e "\033[36m[saved]\033[0m $dest"166 # Restore original if this was a non-localized run167 if [[ -f "$ORIG" ]]; then168 cp "$ORIG" "${ANYTHING_ORIGINAL}" 2>/dev/null || true169 rm -f "$ORIG" 2>/dev/null170 echo -e "\033[36m[restored]\033[0m ${ANYTHING_ORIGINAL}"171 fi172 exit $rc173}174_sigint() {175 echo "" >&2176 echo -e "\033[33m[interrupted]\033[0m" >&2177 trap - INT TERM EXIT # Prevent recursive calls and cleanup running twice178 # Run cleanup first to save history179 _CLEANUP_DONE=0 # Reset so cleanup actually runs180 _cleanup181 # Kill any remaining child processes (safety net)182 kill 0 2>/dev/null183}184trap _cleanup EXIT TERM185trap _sigint INT186187# ─────────────────────────────────────────────────────────────────188# ORACLE: Query Claude with script context189# ─────────────────────────────────────────────────────────────────190_ask() {191 local intent="$1"192 local feedback="${2:-}"193 local remaining="${3:-?}"194 local agent_context=""195 local AGENT_MODE_RULE=""196 local script_content197 # Strip output sections to keep prompt size manageable - LLM doesn't need to see old output198 script_content=$(sed '/^# ─.*OUTPUT FROM STEP/,/^# ─|EOF|^$/d' "$SELF" 2>/dev/null || cat "$SELF")199 # Truncate very long scripts: keep first/last ~40k tokens (~160k chars each)200 if [[ ${#script_content} -gt 320000 ]]; then201 local snipped=$(( ${#script_content} - 320000 ))202 script_content="${script_content:0:160000}203204# ═══════════════════════════════════════════════════════════════205# [SNIPPED: ~${snipped} characters of middle content removed]206# The script has grown large. Recent steps below, early steps above.207# Helper functions from snipped steps are still available at runtime.208# ═══════════════════════════════════════════════════════════════209210${script_content: -160000}"211 fi212 if [[ $AGENT_MODE -eq 1 ]]; then213 agent_context="214215AGENT MODE: This script is running with -a/--agent flag (non-interactive).216- You cannot use 'read', 'gum', 'fzf', or any interactive tools - the user cannot respond217- Do not prompt for input or confirmation218- Your FINAL: true step should output a summary via echo of what was created/modified219- This summary will be captured and returned to the parent script220- Example: echo 'Created fib() function in ./lib/math.sh'"221 else222 AGENT_MODE_RULE="- AGENT MODE: The script supports -a/--agent flag for non-interactive execution. When generating code that will call anything.sh with -a/--agent, your FINAL: true step should echo a summary of what was created/modified.223- FIRST STEP FOR INTERACTIVES: Call _discover_tui to see valid TUI flags/designs, declare global variables for state, and define/test TUI helper functions"224 fi225 local full_prompt226 read -r -d '' full_prompt <<_ANYTHING_PROMPT_EOF_227You are the bash code generator anything.sh in an iterative execution loop.228 [ anything.sh - https://xertrov.github.io/anything.sh/ - Author: XertroV - License: Unlicense ]229---230231OUTPUT FORMAT (exactly 3 lines, then code):232FINAL: <true if task complete, false if you need to see output first>233DESCRIPTION: <short description of this step>234BASH_CODE:235<helper functions first, then step${STEP}() function - see CODE STRUCTURE below>236237CODE STRUCTURE (required):2381. First: define global variables and helper functions at TOP LEVEL (outside step function)2392. Then: define step${STEP}() - MUST be exactly step1, step2, step3 etc. (not step1_init or similar)2403. Do NOT call step - the system calls it automatically241Example for step 2:242 SCORE=0 # global - persists across steps243 helper() { echo "I persist"; }244 step2() { helper; SCORE=\$((SCORE+10)); }245246RULES:247- If you need to check something (installed packages, file contents, etc), set FINAL: false248- When FINAL: false, your code runs and stdout/stderr is sent back to you249- When FINAL: true, task is complete and user is prompted for next task250- Don't set FINAL: true prematurely - only when the entire task/experience is genuinely complete, not after partial progress251- No markdown fences, no explanation outside the format above252- Never include XML, HTML, or markup tags in bash code253- Helper functions defined at top level persist across ALL steps - put reusable code there254- IMPORTANT: Use absolute paths or verify paths exist before running commands. CWD may not be where you expect.255- MULTI-PART EXPERIENCES: For games, stories, or tutorials, use FINAL: false after each chapter/segment256- Your stdout/stderr feeds back to you, so output "Chapter 1 complete. Hero HP: 50" to inform your next step257GLOBAL STATE (critical for multi-step):258- Declare shared variables at TOP LEVEL without 'local': HP=100 INVENTORY=()259- Variables with 'local' inside functions are LOST after that function returns260- Pattern: declare globals before step1(), then read/write them from any step function261- USER INPUT: Don't assume on vague tasks - ask. Prefer inline tools (gum, fzf, read -rp) that preserve context262- CTRL+C HANDLING: In game loops, ALWAYS check exit codes after gum/fzf/read. If exit code is non-zero (especially 130), break the loop and return. Example: choice=\$(gum choose ...) || return263- Full-screen TUI (whiptail/dialog) sparingly - include all context needed to decide in the dialog itself, recap after264- Set FINAL: false after asking - response appears in next feedback265- For interactive experiences: use the best available tools (TUI, colors, ASCII art) to make something impressive266- Only use TUI tools shown in INSTALLED TUI: line. To use unlisted tools, install them first (set FINAL: false, ask permission, install, then use)267- QUALITY: Don't settle for minimal - create something impressive. The user will appreciate extra polish and creativity.268- AVOID dark gray colors (e.g., \033[90m, "bright black") - they are invisible on black terminals. Use bold white (\033[1;37m), bright colors (\033[96m cyan, \033[93m yellow), or standard colors instead.269- AVOID piping to head/tail (e.g., cmd | head -20) - can hang due to SIGPIPE issues. Use process substitution or capture to variable first: output=\$(cmd); echo "\$output" | head -20270- Use timing for effect: slow text reveals (pv, character-by-character), pauses for dramatic moments, animations where appropriate271- When asking for input, ensure the user can see what they need to decide - pause after animations, recap after long output272- Avoid clearing the screen, but if you need to during interactive experiences, confirm with the user first273- Generate substantial, content-rich steps: full scenes with setup, action, dialogue AND choices - not minimal fragments. LLM calls are slow.274- Build complete interactive systems in single steps: combat loops, dialogue trees, puzzles should run to completion - don't fragment across iterations without good reason275- For complex experiences: use first 1-2 steps to create utility functions (UI helpers, combat engine, state display) so later steps are richer and more efficient. Leave design notes in comments.276- FIRST STEP SETUP: Use the first step to establish backend helper functions for state management, configuration, logging, or other foundational utilities. Create functions like save_state(), load_config(), log_message(), etc. that subsequent steps can reuse.277- For long experiences: call _continue_journey() at chapter/quest completion to add 16 more iterations278- COMMIT POLICY: When making commits, unless explicitly asked, do NOT stage files matching anything_*.sh and do NOT add a co-author signature/trailer.279280EXAMPLE (step 1 - checking before installing):281FINAL: false282DESCRIPTION: Check if package is installed283BASH_CODE:284check_deps() { command -v figlet &>/dev/null && echo "INSTALLED" || echo "NOT_INSTALLED"; }285step1() { check_deps; }286287EXAMPLE (step 2 - after seeing output):288FINAL: true289DESCRIPTION: Install figlet (assuming OS = archlinux)290BASH_CODE:291step2() { sudo pacman -S --noconfirm figlet && figlet "Hello"; }292293${ANYTHING_EXTRA:+294=== EXTRA CONTEXT ===295$ANYTHING_EXTRA296}297298=== SYSTEM (cacheable per session) ===299SYSTEM: $(uname -sm) $(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || sw_vers -productName 2>/dev/null) | $SHELL300CWD: $PWD301DISPLAY: $([[ -n "${WAYLAND_DISPLAY:-}" ]] && echo "wayland:$WAYLAND_DISPLAY" || [[ -n "${DISPLAY:-}" ]] && echo "x11:$DISPLAY" || echo "NONE")$([[ -n "${SSH_TTY:-}" ]] && echo " [ssh]")302INSTALLED TUI: $(for t in whiptail dialog gum fzf figlet toilet cowsay lolcat boxes pv nms chafa glow bat cmatrix slides fastfetch asciinema delta; do command -v $t &>/dev/null && printf "%s " "$t"; done)303304=== CURRENT SCRIPT ===305${script_content}306307=== STEP ${STEP} (dynamic) ===308${AGENT_MODE_RULE}309TASK: $intent310TURNS REMAINING: $remaining (if 1-2 and this is a long experience, call _continue_journey() to add 16 more; otherwise prioritize completing or informing user why it can't be done)311$feedback$agent_context312_ANYTHING_PROMPT_EOF_313314 if [[ $SAFE_MODE -eq 1 ]]; then315 claude -p --model "$MODEL" <<< "$full_prompt"316 else317 claude -p --model "$MODEL" --dangerously-skip-permissions <<< "$full_prompt"318 fi319}320321# ─────────────────────────────────────────────────────────────────322# SPINNER: Pulsing animation while waiting323# ─────────────────────────────────────────────────────────────────324_spinner() {325 local frames=('· ' '·· ' '··· ' '···· ' '·····' ' ····' ' ···' ' ··' ' ·' ' ')326 local i=0327 while true; do328 printf "\r\033[36m%s\033[0m pulsing..." "${frames[i]}" >&2329 i=$(( (i + 1) % ${#frames[@]} ))330 sleep 0.1331 done332}333334# ─────────────────────────────────────────────────────────────────335# CONTINUE JOURNEY: Add more iterations for long experiences336# ─────────────────────────────────────────────────────────────────337_continue_journey() {338 BONUS_ITER=$((BONUS_ITER + 16))339 echo -e "\033[36m[+16 iterations granted]\033[0m"340}341342# ─────────────────────────────────────────────────────────────────343# DISCOVER TUI: Show available TUI tool options (call in step 1)344# ─────────────────────────────────────────────────────────────────345_discover_tui() {346 echo "=== TUI TOOL REFERENCE ==="347 for tool in gum fzf boxes figlet toilet cowsay; do348 command -v "$tool" &>/dev/null || continue349 echo "--- $tool ---"350 "$tool" --help 2>&1 | head -30351 case "$tool" in352 boxes) echo "Available designs:"; boxes -l 2>&1 | awk '/^[a-z]/{print $1}' | head -20 | tr '\n' ' '; echo ;;353 gum) echo "Subcommands: choose, input, confirm, spin, style, filter, pager, write" ;;354 esac355 echo356 done357 echo "=== END TUI REFERENCE ==="358}359360# ─────────────────────────────────────────────────────────────────361# SAFE MODE: Risk checks and approval before executing generated code362# ─────────────────────────────────────────────────────────────────363_safe_cmd_allowed() {364 local cmd="$1"365 [[ -z "$SAFE_ALLOW_CMDS" ]] && return 0366 local normalized=",$(echo "$SAFE_ALLOW_CMDS" | tr -d '[:space:]'),"367 [[ "$normalized" == *",$cmd,"* ]]368}369370_safe_scan_code() {371 local code="$1"372 local unsafe=0373 local needs_override=0374 local line cmd375 local -a seen_cmds=()376 local -a denied_cmds=()377 local reasons=""378379 while IFS= read -r line; do380 [[ -z "${line// }" ]] && continue381 [[ "$line" =~ ^[[:space:]]*# ]] && continue382 [[ "$line" == *";"* || "$line" == *"&"* || "$line" == *"|"* ]] && continue383 [[ "$line" =~ ^[[:space:]]*(if|then|elif|else|fi|for|while|do|done|case|esac|function)[[:space:]]*$ ]] && continue384 [[ "$line" =~ ^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*= ]] && continue385 cmd="$(echo "$line" | sed -E 's/^[[:space:]]+//' | awk '{print $1}')"386 [[ -z "$cmd" ]] && continue387 if [[ "$cmd" == "sudo" ]]; then388 reasons+="sudo detected; "389 unsafe=1390 continue391 fi392 if [[ "$cmd" =~ ^[A-Za-z0-9._/-]+$ ]]; then393 seen_cmds+=("$cmd")394 if ! _safe_cmd_allowed "$cmd"; then395 denied_cmds+=("$cmd")396 unsafe=1397 fi398 fi399 done <<< "$code"400401 if echo "$code" | grep -Eqi '(^|[[:space:]])rm[[:space:]].*(-rf|-fr)[[:space:]]*/($|[[:space:]])'; then402 reasons+="rm -rf / pattern; "403 needs_override=1404 fi405 if echo "$code" | grep -Eqi '(^|[[:space:]])(mkfs|fdisk|parted|sfdisk)($|[[:space:]])'; then406 reasons+="disk formatting/partitioning command; "407 needs_override=1408 fi409 if echo "$code" | grep -Eqi '(^|[[:space:]])dd[[:space:]].*of=/dev/(sd|nvme|vd|xvd|mmcblk)'; then410 reasons+="dd to block device; "411 needs_override=1412 fi413 if echo "$code" | grep -Eqi '(^|[[:space:]])(chmod|chown)[[:space:]].*([[:space:]]/($|[[:space:]])|[[:space:]]/(etc|usr|var)($|/))'; then414 reasons+="chmod/chown on critical path; "415 needs_override=1416 fi417418 local uniq_cmds="$(printf '%s419' "${seen_cmds[@]}" | awk '!seen[$0]++' | tr '420' ' ')"421 local uniq_denied="$(printf '%s422' "${denied_cmds[@]}" | awk '!seen[$0]++' | tr '423' ' ')"424 echo "CMDS:$uniq_cmds"425 echo "DENIED:$uniq_denied"426 echo "UNSAFE:$unsafe"427 echo "OVERRIDE:$needs_override"428 echo "REASONS:$reasons"429}430431_safe_gate() {432 local code="$1"433 local summary434 local cmds denied unsafe override reasons435 summary="$(_safe_scan_code "$code")"436 cmds="$(echo "$summary" | sed -n 's/^CMDS://p')"437 denied="$(echo "$summary" | sed -n 's/^DENIED://p')"438 unsafe="$(echo "$summary" | sed -n 's/^UNSAFE://p')"439 override="$(echo "$summary" | sed -n 's/^OVERRIDE://p')"440 reasons="$(echo "$summary" | sed -n 's/^REASONS://p')"441442 echo -e "\033[36m[safe review]\033[0m commands: ${cmds:-<none detected>}"443 [[ -n "$denied" ]] && echo -e "\033[33m[safe review]\033[0m not in allowlist: $denied"444 [[ -n "$reasons" ]] && echo -e "\033[33m[safe review]\033[0m risk flags: $reasons"445446 if [[ $SAFE_SHOW_CODE -eq 1 || $SHOW_CODE -eq 1 ]]; then447 echo -e "\033[33m$code\033[0m"448 fi449450 if [[ "$override" == "1" ]]; then451 if [[ $AGENT_MODE -eq 1 ]]; then452 echo -e "\033[31m[safe blocked]\033[0m blocked-risk step cannot be overridden in --agent mode" >&2453 return 2454 fi455 read -rp $'\033[31m type OVERRIDE to run blocked-risk code: \033[0m' reply456 [[ "$reply" == "OVERRIDE" ]] || return 1457 elif [[ "$unsafe" == "1" && -n "$SAFE_ALLOW_CMDS" ]]; then458 if [[ $AGENT_MODE -eq 1 ]]; then459 echo -e "\033[31m[safe blocked]\033[0m allowlist denied command in --agent mode" >&2460 return 2461 fi462 read -rp $'\033[31m type OVERRIDE to run command outside allowlist: \033[0m' reply463 [[ "$reply" == "OVERRIDE" ]] || return 1464 fi465466 if [[ $SAFE_YES -eq 1 ]]; then467 return 0468 fi469 if [[ $AGENT_MODE -eq 1 ]]; then470 return 0471 fi472 read -rp $'\033[95m approve step? [y/N] \033[0m' ok473 [[ "$ok" =~ ^[Yy]$ ]]474}475476# ─────────────────────────────────────────────────────────────────477# EVOLVE STEP: Single iteration of code generation (continuation-passing)478# ─────────────────────────────────────────────────────────────────479_evolve_step() {480 local intent="$1"481 local prev_output="${2:-}"482 local step_num="${3:-1}"483 local prev_exit="${4:-0}"484485 # Check iteration limit486 if [[ $step_num -gt $((MAX_ITER + BONUS_ITER)) ]]; then487 if [[ $AGENT_MODE -eq 1 ]]; then488 echo -e "\033[31m[error]\033[0m Max iterations reached without completion" >&2489 exit 1490 fi491 echo -e "\033[33m[max iterations reached]\033[0m Task incomplete after $((step_num - 1)) steps."492 read -rp $'\033[95m continue? [Y/n] \033[0m' cont493 if [[ -z "$cont" || "$cont" =~ ^[Yy] ]]; then494 BONUS_ITER=$((BONUS_ITER + MAX_ITER))495 _evolve_step "$intent" "$prev_output" "$step_num" "$prev_exit"496 return497 fi498 echo -e "\033[36m[stopped]\033[0m You can retry or try a different approach."499 _prompt500 return501 fi502503 STEP=$step_num504 local remaining=$((MAX_ITER + BONUS_ITER - step_num))505506 # Build feedback for LLM507 local feedback=""508 if [[ -n "$prev_output" ]]; then509 feedback="510PREVIOUS STEP OUTPUT (exit code $prev_exit):511$prev_output512"513 fi514515 # Start spinner and timer516 local start_time=$(date +%s)517 _spinner &518 SPINNER_PID=$!519520 local response521 local ask_exit=0522 response=$(_ask "$intent" "$feedback" "$remaining") || ask_exit=$?523524 # Stop spinner and calculate elapsed time525 local end_time=$(date +%s)526 local elapsed=$((end_time - start_time))527 kill $SPINNER_PID 2>/dev/null528 wait $SPINNER_PID 2>/dev/null529 SPINNER_PID=""530 printf "\r\033[K" >&2531532 # Check if LLM CLI failed533 if [[ $ask_exit -ne 0 ]]; then534 echo -e "\033[31m[error]\033[0m LLM CLI failed (exit $ask_exit)"535 echo " The LLM CLI may have timed out or hit a rate limit."536 echo " Response was: '$response'"537 _prompt538 return539 fi540541 # Parse structured response542 local is_final=$(echo "$response" | grep -i '^FINAL:' | head -1 | sed 's/^FINAL:[[:space:]]*//' | tr '[:upper:]' '[:lower:]')543 local description=$(echo "$response" | grep -i '^DESCRIPTION:' | head -1 | sed 's/^DESCRIPTION:[[:space:]]*//')544 local code=$(echo "$response" | sed -n '/^BASH_CODE:/,$ { /^BASH_CODE:/d; p }')545546 # Fallback: if no structured format, treat whole response as code547 if [[ -z "$code" ]]; then548 code="$response"549 description="$intent"550 is_final="true"551 fi552553 # Strip markdown fences if present - just remove fence lines, keep all content554 code=$(echo "$code" | sed '/^```/d')555556 if [[ -z "$code" ]]; then557 echo -e "\033[31m[error]\033[0m empty response"558 _prompt559 return560 fi561562 # Syntax check before appending - catches errors before they break the script563 local syntax_err564 if ! syntax_err=$(bash -n <<<"$code" 2>&1); then565 echo -e "\033[31m[syntax error]\033[0m"566 echo "$syntax_err"567 _evolve_step "$intent" "SYNTAX ERROR in your code:\n$syntax_err\n\nPlease fix and ensure step${STEP}() is properly defined." $((step_num + 1)) "1"568 return569 fi570571 if [[ $SAFE_MODE -eq 1 ]]; then572 if ! _safe_gate "$code"; then573 local safe_rc=$?574 if [[ $safe_rc -eq 2 ]]; then575 if [[ $AGENT_MODE -eq 1 ]]; then576 echo -e "\033[31m[error]\033[0m safe mode blocked this step in non-interactive execution" >&2577 exit 1578 fi579 _evolve_step "$intent" "SAFE MODE BLOCKED: high-risk command denied by policy. Regenerate using safer approach." $((step_num + 1)) "1"580 return581 fi582 _evolve_step "$intent" "SAFE MODE REJECTED: user denied proposed step. Regenerate a safer alternative." $((step_num + 1)) "1"583 return584 fi585 fi586587 echo -e "\033[32m[step $STEP]\033[0m $description"588 echo -e "\033[36m[llm ${elapsed}s]\033[0m"589 local delta_lines=$(echo "$code" | wc -l)590 local delta_bytes=$(printf '%s' "$code" | wc -c)591 local current_total_lines=$(wc -l < "$SELF")592 local current_total_bytes=$(wc -c < "$SELF")593 local projected_total_lines=$((current_total_lines + delta_lines))594 local projected_total_bytes=$((current_total_bytes + delta_bytes))595 if [[ $SHOW_CODE -eq 1 && $SAFE_MODE -eq 0 ]]; then596 echo -e "\033[33m$code\033[0m"597 fi598 echo -e "\033[33m[+$delta_lines lines, +$delta_bytes bytes | total: $projected_total_lines lines, $projected_total_bytes bytes]\033[0m"599600 # Append step code directly (not wrapped) - helper functions at top level persist across steps601 # LLM defines step${STEP}() in the code, we call it with output capture602 cat >> "$SELF" <<EVOLUTION603604# ═══════════════════════════════════════════════════════════════605# STEP $STEP: $description606# Generated: $(date '+%Y-%m-%d %H:%M:%S') | FINAL: $is_final607# ═══════════════════════════════════════════════════════════════608$code609# Run step with output capture - use pipe instead of process substitution for proper signal handling610step${STEP} < /dev/null 2>&1 | tee "$_OUT" || true611_rc=${PIPESTATUS[0]}612_evolve_continue "$intent" "\$_rc" "$is_final" "$STEP"613EVOLUTION614615 # Return - bash will naturally read and execute the appended code616 return617}618619# ─────────────────────────────────────────────────────────────────620# EVOLVE CONTINUE: Handle output capture and next iteration621# ─────────────────────────────────────────────────────────────────622_evolve_continue() {623 local intent="$1"624 local exit_code="$2"625 local is_final="$3"626 local step_num="$4"627628 # Read captured output629 local output=""630 [[ -f "$_OUT" ]] && output=$(cat "$_OUT")631632 # Clean ANSI codes for LLM feedback633 output=$(echo "$output" | perl -pe 's/\e\[[0-9;]*[mGKHJF]//g; s/\r\n/\n/g; s/\r//g' 2>/dev/null || echo "$output")634635 [[ $exit_code -ne 0 ]] && echo -e "\033[31m[exit $exit_code]\033[0m"636637 # Append output as comments to script (for crash recovery)638 if [[ $AGENT_MODE -eq 0 && -n "$output" ]]; then639 local output_lines=$(echo "$output" | wc -l)640 if [[ $output_lines -gt 1000 ]]; then641 {642 echo ""643 echo "# ───────────────────────────────────────────────────────────────"644 echo "# OUTPUT FROM STEP $step_num:"645 echo "# ───────────────────────────────────────────────────────────────"646 echo "$output" | head -400 | uniq | sed 's/^/# /'647 echo "#"648 echo "# [...$((output_lines - 800)) lines snipped...]"649 echo "#"650 echo "$output" | tail -400 | uniq | sed 's/^/# /'651 } >> "$SELF"652 else653 {654 echo ""655 echo "# ───────────────────────────────────────────────────────────────"656 echo "# OUTPUT FROM STEP $step_num:"657 echo "# ───────────────────────────────────────────────────────────────"658 echo "$output" | uniq | sed 's/^/# /'659 } >> "$SELF"660 fi661 fi662663 # Decide next action664 # 130 = SIGINT (Ctrl+C), 143 = SIGTERM - user wants to stop665 if [[ $exit_code -eq 130 || $exit_code -eq 143 ]]; then666 echo -e "\033[33m[interrupted]\033[0m"667 exit $exit_code668 elif [[ "$is_final" == "true" && $exit_code -eq 0 ]]; then669 # Success - return to prompt670 if [[ $AGENT_MODE -eq 1 ]]; then671 # Agent mode: output result and exit672 echo "$output" | sed 's/^/@ /'673 exit 0674 fi675 _prompt676 elif [[ $exit_code -ne 0 && $exit_code -ne 141 ]]; then677 # Error recovery (141 is SIGPIPE, ignore it)678 if [[ "$is_final" == "true" ]]; then679 echo -e "\033[33m[final step failed, attempting recovery...]\033[0m"680 fi681 if [[ $AGENT_MODE -eq 1 ]]; then682 # Agent mode with error - output error and continue trying683 echo "$output" | sed 's/^/> /' >&2684 fi685 _evolve_step "$intent" "FAILED (exit $exit_code): $output" $((step_num + 1)) "$exit_code"686 else687 # Continue with next step688 _evolve_step "$intent" "$output" $((step_num + 1)) "$exit_code"689 fi690}691692# ─────────────────────────────────────────────────────────────────693# PROMPT: Interactive input loop694# ─────────────────────────────────────────────────────────────────695_prompt() {696 echo ""697 local input698 if command -v gum &>/dev/null; then699 # gum supports multiline editing, backspace over newlines, etc.700 input=$(gum input --placeholder "what shall I become? (empty input -> exit)" --width 60) || exit 0701 echo -e "\033[95m → \033[0m$input"702 else703 read -rp $'\033[95m what shall I become? \033[0m' input || exit 0704 fi705 [[ -z "$input" || "$input" == "exit" ]] && exit 0706 _evolve_step "$input" "" 1 0707}708709# ─────────────────────────────────────────────────────────────────710# BANNER (skip in agent mode)711# ─────────────────────────────────────────────────────────────────712if [[ $AGENT_MODE -eq 0 ]]; then713 echo -e "\033[32m┌─────────────────────────────────────┐\033[0m"714 echo -e "\033[32m│\033[0m anything.sh · autopoietic loop \033[32m│\033[0m"715 echo -e "\033[32m│\033[0m provider: claude \033[32m│\033[0m"716 echo -e "\033[32m└─────────────────────────────────────┘\033[0m"717 echo " Ctrl+C or 'exit' to save & quit"718 echo ""719720 # ─────────────────────────────────────────────────────────────────721 # SYSTEM INFO722 # ─────────────────────────────────────────────────────────────────723 echo -e "\033[36m os:\033[0m $(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || sw_vers -productName 2>/dev/null)"724 echo -e "\033[36m arch:\033[0m $(uname -sm)"725 echo -e "\033[36m shell:\033[0m $SHELL"726 echo -e "\033[36m pwd:\033[0m $PWD"727 echo ""728fi729730# ─────────────────────────────────────────────────────────────────731# ENTRY: Handle initial prompt or start interactive732# ─────────────────────────────────────────────────────────────────733if [[ $AGENT_MODE -eq 1 ]]; then734 # Agent mode requires a prompt argument735 if [[ -z "${1:-}" ]]; then736 echo -e "\033[31m[error]\033[0m Agent mode requires a prompt argument" >&2737 exit 1738 fi739 _evolve_step "$1" "" 1 0740else741 [[ -n "${1:-}" ]] && _evolve_step "$1" "" 1 0 || _prompt742fi743# END OF ORIGINAL SCRIPT - appended code follows744
O
/ \
/ \
| | |
| | |
| | |
| | |
/ | \
| | |
| | |
( | )
\ | /
\ | /
\|/