Overnight Scheduling: агенты работают пока вы спите
Обещание и реальность
Идея проста и заманчива: вечером вы назначаете задачи, утром просыпаетесь -- фича готова. AI-агент работает 8 часов без перерыва, без отвлечений, без зарплаты за переработки.
21:00 Инженер: "Вот спецификация, вот fix plan, вот тесты. Работай."
→ Запуск Ralph Loop
21:01 Агент: Итерация 1 — Create User entity ✓
21:04 Агент: Итерация 2 — Create UserRepository ✓
21:07 Агент: Итерация 3 — Create UserService ✓
...
04:30 Агент: Итерация 47 — Final integration test ✓
04:31 Агент: "All 47 tasks complete. 0 remaining."
07:00 Инженер просыпается → git log → 47 коммитов → все тесты зелёные
Реальность: это работает, но только при выполнении жёстких предусловий. Без них ваша "ночная смена" превратится в утреннюю археологию.
Предусловия для overnight runs
| Предусловие | Почему критично | Что будет без него |
|---|---|---|
| Комплексный тестовый набор | Агент не может спросить человека в 3 AM | Код "работает" только визуально, баги скрыты |
| Однозначная спецификация | Нет возможности уточнить | Агент интерпретирует по-своему |
| Git branch isolation | Ошибки не должны попасть в main | Утром main сломан |
| Лимиты ресурсов | Prevent runaway API costs | Утром счёт на $500 |
| Детальный fix plan | Агент должен знать порядок | Агент делает задачи в случайном порядке |
Железное правило: Если вы не можете написать тесты для задачи -- вы не можете запустить её на ночь. Без тестов агент -- это генератор случайного кода.
Настройка overnight run
#!/bin/bash
# overnight-run.sh — Safe overnight Ralph Loop execution
set -euo pipefail
# === Configuration ===
MAX_COST=50 # Maximum API cost in dollars
MAX_TIME=28800 # Maximum runtime: 8 hours (in seconds)
MAX_ITERATIONS=200 # Maximum loop iterations
BRANCH="overnight/$(date +%Y%m%d)"
LOG_FILE="overnight-$(date +%Y%m%d).log"
NOTIFY_CHANNEL="telegram" # or: slack, email, none
# === Pre-flight ===
echo "$(date): Starting overnight run" | tee "$LOG_FILE"
# Verify tests pass BEFORE starting
echo "Running pre-flight tests..." | tee -a "$LOG_FILE"
npm test >> "$LOG_FILE" 2>&1 || {
echo "PRE-FLIGHT FAILED: Tests not passing. Aborting overnight run." | tee -a "$LOG_FILE"
exit 1
}
# Verify fix plan has tasks
TASKS=$(grep -c "\- \[ \]" fix_plan.md 2>/dev/null || echo "0")
if [ "$TASKS" -eq 0 ]; then
echo "No tasks in fix_plan.md. Nothing to do." | tee -a "$LOG_FILE"
exit 0
fi
echo "Found $TASKS tasks to complete" | tee -a "$LOG_FILE"
# === Main Loop ===
ITERATION=0
START_TIME=$(date +%s)
while [ $ITERATION -lt $MAX_ITERATIONS ]; do
ITERATION=$((ITERATION + 1))
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - START_TIME))
# Time limit check
if [ $ELAPSED -gt $MAX_TIME ]; then
echo "$(date): Time limit reached ($MAX_TIME seconds)" | tee -a "$LOG_FILE"
break
fi
# Check remaining tasks
REMAINING=$(grep -c "\- \[ \]" fix_plan.md 2>/dev/null || echo "0")
if [ "$REMAINING" -eq 0 ]; then
echo "$(date): All tasks complete!" | tee -a "$LOG_FILE"
break
fi
echo "$(date): Iteration $ITERATION | Remaining: $REMAINING | Elapsed: ${ELAPSED}s" | tee -a "$LOG_FILE"
# Run agent
cat PROMPT.md | claude --print >> "$LOG_FILE" 2>&1
# Minimal pause
sleep 2
done
# === Post-flight ===
echo "" | tee -a "$LOG_FILE"
echo "=== OVERNIGHT RUN COMPLETE ===" | tee -a "$LOG_FILE"
echo "Iterations: $ITERATION" | tee -a "$LOG_FILE"
echo "Duration: $((ELAPSED / 60)) minutes" | tee -a "$LOG_FILE"
echo "Completed: $(grep -c '\[x\]' fix_plan.md 2>/dev/null || echo 0)" | tee -a "$LOG_FILE"
echo "Remaining: $(grep -c '\[ \]' fix_plan.md 2>/dev/null || echo 0)" | tee -a "$LOG_FILE"
# Run full test suite
echo "Running post-flight tests..." | tee -a "$LOG_FILE"
npm test >> "$LOG_FILE" 2>&1 && echo "ALL TESTS PASS" | tee -a "$LOG_FILE" || echo "SOME TESTS FAILING" | tee -a "$LOG_FILE"
# === Notification ===
SUMMARY="Overnight run: $ITERATION iterations, $(grep -c '\[x\]' fix_plan.md 2>/dev/null || echo 0) tasks done, $(grep -c '\[ \]' fix_plan.md 2>/dev/null || echo 0) remaining"
case $NOTIFY_CHANNEL in
telegram)
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
-d "text=${SUMMARY}" >/dev/null 2>&1 || true
;;
slack)
curl -s -X POST "$SLACK_WEBHOOK" \
-H 'Content-type: application/json' \
-d "{\"text\": \"$SUMMARY\"}" >/dev/null 2>&1 || true
;;
none)
# macOS notification as fallback
osascript -e "display notification \"$SUMMARY\" with title \"Overnight Run\"" 2>/dev/null || true
;;
esac
echo "$(date): Overnight run finished" | tee -a "$LOG_FILE"
Утренний workflow ревью
Утром вы не просто "принимаете работу". Вы проводите систематическую проверку:
# Morning Review Checklist
## Step 1: Read the log (5 min)
- How many iterations?
- Any repeated failures?
- Any tasks marked as BLOCKED?
- Total estimated cost?
## Step 2: Check git log (5 min)
```bash
git log --oneline overnight/YYYYMMDD
# Look for:
# - Consistent commit messages
# - Reasonable commit size
# - No "fix fix fix" patterns
Step 3: Run full test suite (2 min)
npm test
# Must be 100% green. If not — do NOT merge.
Step 4: Review the diff (15-30 min)
git diff main..overnight/YYYYMMDD
# Look for:
# - Correct architecture (right layers, right patterns)
# - No hardcoded values
# - No security issues
# - No TODO/FIXME/HACK
# - Consistent style
Step 5: Decision
- All tests pass AND code quality acceptable → Merge
- Tests pass but code needs fixes → Fix manually, then merge
- Tests failing → Do NOT merge, investigate
- Architecture wrong → Delete branch, redo with better spec
> **Правило:** Никогда не мержите overnight-ветку без ревью. Даже если все тесты зелёные -- проверьте код глазами. AI может генерировать "работающий, но плохой" код.
---
## Multi-Agent координация
### Когда использовать несколько агентов
Один агент (90% случаев): ✓ Последовательная реализация ✓ Простая координация ✓ Предсказуемый результат ✓ Минимальный расход API
Несколько агентов (10% случаев): ✓ Большие фичи с независимыми компонентами ✓ Разная экспертиза (backend + frontend) ✓ Параллельное тестирование и реализация ✗ Сложная координация ✗ Потенциальные конфликты ✗ Расход API x N
### Стратегия: Shared Fix Plan
Все агенты читают и пишут в один fix_plan.md. Требуется механизм блокировки.
```markdown
# fix_plan.md with agent assignment
## Backend Agent
- [x] [backend] Create Order entity
- [x] [backend] Create OrderRepository
- [ ] [backend] Create OrderService
- [ ] [backend] Create OrderController
## Frontend Agent
- [x] [frontend] Create OrderForm component
- [x] [frontend] Create OrderList component
- [ ] [frontend] Create OrderDetail page
- [ ] [frontend] Add API integration
## Test Agent
- [x] [test] Write OrderService unit tests
- [ ] [test] Write OrderController integration tests
- [ ] [test] Write E2E order creation test
Проблема: два агента могут одновременно решить обновить fix_plan.md. Решение -- файловая блокировка или разделение на отдельные файлы:
fix_plans/
├── backend.md # Only backend agent reads/writes
├── frontend.md # Only frontend agent reads/writes
└── testing.md # Only test agent reads/writes
Стратегия: File-Level Locking
Предотвращение модификации одного файла двумя агентами:
# In each agent's PROMPT.md:
## File Ownership
You may ONLY modify files in these directories:
- src/Service/
- src/Repository/
- src/Entity/
You may NOT modify:
- src/Controller/ (owned by API agent)
- resources/views/ (owned by frontend agent)
- tests/ (owned by test agent)
Стратегия: Communication via Files
Агенты общаются через файлы в специальной директории:
.agents/
├── backend-status.md # Backend agent writes status here
├── frontend-status.md # Frontend agent writes status here
├── requests.md # Agents request things from each other
└── interfaces.md # Shared interface definitions
# .agents/requests.md
## Request from Frontend Agent (2026-03-07 22:30)
Need: OrderResponse DTO with fields: id, status, items[], total, createdAt
For: Frontend OrderDetail component
Priority: Blocking
## Response from Backend Agent (2026-03-07 22:35)
Done: OrderResponse DTO created at src/DTO/OrderResponse.php
Fields: id (UUID), status (string), items (array), totalAmount (int), createdAt (DateTime)
Note: totalAmount is in cents, frontend should divide by 100 for display
Предупреждение
Мнение практиков: Большинство команд, использующих мульти-агентный подход, переоценивают выигрыш от параллелизации и недооценивают стоимость координации. Один хорошо настроенный агент с детальной спецификацией часто быстрее, чем три плохо координированных.
Системы безопасности -- CRITICAL
Безопасность автономных агентов -- это не "best practice", а необходимость. Агент без ограничений -- это root-доступ для вероятностной модели.
Resource Limits (Ограничение ресурсов)
# safety-config.yml
resource_limits:
# Cost control
max_api_cost_per_session: 50 # dollars
max_api_cost_per_iteration: 2 # dollars
cost_alert_threshold: 25 # alert at 50%
# Time control
max_session_duration: 28800 # 8 hours in seconds
max_iteration_duration: 600 # 10 minutes per iteration
timeout_action: "stop" # stop | pause | alert
# Scope control
max_iterations: 200 # hard limit
max_files_modified: 50 # alert if exceeded
max_lines_changed_per_file: 500 # alert if exceeded
max_new_files: 30 # alert if exceeded
Operation Restrictions (Ограничение операций)
Это самый критичный раздел. Автономный агент категорически не должен выполнять определённые операции:
# ABSOLUTE RESTRICTIONS — NEVER ALLOWED
## Git Operations
- NO git push (human reviews and pushes)
- NO git push --force (NEVER, under any circumstances)
- NO git merge to main/master
- NO git rebase of shared branches
- NO git tag (releases are human decision)
## Deployment
- NO deploy to any environment
- NO docker push to registry
- NO kubectl apply to cluster
- NO ssh to production servers
- NO ansible/terraform on production
## Database
- NO migrations on production databases
- NO data deletion on any environment
- NO schema changes on shared databases
## External Services
- NO calls to production APIs
- NO sending emails to real users
- NO payment processing
- NO modifying DNS/CDN configuration
## Secrets
- NO hardcoded API keys, tokens, passwords
- NO committing .env files
- NO logging sensitive data
Реализация ограничений в скрипте:
#!/bin/bash
# safety-wrapper.sh — Wraps claude commands with safety checks
# Override dangerous commands
git() {
case "$1" in
push|merge|rebase|tag)
echo "BLOCKED: 'git $1' is not allowed in autonomous mode"
echo "$(date): BLOCKED git $1" >> safety.log
return 1
;;
*)
command git "$@"
;;
esac
}
# Override deployment commands
docker() {
case "$1" in
push)
echo "BLOCKED: 'docker push' is not allowed"
return 1
;;
*)
command docker "$@"
;;
esac
}
# Override SSH
ssh() {
echo "BLOCKED: SSH is not allowed in autonomous mode"
return 1
}
export -f git docker ssh
Monitoring and Alerting (Мониторинг и оповещения)
#!/bin/bash
# monitor.sh — Monitor running Ralph Loop
LOG_FILE="ralph.log"
ALERT_THRESHOLD_FAILURES=3
ALERT_THRESHOLD_SAME_ERROR=3
# Watch for repeated failures
CONSECUTIVE_FAILURES=0
LAST_ERROR=""
tail -f "$LOG_FILE" | while read -r line; do
# Detect test failure
if echo "$line" | grep -qi "FAIL\|ERROR\|Exception"; then
CONSECUTIVE_FAILURES=$((CONSECUTIVE_FAILURES + 1))
# Check for same error repeating
CURRENT_ERROR=$(echo "$line" | head -c 100)
if [ "$CURRENT_ERROR" = "$LAST_ERROR" ]; then
SAME_ERROR_COUNT=$((SAME_ERROR_COUNT + 1))
else
SAME_ERROR_COUNT=1
LAST_ERROR="$CURRENT_ERROR"
fi
# Alert on repeated failures
if [ $CONSECUTIVE_FAILURES -ge $ALERT_THRESHOLD_FAILURES ]; then
osascript -e "display notification \"$CONSECUTIVE_FAILURES consecutive failures detected\" with title \"Ralph Loop Alert\" sound name \"Basso\"" 2>/dev/null
fi
# Alert on same error repeating
if [ $SAME_ERROR_COUNT -ge $ALERT_THRESHOLD_SAME_ERROR ]; then
osascript -e "display notification \"Same error $SAME_ERROR_COUNT times. Agent may be stuck.\" with title \"Ralph Loop STUCK\" sound name \"Sosumi\"" 2>/dev/null
fi
else
CONSECUTIVE_FAILURES=0
fi
# Detect unexpected file modifications
if echo "$line" | grep -qi "modified.*\.env\|modified.*config/secrets"; then
osascript -e "display notification \"Sensitive file modified!\" with title \"SECURITY ALERT\" sound name \"Funk\"" 2>/dev/null
fi
done
Alerted conditions (Условия для оповещений)
| Условие | Уровень | Действие |
|---|---|---|
| 3+ последовательных провала | Warning | Уведомление + пауза |
| Одна и та же ошибка 3+ раз | Critical | Уведомление + остановка |
| Модификация .env / secrets | Critical | Немедленная остановка |
| Превышение лимита стоимости | Critical | Остановка |
| Превышение лимита времени | Warning | Остановка |
| Более 50 файлов изменено | Warning | Уведомление |
| git push / deploy попытка | Critical | Блокировка + уведомление |
Rollback Strategy (Стратегия отката)
Каждый агент работает на изолированной ветке. Откат -- тривиальная операция:
# If overnight run produced bad results:
# Option 1: Delete entire branch (nuclear option)
# git checkout main
# git branch -D overnight/20260307
# Option 2: Cherry-pick good commits
# git checkout main
# git cherry-pick <good-commit-hash-1> <good-commit-hash-2>
# Option 3: Reset to last known good state
# git checkout overnight/20260307
# git reset --hard <last-good-commit>
Стратегия безопасности — уровни защиты:
Level 1: Isolated branch ← Ошибки не попадают в main
Level 2: Operation restrictions ← Нет push/deploy/production
Level 3: Resource limits ← Ограничение по стоимости и времени
Level 4: Monitoring + alerts ← Обнаружение проблем в реальном времени
Level 5: Human review ← Финальное решение всегда за человеком
Принцип максимального ущерба: Спроектируйте систему так, чтобы при ХУДШЕМ возможном сценарии максимальный ущерб был: "потеряна одна ветка git + $50 на API". Не больше.
231 пример от Паполини
Книга Паполини содержит 231 полностью рабочий пример. Наиболее практически ценные:
Пример: Safe Loop с трекингом затрат
#!/bin/bash
# From Papalini's patterns — adapted
COST_FILE=".cost_tracker"
echo "0" > "$COST_FILE"
estimate_cost() {
# Rough estimation: each iteration ~$0.30-0.80
local iterations=$1
echo "scale=2; $iterations * 0.50" | bc
}
check_budget() {
local current=$(cat "$COST_FILE")
local limit=$1
if (( $(echo "$current > $limit" | bc -l) )); then
echo "BUDGET EXCEEDED: \$$current > \$$limit"
return 1
fi
return 0
}
# Main loop with cost tracking
ITERATION=0
MAX_COST=25
while grep -q "\- \[ \]" fix_plan.md; do
ITERATION=$((ITERATION + 1))
# Update cost estimate
ESTIMATED=$(estimate_cost $ITERATION)
echo "$ESTIMATED" > "$COST_FILE"
# Check budget
check_budget $MAX_COST || {
echo "Stopping: budget limit reached"
break
}
echo "Iteration $ITERATION | Est. cost: \$$ESTIMATED / \$$MAX_COST"
# Run agent
cat PROMPT.md | claude --print
sleep 2
done
Пример: Автоматический откат при неудаче
#!/bin/bash
# Automatic rollback pattern
run_with_rollback() {
local save_point=$(git rev-parse HEAD)
local task="$1"
local max_attempts=3
local attempt=0
while [ $attempt -lt $max_attempts ]; do
attempt=$((attempt + 1))
echo "Task: $task | Attempt: $attempt"
# Run agent for this specific task
echo "Implement this task: $task" | claude --print
# Verify
if npm test 2>/dev/null; then
echo "Task succeeded on attempt $attempt"
return 0
fi
# Rollback to save point
echo "Rolling back to $save_point"
git checkout -- .
git clean -fd
done
echo "Task FAILED after $max_attempts attempts: $task"
return 1
}
# Process each task with rollback safety
while IFS= read -r task; do
run_with_rollback "$task" || {
echo "BLOCKED: $task" >> blocked_tasks.md
}
done < <(grep "\- \[ \]" fix_plan.md | sed 's/- \[ \] //')
Пример: Memory-enhanced Compound Learning Loop
#!/bin/bash
# Compound learning loop — agent improves over iterations
LEARNING_FILE="learned_patterns.md"
touch "$LEARNING_FILE"
ITERATION=0
while grep -q "\- \[ \]" fix_plan.md; do
ITERATION=$((ITERATION + 1))
# Build prompt with accumulated learning
cat <<EOF | claude --print
Read @AGENT.md for project conventions.
Read @spec.md for feature specification.
Read @fix_plan.md for current tasks.
Read @${LEARNING_FILE} for patterns learned in previous iterations.
## Instructions
1. Pick the first unchecked task
2. Check learned_patterns.md for relevant patterns
3. Implement the task
4. Run tests
5. If successful:
- Mark task done
- If you discovered a new pattern, append it to ${LEARNING_FILE}:
## Pattern: [name]
**Context**: [when to use]
**Implementation**: [how to implement]
**Discovered**: Iteration $ITERATION
6. If failed:
- Analyze the error
- Record what you learned in ${LEARNING_FILE}:
## Anti-pattern: [name]
**Mistake**: [what went wrong]
**Correct approach**: [how to fix]
**Discovered**: Iteration $ITERATION
EOF
sleep 2
done
echo "Learning complete. Patterns discovered:"
grep -c "## Pattern:" "$LEARNING_FILE" 2>/dev/null || echo "0"
echo "Anti-patterns recorded:"
grep -c "## Anti-pattern:" "$LEARNING_FILE" 2>/dev/null || echo "0"
Когда НЕ использовать автономных агентов
Категорически не рекомендуется
| Ситуация | Почему не подходит | Что делать вместо |
|---|---|---|
| Legacy без тестов | Нет верификации, агент сломает что угодно | Сначала написать тесты вручную |
| Security-critical код | Аутентификация, криптография, платежи | Писать вручную, AI максимум как ассистент |
| Performance hot paths | Агент не профилирует, не оптимизирует | Профилировать вручную, AI для черновика |
| Плохая спецификация | "Сделай что-то крутое" -- не spec | Сначала написать нормальную спецификацию |
| Изучение домена | Вам нужно понять бизнес, а не написать код | Изучить домен, затем автоматизировать |
Пограничные случаи
Существующая кодовая база с тестами:
→ Можно, но с осторожностью
→ Обязательно: Selective Context + reference files
→ Риск: агент может не уловить неявные конвенции
Фронтенд (UI/UX):
→ Ограниченно
→ Генерация компонентов — да
→ Визуальный дизайн — нет (агент не "видит" результат)
→ Accessibility — частично (может проверять ARIA-атрибуты)
Рефакторинг:
→ Хорошо подходит для механических рефакторингов
→ Плохо для архитектурных рефакторингов
→ Обязательно: полный тестовый набор до начала
Матрица применимости
Тесты есть Тесты нет
┌─────────────┬─────────────┐
Greenfield │ ИДЕАЛЬНО │ ВОЗМОЖНО* │
│ 95% успех │ 60% успех │
├─────────────┼─────────────┤
Existing codebase │ ХОРОШО │ ОПАСНО │
│ 75% успех │ 20% успех │
├─────────────┼─────────────┤
Legacy │ ОСТОРОЖНО │ НЕ НАДО │
│ 50% успех │ ~0% успех │
└─────────────┴─────────────┘
* Если пишете тесты параллельно с реализацией
Чеклист безопасности для production
Перед запуском автономного агента в любом режиме:
# Safety Checklist
## Environment Isolation
- [ ] Agent works on isolated git branch (not main/master)
- [ ] Agent has NO access to production environment
- [ ] Agent has NO access to production database
- [ ] Agent has NO access to production APIs
- [ ] Agent has NO SSH keys for production servers
## Operation Restrictions
- [ ] git push is blocked or not configured
- [ ] deploy commands are blocked
- [ ] External API calls are mocked or blocked
- [ ] Email sending is disabled or mocked
- [ ] Payment processing is disabled
## Resource Limits
- [ ] Maximum API cost per session is set
- [ ] Maximum runtime is set
- [ ] Maximum iterations is set
- [ ] Cost tracking is enabled
## Monitoring
- [ ] Log file is configured
- [ ] Failure alerts are configured
- [ ] Cost alerts are configured
- [ ] Security alerts are configured (sensitive file modification)
## Rollback Plan
- [ ] I know how to delete the agent's branch
- [ ] I know how to cherry-pick good commits
- [ ] I have a backup of the current main state
- [ ] Maximum possible damage is: lost branch + $X API cost
## Human Review
- [ ] I will review ALL changes before merging
- [ ] I will run full test suite before merging
- [ ] I will NOT merge without visual code review
- [ ] I understand this is MY responsibility, not the agent's
Выводы
-
Overnight scheduling работает при наличии тестов, спецификации и ограничений. Без них -- это рулетка.
-
Multi-agent = последнее средство. Один хороший агент > три плохо координированных. Используйте мульти-агент только для по-настоящему независимых задач.
-
Безопасность -- это 5 уровней: изолированная ветка, ограничение операций, лимиты ресурсов, мониторинг, человеческое ревью. Все пять обязательны.
-
Принцип максимального ущерба: при самом плохом сценарии потери = одна git-ветка + стоимость API. Не больше. Если потенциальный ущерб больше -- система небезопасна.
-
Автономность != бесконтрольность. Агент работает автономно, но человек всегда имеет финальное слово. Merge, push, deploy -- это решения человека.
-
Не автоматизируйте то, что не понимаете. Если вы не можете написать спецификацию для задачи -- вы не готовы отдать её агенту. Сначала поймите, потом автоматизируйте.