[object Object]

← back to Rentv

ops: persistent (launchd) RENTV build loop — sandboxed claude -p (no deploy/spend tool, drafts gated to pending-approval), hourly, sonnet; activation is Steve-run

80e38cfee4ffe012129ad5fe607d411e8dd4e9f9 · 2026-08-05 13:52:22 -0700 · Steve Abrams

Files touched

Diff

commit 80e38cfee4ffe012129ad5fe607d411e8dd4e9f9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Aug 5 13:52:22 2026 -0700

    ops: persistent (launchd) RENTV build loop — sandboxed claude -p (no deploy/spend tool, drafts gated to pending-approval), hourly, sonnet; activation is Steve-run
---
 .gitignore                          |  2 ++
 ops/buildloop-cycle.sh              | 29 +++++++++++++++++++++++++++++
 ops/com.steve.rentv-buildloop.plist | 24 ++++++++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/.gitignore b/.gitignore
index 51d326a3..e489498b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,5 @@ data/archive-crawl-state.json
 # unified search index — large rebuildable artifact (build-search-index.mjs)
 data/search-index.jsonl
 data/search-index-meta.json
+ops/*.log
+ops/*.err
diff --git a/ops/buildloop-cycle.sh b/ops/buildloop-cycle.sh
new file mode 100755
index 00000000..c5dc1953
--- /dev/null
+++ b/ops/buildloop-cycle.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# RENTV autonomous build loop — one /yoloforever cycle, headless + SANDBOXED.
+# Installed via launchd (com.steve.rentv-buildloop) so it survives restarts.
+#
+# SAFETY MODEL: this runs `claude -p` with a RESTRICTED allowedTools set — it can
+# read/edit/write files and run git/node/npm, but it has NO tool to run deploy.sh,
+# curl, or any paid API. So it CANNOT deploy to prod or spend money; gated work is
+# structurally forced to a draft in ~/.claude/yolo-queue/pending-approval/ for Steve.
+# Stop it: launchctl bootout gui/$(id -u)/com.steve.rentv-buildloop
+set -euo pipefail
+cd "$HOME/Projects/rentv" || exit 1
+mkdir -p "$HOME/Projects/rentv/ops"
+LOG="$HOME/Projects/rentv/ops/buildloop.log"
+# Trim the log if it grows past ~5MB.
+[ -f "$LOG" ] && [ "$(wc -c <"$LOG")" -gt 5000000 ] && tail -c 2000000 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
+
+PROMPT='/yoloforever continue — autonomous build loop for the RENTV project (~/Projects/rentv, live at rentv.agentabrams.com; surfaces: pr-intelligence CRM, Content Studio, Deal Desk, /audience, /blog + front-end). STANDING OBJECTIVE: harden/extend rentv. THIS cycle pick ONE highest-value SAFE reversible item and finish it: a real bug fix, UI/UX polish, enforce Steve standing rules (admin cards show created date+time; every data point hrefs deeper; grids have sort+density; lists have adjustable/expandable columns), CA/AZ data completeness, Content Studio / Deal Desk / Boomer improvements, dedup/quality. VERIFY any claimed defect by reproducing before fixing (drop phantoms). Do reversible work directly (edit + node --check) and git commit each success (author steve@designerwallcoverings.com). YOU HAVE NO DEPLOY OR SPEND TOOL — for any gated action (prod deploy, DNS, ElevenLabs/Gemini/HeyGen spend, send-to-list, publish, remote push) WRITE a memo to ~/.claude/yolo-queue/pending-approval/ with APPROVE/REVISE/BLOCK; never attempt to run it. If nothing safe+valuable remains, write a short ops/buildloop.log note and exit. One increment per run; do not loop internally.'
+
+# `claude` is a shell function in interactive shells; launchd runs non-interactive, so pin the real binary.
+CLAUDE_BIN="$HOME/.local/bin/claude"; [ -x "$CLAUDE_BIN" ] || CLAUDE_BIN="$(command -v claude)"
+
+{
+  echo "==================== $(date '+%Y-%m-%d %H:%M:%S') cycle start ===================="
+  "$CLAUDE_BIN" -p "$PROMPT" \
+    --model sonnet \
+    --allowedTools "Read" "Edit" "Write" "Grep" "Glob" "Bash(git:*)" "Bash(node:*)" "Bash(npm:*)" \
+    2>&1 || echo "[cycle exited non-zero: $?]"
+  echo "==================== $(date '+%Y-%m-%d %H:%M:%S') cycle end ===================="
+} >> "$LOG" 2>&1
diff --git a/ops/com.steve.rentv-buildloop.plist b/ops/com.steve.rentv-buildloop.plist
new file mode 100644
index 00000000..d4ad8c57
--- /dev/null
+++ b/ops/com.steve.rentv-buildloop.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>Label</key><string>com.steve.rentv-buildloop</string>
+  <key>ProgramArguments</key>
+  <array>
+    <string>/bin/bash</string>
+    <string>/Users/macstudio3/Projects/rentv/ops/buildloop-cycle.sh</string>
+  </array>
+  <!-- Hourly at :17 (off the round marks). Does NOT fire on load. -->
+  <key>StartCalendarInterval</key>
+  <dict><key>Minute</key><integer>17</integer></dict>
+  <key>RunAtLoad</key><false/>
+  <key>ProcessType</key><string>Background</string>
+  <key>StandardOutPath</key><string>/Users/macstudio3/Projects/rentv/ops/buildloop.launchd.log</string>
+  <key>StandardErrorPath</key><string>/Users/macstudio3/Projects/rentv/ops/buildloop.launchd.err</string>
+  <key>EnvironmentVariables</key>
+  <dict>
+    <key>PATH</key><string>/Users/macstudio3/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
+    <key>HOME</key><string>/Users/macstudio3</string>
+  </dict>
+</dict>
+</plist>

← 97ad44f2 search-index: resolve psql by full path so launchd (minimal  ·  back to Rentv  ·  RENTV closings: merge article corpus into /api/closings (Sal f44b4fff →