← back to Lifestyle Asset Intel

.yolo/run-tick.sh

49 lines

#!/bin/bash
# LAI yolo tick runner — fired by launchd every 30 minutes.
# Locks via flock so overlapping fires don't race on git.
set -u

PROJ="/Users/macstudio3/Projects/lifestyle-asset-intel"
LOCK="$PROJ/.yolo/.lock"
LOG="$PROJ/.yolo/yolo-loop.log"
PROMPT="$PROJ/.yolo/tick-prompt.md"

cd "$PROJ" || { echo "[$(date -u +%FT%TZ)] cwd FAIL" >> "$LOG"; exit 2; }

# Standing rule: NEVER use Anthropic API key — Claude CLI uses Max plan only.
unset ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN

# Single-fire lock — bail if a previous tick is still running.
# macOS has no flock, so we use a mkdir-as-lock pattern (atomic on POSIX).
LOCK_DIR="$PROJ/.yolo/.lock.d"
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
  # Stale lock recovery: if the dir is older than 12 minutes (max-turns 12 +
  # margin), assume the previous tick is dead and steal the lock.
  if [ "$(find "$LOCK_DIR" -maxdepth 0 -mmin +12 2>/dev/null | wc -l)" -gt 0 ]; then
    echo "[$(date -u +%FT%TZ)] STALE lock → steal" >> "$LOG"
    rmdir "$LOCK_DIR" 2>/dev/null
    mkdir "$LOCK_DIR" || { echo "[$(date -u +%FT%TZ)] lock steal FAIL" >> "$LOG"; exit 0; }
  else
    echo "[$(date -u +%FT%TZ)] SKIP — previous tick still running" >> "$LOG"
    exit 0
  fi
fi
trap 'rmdir "$LOCK_DIR" 2>/dev/null' EXIT

START=$(date -u +%FT%TZ)
echo "[$START] tick start" >> "$LOG"

# Pipe the prompt to claude CLI, --print so it exits, --max-turns 25.
# Bumped from 12 → 25 after the 2026-05-10 08:14 fire blew its budget
# mid-implementation. 25 leaves room for (read+plan) + (do work) +
# (test+restart+commit) + (1-2 extra) without uncapped runaway.
/Users/macstudio3/.local/bin/claude --print --dangerously-skip-permissions --max-turns 25 < "$PROMPT" \
  >> "$LOG" 2>&1
EXIT=$?

END=$(date -u +%FT%TZ)
echo "[$END] tick end exit=$EXIT" >> "$LOG"
echo "---" >> "$LOG"

exit "$EXIT"