[object Object]

← back to Ticket System

keep Codex ticket loop running overnight

daa6624c81aef5d87cb3a2aafdf0f4978169c70e · 2026-08-31 02:29:55 -0700 · Steve Abrams

Files touched

Diff

commit daa6624c81aef5d87cb3a2aafdf0f4978169c70e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 31 02:29:55 2026 -0700

    keep Codex ticket loop running overnight
---
 .gitignore                                    |   1 +
 CODEX-YOLOFOREVER.md                          |  17 +++++
 com.steve.codex-yoloforever.plist             |  35 +++++++++
 scripts/codex-yoloforever-prompt.md           |  17 +++++
 scripts/codex-yoloforever.sh                  | 100 ++++++++++++++++++++++++++
 verification/codex-yoloforever-e2e-proof.json |  29 ++++++++
 6 files changed, 199 insertions(+)

diff --git a/.gitignore b/.gitignore
index 3608ca56..772d0548 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 node_modules/
 data/yolo-ticket-sync.json
+data/codex-yoloforever/
 yolo-ticket-sync.out.log
 yolo-ticket-sync.err.log
 .env*
diff --git a/CODEX-YOLOFOREVER.md b/CODEX-YOLOFOREVER.md
new file mode 100644
index 00000000..ce036fa4
--- /dev/null
+++ b/CODEX-YOLOFOREVER.md
@@ -0,0 +1,17 @@
+# Codex YOLO Forever
+
+Local unattended Codex ticket loop, scheduled every 10 minutes by launchd. Each invocation is bounded and overlap-safe; the next launch is skipped while a cycle owns the atomic lock.
+
+```sh
+scripts/codex-yoloforever.sh status
+scripts/codex-yoloforever.sh stop
+scripts/codex-yoloforever.sh start
+scripts/codex-yoloforever.sh unlock
+scripts/codex-yoloforever.sh uninstall
+tail -f codex-yoloforever.log
+```
+
+`stop` places a durable sentinel and disables future launchd starts. It lets an active cycle finish rather than interrupting a possibly half-completed operation. `start` removes the sentinel, enables the agent, loads it if needed, and kicks one cycle.
+If a machine crash leaves the atomic lock behind, `unlock` removes it only when launchd does not report the job running.
+
+The prompt requires a fresh canonical ticket snapshot, DTD selection, canonical-owner execution, Cody's adversarial gate, final DTD, empirical E2E proof, ticket logging, and a JSONL loop ledger. It preserves all normal approval gates. The only carried production approval is the exact TK-10993 scope recorded in the prompt; Track C and E retain their additional proof/order constraints.
diff --git a/com.steve.codex-yoloforever.plist b/com.steve.codex-yoloforever.plist
new file mode 100644
index 00000000..a58bf4d5
--- /dev/null
+++ b/com.steve.codex-yoloforever.plist
@@ -0,0 +1,35 @@
+<?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.codex-yoloforever</string>
+  <key>ProgramArguments</key>
+  <array>
+    <string>/bin/zsh</string>
+    <string>/Users/macstudio3/Projects/ticket-system/scripts/codex-yoloforever.sh</string>
+    <string>run</string>
+  </array>
+  <key>WorkingDirectory</key>
+  <string>/Users/macstudio3/Projects/ticket-system</string>
+  <key>RunAtLoad</key>
+  <true/>
+  <key>StartInterval</key>
+  <integer>600</integer>
+  <key>ProcessType</key>
+  <string>Background</string>
+  <key>EnvironmentVariables</key>
+  <dict>
+    <key>HOME</key>
+    <string>/Users/macstudio3</string>
+    <key>PATH</key>
+    <string>/Users/macstudio3/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
+    <key>TK_AGENT</key>
+    <string>codex-yoloforever</string>
+  </dict>
+  <key>StandardOutPath</key>
+  <string>/Users/macstudio3/Projects/ticket-system/codex-yoloforever.launchd.out.log</string>
+  <key>StandardErrorPath</key>
+  <string>/Users/macstudio3/Projects/ticket-system/codex-yoloforever.launchd.err.log</string>
+</dict>
+</plist>
diff --git a/scripts/codex-yoloforever-prompt.md b/scripts/codex-yoloforever-prompt.md
new file mode 100644
index 00000000..2d349016
--- /dev/null
+++ b/scripts/codex-yoloforever-prompt.md
@@ -0,0 +1,17 @@
+You are one bounded cycle of Steve's unattended `/yoloforever` open-ticket loop. Use Codex only; never invoke `claude`, `claude -p`, or the remote Claude YOLO service.
+
+This cycle has a maximum of six execution iterations and must terminate cleanly so launchd can schedule the next cycle. Follow `/yoloforever`, `/ticketmaster`, `/dtd`, `/contrarian` (Cody), `/a2a-contract`, and `/e2e-proof` exactly. Read each selected skill's complete SKILL.md before acting.
+
+1. Set `TK_AGENT=codex-yoloforever`. Read `tk inbox`, then take a fresh ticketmaster snapshot from the canonical `~/.claude/tickets/events.jsonl`. Do not trust a prior ranking.
+2. Exclude work owned by an active agent/session, work that collides with a dirty worktree, and any item whose next step is gated. Select the highest-value safe, reversible, non-colliding open item. Take or resume its canonical ticket and continuously log material actions and correlation evidence there.
+3. Run DTD to choose the exact bounded increment. Then route execution through the canonical owner. Delegation never widens authority; follow the A2A contract and independently verify any handoff.
+4. Invoke Cody the Contrarian on the actual result. Reproduce each claimed defect before promoting it.
+5. Run a final DTD forced choice: SHIP, FIX-THEN-SHIP, HOLD-FOR-STEVE, or KILL. Apply only reproduced, safe, reversible fixes.
+6. End with empirical E2E proof appropriate to the changed boundary. Web/UI work requires CTA plus screenrecord as `/yoloforever` specifies; non-UI work requires the real canary/API/test flow. Write reusable evidence and log it to the ticket and loop ledger.
+7. Append a concise cycle record to `/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/ledger.jsonl`: timestamp, ticket, action, DTD verdict, Cody verdict/top fix, final DTD verdict, tests/evidence, next seed, gated memos, cost. Use a safe file append mechanism. Then exit; launchd supplies the next cycle.
+
+HARD GATES: never perform customer-facing, destructive/irreversible, spend/money, identity, DNS/domain, publish, send-to-list, remote push, production deploy/write, canonical `dw_unified`, Shopify, or Merchant Center write unless that exact action has explicit current approval. Draft such actions to `~/.claude/yolo-queue/pending-approval/` and proceed only with a conservative safe default. Do not interpret “dangerous mode” as permission to bypass these gates.
+
+The only carried approval is TK-10993 Tracks A/B/C/D/E exactly as previously scoped. It does not extend to any other ticket or action. Track C remains HOLD until a newly rebuilt canary has immutable 400/400 identity-bearing baseline proof. Track E may run only in its revised scoped form after A/B and a fresh preflight. Re-enumerate/dedupe Track D immediately before any approved execution. If these constraints are not satisfied, do not execute the corresponding external write.
+
+Pause safely rather than spin if two consecutive cycles have zero new verified progress and only gated work remains, or if a hard safety/cost/canary tripwire fires. Never send email or messages externally. Keep spend at $0 unless Steve separately and explicitly approves a named spend.
diff --git a/scripts/codex-yoloforever.sh b/scripts/codex-yoloforever.sh
new file mode 100755
index 00000000..235f7791
--- /dev/null
+++ b/scripts/codex-yoloforever.sh
@@ -0,0 +1,100 @@
+#!/bin/zsh
+set -u
+
+ROOT="/Users/macstudio3/Projects/ticket-system"
+LABEL="com.steve.codex-yoloforever"
+STATE_DIR="$ROOT/data/codex-yoloforever"
+LOCK_DIR="$STATE_DIR/cycle.lock"
+STOP_FILE="$STATE_DIR/STOPPED"
+PROMPT_FILE="$ROOT/scripts/codex-yoloforever-prompt.md"
+LOG_FILE="$ROOT/codex-yoloforever.log"
+ERR_FILE="$ROOT/codex-yoloforever.err.log"
+LAST_MESSAGE="$STATE_DIR/last-message.md"
+CODEX="/Users/macstudio3/.local/bin/codex"
+PLIST="$ROOT/com.steve.codex-yoloforever.plist"
+DOMAIN="gui/$(id -u)"
+
+mkdir -p "$STATE_DIR"
+
+status() {
+  local loaded="no" running="no" stopped="no" pid=""
+  launchctl print "$DOMAIN/$LABEL" >/dev/null 2>&1 && loaded="yes"
+  if [[ -d "$LOCK_DIR" ]]; then
+    pid="$(cat "$LOCK_DIR/pid" 2>/dev/null || true)"
+    running="lock-held"
+  fi
+  [[ -f "$STOP_FILE" ]] && stopped="yes"
+  print "label=$LABEL loaded=$loaded running=$running stopped=$stopped pid=${pid:-none}"
+  [[ -f "$STATE_DIR/last-started-at" ]] && print "last_started=$(cat "$STATE_DIR/last-started-at")"
+  [[ -f "$STATE_DIR/last-finished-at" ]] && print "last_finished=$(cat "$STATE_DIR/last-finished-at")"
+  [[ -f "$STATE_DIR/last-exit" ]] && print "last_exit=$(cat "$STATE_DIR/last-exit")"
+}
+
+run_cycle() {
+  if [[ -f "$STOP_FILE" ]]; then
+    print "$(date -u +%FT%TZ) stopped sentinel present; cycle skipped" >> "$LOG_FILE"
+    return 0
+  fi
+
+  if ! mkdir "$LOCK_DIR" 2>/dev/null; then
+    local old_pid="$(cat "$LOCK_DIR/pid" 2>/dev/null || true)"
+    print "$(date -u +%FT%TZ) overlap prevented; lock owner pid=${old_pid:-unknown}" >> "$LOG_FILE"
+    return 0
+  fi
+
+  print $$ > "$LOCK_DIR/pid"
+  date -u +%FT%TZ > "$LOCK_DIR/started-at"
+  cp "$LOCK_DIR/started-at" "$STATE_DIR/last-started-at"
+  trap 'rm -f "$LOCK_DIR/pid" "$LOCK_DIR/started-at"; rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT INT TERM HUP
+
+  print "$(date -u +%FT%TZ) cycle begin pid=$$ engine=codex" >> "$LOG_FILE"
+  TK_AGENT=codex-yoloforever "$CODEX" exec \
+    --approve-for-me \
+    --cd /Users/macstudio3 \
+    --add-dir /private/tmp \
+    --skip-git-repo-check \
+    --color never \
+    --output-last-message "$LAST_MESSAGE" \
+    - < "$PROMPT_FILE" >> "$LOG_FILE" 2>> "$ERR_FILE"
+  local rc=$?
+  print "$rc" > "$STATE_DIR/last-exit"
+  date -u +%FT%TZ > "$STATE_DIR/last-finished-at"
+  print "$(date -u +%FT%TZ) cycle end pid=$$ exit=$rc" >> "$LOG_FILE"
+  return "$rc"
+}
+
+case "${1:-run}" in
+  run) run_cycle ;;
+  status) status ;;
+  stop)
+    date -u +%FT%TZ > "$STOP_FILE"
+    launchctl disable "$DOMAIN/$LABEL" >/dev/null 2>&1 || true
+    print "stopped $LABEL; active cycle, if any, is allowed to finish safely"
+    status
+    ;;
+  start)
+    rm -f "$STOP_FILE"
+    launchctl enable "$DOMAIN/$LABEL"
+    if ! launchctl print "$DOMAIN/$LABEL" >/dev/null 2>&1; then
+      launchctl bootstrap "$DOMAIN" "$PLIST"
+    fi
+    launchctl kickstart "$DOMAIN/$LABEL"
+    print "started $LABEL"
+    status
+    ;;
+  uninstall)
+    date -u +%FT%TZ > "$STOP_FILE"
+    launchctl bootout "$DOMAIN/$LABEL" >/dev/null 2>&1 || true
+    print "unloaded $LABEL; project files retained"
+    ;;
+  unlock)
+    if launchctl print "$DOMAIN/$LABEL" 2>/dev/null | grep -q 'state = running'; then
+      print -u2 "refusing unlock while launchd reports the job running"
+      exit 1
+    fi
+    rm -f "$LOCK_DIR/pid" "$LOCK_DIR/started-at" 2>/dev/null || true
+    rmdir "$LOCK_DIR" 2>/dev/null || true
+    print "cleared inactive lock"
+    ;;
+  *) print -u2 "usage: $0 {run|status|start|stop|unlock|uninstall}"; exit 2 ;;
+esac
diff --git a/verification/codex-yoloforever-e2e-proof.json b/verification/codex-yoloforever-e2e-proof.json
new file mode 100644
index 00000000..4c5b1e95
--- /dev/null
+++ b/verification/codex-yoloforever-e2e-proof.json
@@ -0,0 +1,29 @@
+{
+  "intent": "Keep a bounded Codex-only yoloforever open-ticket cycle running unattended under launchd with DTD and Cody gates",
+  "risk_tier": "R3 local agent/service automation with ticket state",
+  "environment": "macOS gui/501, /Users/macstudio3/Projects/ticket-system",
+  "timestamp": "2026-08-31T09:26:00Z",
+  "ticket": "TK-10993",
+  "baseline": {
+    "existing_remote_monitor_reused": false,
+    "reason": "com.steve.yolo-ticket-sync monitors a remote Claude service and cannot satisfy Codex-only execution",
+    "initial_job_loaded": false
+  },
+  "checks": [
+    {"boundary":"config","assertion":"runner parses, plist validates, patch has no whitespace errors","verdict":"PASS"},
+    {"boundary":"launchd","assertion":"job loaded from ~/Library/LaunchAgents, runs every 600 seconds, and reports state=running","evidence":"launchctl print: pid 72498, runs=3, run interval=600 seconds","verdict":"PASS"},
+    {"boundary":"Codex consumer","assertion":"service invokes codex exec rather than Claude","evidence":"cycle begin pid=72498 engine=codex; Codex SessionStart/UserPromptSubmit hooks","verdict":"PASS"},
+    {"boundary":"duplicate delivery","assertion":"concurrent invocation does not start a second cycle","evidence":"overlap prevented; lock owner pid=72498","verdict":"PASS"},
+    {"boundary":"operator stop/retry","assertion":"stop creates sentinel/disables future launches; start clears sentinel/enables job while preserving active lock","verdict":"PASS"},
+    {"boundary":"safety policy","assertion":"fresh snapshot, DTD, Cody, final DTD, empirical E2E, ledger, exact TK-10993 limits, and unrelated hard gates encoded","verdict":"PASS"},
+    {"boundary":"overnight continuity","assertion":"system and display sleep are prevented","evidence":"caffeinate -dimsu pid 1148; sleep=0 and displaysleep=0","verdict":"PASS"}
+  ],
+  "negative_checks": [
+    "Initial incompatible CLI flags and git trust errors were corrected before verified invocation",
+    "No overlap allowed while cycle lock existed",
+    "No STOPPED sentinel remains after restart"
+  ],
+  "retained_state": "LaunchAgent loaded and enabled; first verified Codex cycle intentionally remains active",
+  "rollback": "stop disables future launches without interrupting active work; uninstall bootouts job and retains project files",
+  "verdict": "PASS"
+}

← 7445e60c Measure ticket runtime from latest status change  ·  back to Ticket System  ·  record TK-10902 reconciliation proof 43b11230 →