diff --git a/docs/prompt/evolve.md b/docs/prompt/evolve.md index 92b612f..2b8531c 100644 --- a/docs/prompt/evolve.md +++ b/docs/prompt/evolve.md @@ -350,7 +350,7 @@ You are not a task runner. You are the engineer who owns this system. Before end | Security / robustness | Edge cases that crash? Input validation gaps? Auto-merge exploitable? Secrets exposed? | **Constraints:** -- **Queue-aware cap.** Count pending tasks in `docs/tasks/`. If 40+ pending, create 0 new tasks. If 30-39 pending, max 1 task. If under 30, max 3 tasks. Creating tasks is NOT mandatory — create 0 if nothing important was discovered. The queue must not grow faster than the system can close tasks. +- **Create only what matters.** If you found a real bug, edge case, or missing test — create a task. If you didn't discover anything new — create 0. Never create tasks just to fill a quota. Check for duplicates first (scan pending tasks). The OVERSEE role handles queue cleanup. - **Check for duplicates first.** Scan all pending tasks in `docs/tasks/`. If a task already covers your idea, skip it or update the existing task instead. - **Span multiple dimensions.** If you create 3 tasks, they should not all be "code quality." Spread across at least 2 different dimensions. - **Vision alignment check.** Before creating tasks, read the last 5 task files (by number). Check their `vision_section` field. If 3+ target the same section, your new tasks MUST prioritize a different section. Check `docs/vision-tracker/TRACKER.md` — lower-percentage sections need more attention. Set `vision_section` in every new task's frontmatter (`loop1`, `loop2`, `self-maintaining`, `meta-prompt`, or `none`). Exception: if a section has urgent bugs or blockers, alignment can be overridden — explain why in the task description. diff --git a/docs/tasks/0032.md b/docs/tasks/0032.md index 0d31179..c786aec 100644 --- a/docs/tasks/0032.md +++ b/docs/tasks/0032.md @@ -1,5 +1,5 @@ --- -status: blocked +status: pending priority: normal environment: integration blocked_reason: environment diff --git a/docs/tasks/0103.md b/docs/tasks/0103.md index e850b9e..2e2397c 100644 --- a/docs/tasks/0103.md +++ b/docs/tasks/0103.md @@ -1,5 +1,5 @@ --- -status: blocked +status: pending priority: urgent target: v0.0.9 blocked_reason: design diff --git a/docs/tasks/0074.md b/docs/tasks/archive/0074.md similarity index 98% rename from docs/tasks/0074.md rename to docs/tasks/archive/0074.md index 956e2b2..b45ccf6 100644 --- a/docs/tasks/0074.md +++ b/docs/tasks/archive/0074.md @@ -1,5 +1,5 @@ --- -status: pending +status: wontfix priority: normal target: v0.0.8 vision_section: loop2 diff --git a/scripts/watchdog.sh b/scripts/watchdog.sh new file mode 100755 index 0000000..f9f2284 --- /dev/null +++ b/scripts/watchdog.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# ---------------------------------------------- +# Nightshift Watchdog +# +# Keeps the daemon running forever. If it crashes, +# cleans up and restarts. Designed to run via: +# +# caffeinate -s bash scripts/watchdog.sh codex 60 +# +# Or in tmux: +# tmux new-session -d -s nightshift "caffeinate -s bash scripts/watchdog.sh codex 60" +# +# The watchdog never exits unless you kill it. +# The daemon inside it handles its own circuit breaker, +# budget limits, and session caps. +# ---------------------------------------------- + +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +LOCKFILE="$REPO_DIR/.nightshift-daemon.lock" + +AGENT="${1:-codex}" +PAUSE="${2:-60}" +RESTART_DELAY=30 +MAX_RESTARTS_PER_HOUR=5 +RESTART_COUNT=0 +LAST_RESET_TIME=$(date +%s) + +echo "==================================================" +echo " NIGHTSHIFT WATCHDOG" +echo " Agent: $AGENT" +echo " Pause: ${PAUSE}s" +echo " Restart delay: ${RESTART_DELAY}s" +echo " Max restarts: $MAX_RESTARTS_PER_HOUR per hour" +echo " Stop: Ctrl+C" +echo "==================================================" +echo "" + +while true; do + # --- Rate limit restarts --- + NOW=$(date +%s) + ELAPSED=$(( NOW - LAST_RESET_TIME )) + if [ "$ELAPSED" -ge 3600 ]; then + RESTART_COUNT=0 + LAST_RESET_TIME=$NOW + fi + + if [ "$RESTART_COUNT" -ge "$MAX_RESTARTS_PER_HOUR" ]; then + echo "WATCHDOG: $MAX_RESTARTS_PER_HOUR restarts in the last hour. Something is fundamentally broken." + echo "WATCHDOG: Sleeping 1 hour before retrying." + sleep 3600 + RESTART_COUNT=0 + LAST_RESET_TIME=$(date +%s) + fi + + # --- Clean stale lock --- + if [ -d "$LOCKFILE" ]; then + echo "WATCHDOG: Cleaning stale lock from previous crash." + rmdir "$LOCKFILE" 2>/dev/null || true + fi + + # --- Run the daemon --- + echo "WATCHDOG: Starting daemon (attempt $((RESTART_COUNT + 1))) --- $(date '+%Y-%m-%d %H:%M:%S') ---" + bash "$SCRIPT_DIR/daemon.sh" "$AGENT" "$PAUSE" + EXIT_CODE=$? + + RESTART_COUNT=$((RESTART_COUNT + 1)) + + if [ "$EXIT_CODE" -eq 0 ]; then + echo "WATCHDOG: Daemon exited cleanly (exit 0). Restarting in ${RESTART_DELAY}s." + else + echo "WATCHDOG: Daemon crashed (exit $EXIT_CODE). Restarting in ${RESTART_DELAY}s." + fi + + sleep "$RESTART_DELAY" +done