HardПрактика11 min

Практическая реализация Ralph Loop

Пошаговое руководство по настройке автономного цикла разработки

Предварительные требования

Прежде чем запускать Ralph Loop, необходимо подготовить инфраструктуру. Автономный цикл -- это не магия; он требует продуманной основы.

Что нужно для старта

Компонент Назначение Примеры
AI-инструмент Агент, выполняющий задачи Claude Code, Copilot CLI, Amp, Aider
Тестовая инфраструктура Автоматическая верификация PHPUnit, Jest, Vitest, go test
Система типов Backpressure на уровне языка TypeScript strict, PHPStan, Go compiler
Линтер Проверка стиля и паттернов ESLint, PHP CS Fixer, golangci-lint
VCS Контроль версий Git (обязательно)
Спецификация Описание того, что строить Markdown-файлы

Важно: Если в проекте нет тестов -- Ralph Loop будет генерировать код без верификации. Это как водить машину с завязанными глазами. Сначала напишите тесты, потом запускайте цикл.

Проверка готовности

# Checklist before starting Ralph Loop
#!/bin/bash
echo "=== Ralph Loop Readiness Check ==="

# 1. AI tool available
command -v claude >/dev/null 2>&1 && echo "✓ Claude Code installed" || echo "✗ Claude Code not found"

# 2. Tests exist and pass
if [ -f "package.json" ]; then
  npm test && echo "✓ Tests pass" || echo "✗ Tests failing"
elif [ -f "composer.json" ]; then
  php vendor/bin/phpunit && echo "✓ Tests pass" || echo "✗ Tests failing"
elif [ -f "go.mod" ]; then
  go test ./... && echo "✓ Tests pass" || echo "✗ Tests failing"
fi

# 3. Linter configured
if [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
  echo "✓ ESLint configured"
elif [ -f "phpstan.neon" ]; then
  echo "✓ PHPStan configured"
elif [ -f ".golangci.yml" ]; then
  echo "✓ golangci-lint configured"
else
  echo "✗ No linter configuration found"
fi

# 4. Git clean state
if [ -z "$(git status --porcelain)" ]; then
  echo "✓ Git working directory clean"
else
  echo "✗ Git has uncommitted changes"
fi

echo "=== Check complete ==="

Шаг 1: Создание AGENT.md

AGENT.md -- это "конституция" вашего проекта для AI-агента. Он загружается при каждой итерации цикла и определяет, как агент должен работать.

Структура AGENT.md

# Project: My E-Commerce API

## Overview
REST API for e-commerce platform built with Symfony 7 and PHP 8.4.
PostgreSQL for storage, Redis for caching, RabbitMQ for async messaging.

## Build & Test Commands
- **Build**: `composer check` (runs PHPStan + CS Fixer + tests)
- **Test all**: `php bin/phpunit`
- **Test unit**: `php bin/phpunit --testsuite=unit`
- **Test integration**: `php bin/phpunit --testsuite=integration`
- **Static analysis**: `vendor/bin/phpstan analyse -l 9`
- **Code style**: `vendor/bin/php-cs-fixer fix --dry-run`
- **Fix style**: `vendor/bin/php-cs-fixer fix`

## Architecture

src/ ├── Controller/ # Thin controllers, validation + delegation ├── DTO/ # Request/Response objects ├── Entity/ # Doctrine entities ├── Repository/ # Data access layer ├── Service/ # Business logic ├── Event/ # Domain events ├── Exception/ # Custom exceptions └── Validator/ # Custom validators


## Conventions
- `declare(strict_types=1)` in every PHP file
- `final` classes by default
- `readonly` DTOs
- Constructor property promotion always
- Type hints on ALL parameters and return types
- Enums for statuses (never string constants)
- UUID v7 for primary keys (never auto-increment)
- Repository pattern for data access (never raw SQL in services)

## Naming
- Entities: singular PascalCase (Order, OrderItem)
- Repositories: {Entity}Repository
- Services: {Domain}Service (OrderService, not OrderManager)
- DTOs: {Action}{Entity}Request/Response (CreateOrderRequest)
- Controllers: {Entity}Controller
- Tests: {Class}Test

## Patterns to Follow
- Services are injected via constructor
- Controllers return JsonResponse
- Validation in DTO classes (Symfony Validator attributes)
- Business logic ONLY in Service layer
- Events for side effects (email, notifications)

## Anti-patterns to Avoid
- No service locator (never use container directly)
- No business logic in controllers
- No raw SQL in services
- No static methods for business logic
- No mixed return types (always specific types)

Советы по написанию AGENT.md

  1. Будьте конкретны. "Используйте паттерн репозиторий" -- плохо. "Все обращения к БД через {Entity}Repository, никогда не используйте EntityManager напрямую в сервисах" -- хорошо.

  2. Приведите реальные примеры. Если в проекте есть эталонный контроллер -- сошлитесь на него:

    ## Reference Files
    - Example controller: src/Controller/ProductController.php
    - Example service: src/Service/ProductService.php
    - Example test: tests/Unit/Service/ProductServiceTest.php
    
  3. Укажите запреты. AI-агенты склонны к определённым паттернам -- явно запретите нежелательные.

  4. Держите файл компактным. AGENT.md загружается при каждой итерации и съедает контекстное окно. Оптимальный размер: 100-200 строк.


Шаг 2: Создание спецификации (spec.md)

Спецификация описывает что нужно реализовать. Это контракт между вами и AI-агентом.

Структура спецификации

# Feature: Order Management API

## Business Context
Customers need to create, view, and manage orders through the mobile app.
Each order contains one or more items, has a delivery address, and goes
through a lifecycle: created → confirmed → shipped → delivered.

## API Endpoints

### POST /api/v1/orders
Create a new order.

**Request Body:**
```json
{
  "items": [
    {
      "product_id": "01930f8e-7a1b-7000-8000-000000000001",
      "quantity": 2
    }
  ],
  "shipping_address": {
    "street": "123 Main St",
    "city": "Moscow",
    "postal_code": "101000"
  },
  "idempotency_key": "unique-request-id-123"
}

Response 201:

{
  "id": "01930f8e-7a1b-7000-8000-000000000099",
  "status": "created",
  "items": [...],
  "total_amount": 5000,
  "created_at": "2026-03-07T10:00:00Z"
}

Response 422:

{
  "errors": {
    "items[0].quantity": "Quantity must be between 1 and 1000",
    "shipping_address.postal_code": "Invalid postal code format"
  }
}

GET /api/v1/orders/{id}

Get order details.

GET /api/v1/orders

List orders for authenticated user with cursor-based pagination.

Data Model

Order Entity

Field Type Constraints
id UUID v7 PK
user_id UUID v7 FK → users, NOT NULL
status OrderStatus enum NOT NULL, default: CREATED
total_amount int (cents) NOT NULL
idempotency_key string(64) UNIQUE
shipping_address embedded NOT NULL
created_at timestamptz NOT NULL, default: NOW
updated_at timestamptz NOT NULL, default: NOW

OrderItem Entity

Field Type Constraints
id UUID v7 PK
order_id UUID v7 FK → orders
product_id UUID v7 FK → products
quantity int NOT NULL, 1-1000
unit_price int (cents) NOT NULL

OrderStatus Enum

  • CREATED
  • CONFIRMED
  • SHIPPED
  • DELIVERED
  • CANCELLED

Business Rules

  1. Order must have at least 1 item
  2. Maximum 50 items per order
  3. Product must exist and be available
  4. Quantity between 1 and 1000
  5. Idempotency: same key returns existing order (not error)
  6. Only authenticated users can create orders
  7. Users can only view their own orders

Edge Cases

  • Product out of stock after order creation → handle gracefully
  • Concurrent requests with same idempotency key → return existing
  • User tries to view another user's order → 403
  • Invalid product_id → 422 with clear error

> **Правило:** Чем детальнее спецификация, тем точнее результат. Потратьте 30 минут на спецификацию, чтобы сэкономить 3 часа на исправлениях.

---

## Шаг 3: Создание fix plan (fix_plan.md)

Fix plan -- это упорядоченный список атомарных задач. Агент при каждой итерации находит первую невыполненную задачу и реализует её.

### Структура fix plan

```markdown
# Fix Plan: Order Management API

## Priority: Critical (must have)

### Data Layer
- [x] Create OrderStatus enum (src/Enum/OrderStatus.php)
- [x] Create Order entity with all fields and validation
- [x] Create OrderItem entity with relationship to Order
- [x] Create ShippingAddress embeddable
- [ ] Create OrderRepository with findByUser() and findByIdempotencyKey()
- [ ] Create Doctrine migration for orders and order_items tables

### Service Layer
- [ ] Create CreateOrderRequest DTO with validation
- [ ] Create OrderResponse DTO
- [ ] Create OrderListResponse DTO with pagination
- [ ] Create OrderService.create() with idempotency handling
- [ ] Create OrderService.getById() with ownership check
- [ ] Create OrderService.listByUser() with cursor pagination

### API Layer
- [ ] Create OrderController.create() — POST /api/v1/orders
- [ ] Create OrderController.show() — GET /api/v1/orders/{id}
- [ ] Create OrderController.index() — GET /api/v1/orders

### Testing
- [ ] Unit test: OrderService.create() — happy path
- [ ] Unit test: OrderService.create() — duplicate idempotency key
- [ ] Unit test: OrderService.create() — invalid product
- [ ] Unit test: OrderService.create() — empty items
- [ ] Unit test: OrderService.getById() — ownership check
- [ ] Integration test: POST /api/v1/orders — full flow
- [ ] Integration test: GET /api/v1/orders — pagination

## Priority: Medium (should have)
- [ ] Add order confirmation endpoint (POST /api/v1/orders/{id}/confirm)
- [ ] Add order cancellation with business rules
- [ ] Add order history/audit log

## Priority: Low (nice to have)
- [ ] Add order search by date range
- [ ] Add order export to CSV

Правила составления fix plan

  1. Порядок зависимостей. Сущности перед репозиториями, репозитории перед сервисами, сервисы перед контроллерами.

  2. Атомарность. Каждый пункт = один файл или один метод. Не "Create OrderService" (слишком крупно), а "Create OrderService.create() with idempotency handling".

  3. Верифицируемость. К каждому пункту должна быть понятна проверка: компилируется, тесты проходят, линтер чист.

  4. Чеклист-формат. Агент ищет - [ ] и заменяет на - [x] после выполнения. Это позволяет отслеживать прогресс.


Шаг 4: Создание скрипта цикла

Теперь собираем всё вместе в исполняемый скрипт.

Базовый скрипт

#!/bin/bash
# ralph.sh - Autonomous development loop
set -euo pipefail

# Configuration
SPEC="spec.md"
AGENT="AGENT.md"
FIX_PLAN="fix_plan.md"
MAX_ITERATIONS=50
LOG_FILE="ralph.log"
ITERATION=0

# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo "$(date): Ralph Loop starting" | tee -a "$LOG_FILE"
echo "Max iterations: $MAX_ITERATIONS" | tee -a "$LOG_FILE"

while [ $ITERATION -lt $MAX_ITERATIONS ]; do
  ITERATION=$((ITERATION + 1))
  echo -e "\n${YELLOW}=== Loop iteration $ITERATION / $MAX_ITERATIONS ===${NC}" | tee -a "$LOG_FILE"

  # Check if there are remaining tasks
  REMAINING=$(grep -c "\- \[ \]" "$FIX_PLAN" 2>/dev/null || echo "0")
  if [ "$REMAINING" -eq 0 ]; then
    echo -e "${GREEN}All tasks complete! Total iterations: $ITERATION${NC}" | tee -a "$LOG_FILE"
    break
  fi
  echo "Remaining tasks: $REMAINING" | tee -a "$LOG_FILE"

  # Run the agent with combined prompt
  cat <<EOF | claude --print
Read the file @${AGENT} for project conventions and build commands.
Read the file @${SPEC} for the feature specification.
Read the file @${FIX_PLAN} for the current task list.

## Instructions

1. Find the FIRST unchecked task (- [ ]) in ${FIX_PLAN}
2. Search the codebase to understand existing patterns and code
3. Implement ONLY that single task following project conventions
4. Run the test/build commands from AGENT.md to verify your changes
5. If all checks pass:
   - Mark the task as done: change "- [ ]" to "- [x]" in ${FIX_PLAN}
   - Commit with a descriptive message
6. If checks fail:
   - Analyze the error
   - Fix the issue
   - Re-run checks
   - If you cannot fix after 3 attempts, add a note to ${FIX_PLAN}
EOF

  # Log iteration result
  COMPLETED=$(grep -c "\- \[x\]" "$FIX_PLAN" 2>/dev/null || echo "0")
  echo "$(date): Iteration $ITERATION complete. Tasks done: $COMPLETED, remaining: $REMAINING" | tee -a "$LOG_FILE"

  # Safety pause -- human can interrupt
  echo -e "${YELLOW}Press Ctrl+C to stop. Continuing in 5 seconds...${NC}"
  sleep 5
done

# Final report
echo -e "\n${GREEN}=== Ralph Loop Complete ===${NC}" | tee -a "$LOG_FILE"
echo "Total iterations: $ITERATION" | tee -a "$LOG_FILE"
echo "Tasks completed: $(grep -c '\- \[x\]' "$FIX_PLAN" 2>/dev/null || echo 0)" | tee -a "$LOG_FILE"
echo "Tasks remaining: $(grep -c '\- \[ \]' "$FIX_PLAN" 2>/dev/null || echo 0)" | tee -a "$LOG_FILE"

Продвинутый скрипт с контролем затрат

#!/bin/bash
# ralph-advanced.sh - Ralph Loop with cost tracking and safety
set -euo pipefail

# Configuration
MAX_ITERATIONS=100
MAX_COST_DOLLARS=25
BRANCH_PREFIX="ralph"
PAUSE_SECONDS=3
NOTIFY_ON_COMPLETE=true

# Create isolated branch
BRANCH="${BRANCH_PREFIX}/$(date +%Y%m%d-%H%M%S)"
echo "Working on branch: $BRANCH"

# Track start time
START_TIME=$(date +%s)

# Iteration loop
ITERATION=0
TOTAL_TOKENS=0

while [ $ITERATION -lt $MAX_ITERATIONS ]; do
  ITERATION=$((ITERATION + 1))

  # Check remaining tasks
  REMAINING=$(grep -c "\- \[ \]" fix_plan.md 2>/dev/null || echo "0")
  [ "$REMAINING" -eq 0 ] && {
    echo "All tasks complete!"
    break
  }

  # Estimate cost (rough: $0.03 per 1K input tokens, $0.15 per 1K output)
  # Simple heuristic: each iteration ~5K tokens = ~$0.50
  ESTIMATED_COST=$(echo "scale=2; $ITERATION * 0.50" | bc)
  if (( $(echo "$ESTIMATED_COST > $MAX_COST_DOLLARS" | bc -l) )); then
    echo "Cost limit reached: ~\$$ESTIMATED_COST > \$$MAX_COST_DOLLARS"
    break
  fi

  echo "=== Iteration $ITERATION | Remaining: $REMAINING | Est. cost: \$$ESTIMATED_COST ==="

  # Run agent
  cat PROMPT.md | claude --print 2>&1 | tee -a ralph.log

  # Brief pause for human interrupt opportunity
  sleep $PAUSE_SECONDS
done

# Calculate duration
END_TIME=$(date +%s)
DURATION=$(( (END_TIME - START_TIME) / 60 ))

# Final report
cat <<REPORT

========================================
  Ralph Loop Summary
========================================
  Branch:      $BRANCH
  Iterations:  $ITERATION
  Duration:    ${DURATION} minutes
  Est. cost:   ~\$$(echo "scale=2; $ITERATION * 0.50" | bc)
  Completed:   $(grep -c '\- \[x\]' fix_plan.md 2>/dev/null || echo 0) tasks
  Remaining:   $(grep -c '\- \[ \]' fix_plan.md 2>/dev/null || echo 0) tasks
========================================

REPORT

# Send notification if enabled
if [ "$NOTIFY_ON_COMPLETE" = true ]; then
  # macOS notification
  osascript -e 'display notification "Ralph Loop завершён" with title "Ralph Loop"' 2>/dev/null || true
fi

Шаг 5: Мониторинг цикла

Запустить цикл -- только полдела. Нужно отслеживать его работу, особенно первые 5-10 итераций.

Что мониторить

# Terminal 1: Watch git log in real-time
watch -n 5 'git log --oneline -20'

# Terminal 2: Watch fix plan progress
watch -n 5 'echo "Done:"; grep -c "\[x\]" fix_plan.md; echo "Todo:"; grep -c "\[ \]" fix_plan.md'

# Terminal 3: Watch test results
watch -n 10 'npm test 2>&1 | tail -5'

# Terminal 4: Watch the ralph.log
tail -f ralph.log

Признаки здорового цикла

Признак Здоровый Проблемный
Коммиты Регулярные, каждые 1-3 минуты Нет коммитов > 10 минут
Тесты Проходят стабильно Постоянно падают
Fix plan Задачи закрываются Задачи добавляются быстрее, чем закрываются
Git diff Маленькие, фокусированные изменения Огромные диффы, много файлов
Лог Чистый вывод Повторяющиеся ошибки

Когда вмешиваться

Нажимайте Ctrl+C и берите управление, если:

  1. Агент зациклился. Одна и та же ошибка 3+ раза подряд
  2. Не те файлы. Агент модифицирует файлы, не связанные с текущей задачей
  3. Архитектурное решение. Агент делает выбор, который вы не одобряете
  4. Тесты красные > 5 минут. Агент не может починить тест

Продвинутые паттерны

Субагенты (Subagent Spawning)

В продвинутых реализациях основной агент может порождать "субагентов" для параллельных задач:

Основной агент (реализация)
  ├── Субагент 1: поиск по кодовой базе (readonly)
  ├── Субагент 2: генерация документации
  └── Субагент 3: написание тестов

Важное ограничение: субагенты не модифицируют код. Они выполняют вспомогательные задачи и передают результат основному агенту.

Самообновляющийся AGENT.md

Продвинутый паттерн, при котором агент дополняет собственные инструкции:

# In PROMPT.md, add rule:

## Learning Rule
If you discover a pattern in the codebase that is NOT documented in AGENT.md,
add it to the "## Discovered Patterns" section of AGENT.md.

Example: If you find that all repositories use a specific base class,
document it so future iterations know about it.

Это создаёт цикл обучения: каждая итерация потенциально улучшает инструкции для будущих итераций.

Автоматический откат

Если агент не может пройти тесты за N попыток, откат к последнему рабочему состоянию:

#!/bin/bash
# safe-iteration.sh - Single iteration with rollback safety

# Save current state
SAVE_POINT=$(git rev-parse HEAD)
MAX_RETRIES=3
RETRY=0

while [ $RETRY -lt $MAX_RETRIES ]; do
  RETRY=$((RETRY + 1))
  echo "Attempt $RETRY of $MAX_RETRIES"

  # Run agent
  cat PROMPT.md | claude --print

  # Check if tests pass
  if npm test 2>/dev/null; then
    echo "Tests pass! Proceeding."
    exit 0
  fi

  echo "Tests failed. Retry..."
done

# All retries exhausted -- rollback
echo "Max retries reached. Rolling back to $SAVE_POINT"
git checkout -- .
git clean -fd

# Mark task as blocked in fix plan
sed -i '' "s/^- \[ \] $(head -1 current_task.txt)/- [ ] [BLOCKED] $(head -1 current_task.txt)/" fix_plan.md

exit 1

Системы безопасности

Обязательные ограничения

При запуске Ralph Loop в автономном режиме необходимо установить защитные механизмы:

# ralph-config.yml - Safety configuration
safety:
  max_iterations: 50          # Hard stop after 50 iterations
  max_duration_hours: 4        # Hard stop after 4 hours
  max_cost_dollars: 25         # Hard stop at $25 API cost
  max_files_modified: 30       # Alert if more than 30 files changed

restrictions:
  - no_git_push               # Never push to remote
  - no_deploy                 # Never deploy
  - no_production_db          # Never touch production DB
  - no_external_api           # No calls to external production APIs
  - no_secrets_in_code        # Scan for leaked secrets

monitoring:
  log_file: ralph.log
  notify_on_failure: true      # macOS/Slack notification on failure
  notify_on_complete: true     # Notification when all tasks done
  pause_between_iterations: 3  # Seconds between iterations

Изоляция через ветки

# Always work on an isolated branch
BRANCH="ralph/feature-$(date +%s)"
# Agent works on $BRANCH
# Human reviews and merges to main
# If anything goes wrong: delete branch, no damage

Золотое правило безопасности: Автономный агент никогда не должен иметь возможность необратимо повредить проект. Работа на изолированной ветке + запрет push = нулевой риск.


Практические советы

Для начинающих

  1. Начните с малого. Первый Ralph Loop -- 3-5 простых задач (создать сущность, DTO, тест). Не пытайтесь автоматизировать целую фичу сразу.

  2. Наблюдайте внимательно. Первые 5-10 итераций -- смотрите в реальном времени. Понимайте, как агент работает с вашей кодовой базой.

  3. Улучшайте AGENT.md. Если агент делает что-то не так -- это пробел в AGENT.md. Добавьте правило и перезапустите.

  4. Гранулируйте задачи. Если задача занимает больше 5 минут -- разбейте на подзадачи.

Для опытных

  1. Оптимизируйте backpressure. Настройте инкрементальные проверки (только изменённые файлы) для максимальной скорости цикла.

  2. Используйте reference files. Укажите в AGENT.md "образцовые" файлы, по которым агент будет ориентироваться.

  3. Параллелизуйте. Запустите два агента: один для реализации, другой для тестов (на разных файлах).

  4. Автоматизируйте отчётность. Скрипт отправляет отчёт в Slack/Telegram после завершения цикла.

Чего избегать

Ошибка Последствие Решение
Слишком крупные задачи Агент теряется, генерирует некорректный код Разбить на 20-100 строк
Нет тестов Код "работает" только в воображении агента Добавить тесты перед запуском
Слабый AGENT.md Агент использует свои паттерны, не ваши Детальные конвенции с примерами
Нет паузы между итерациями Невозможно вовремя прервать Минимум 3-5 секунд паузы
Работа на main Рискуете основной веткой Всегда изолированная ветка

Чеклист запуска Ralph Loop

Перед каждым запуском пройдите этот чеклист:

## Pre-Launch Checklist

### Environment
- [ ] AI tool installed and authenticated
- [ ] Git repo clean (no uncommitted changes)
- [ ] Working on isolated branch (not main)
- [ ] All existing tests pass

### Documentation
- [ ] AGENT.md created with conventions and commands
- [ ] spec.md created with detailed feature specification
- [ ] fix_plan.md created with ordered atomic tasks
- [ ] Tasks ordered by dependency

### Safety
- [ ] Max iterations configured
- [ ] Cost limit set
- [ ] No git push allowed
- [ ] No deploy allowed
- [ ] Pause between iterations enabled

### Monitoring
- [ ] Log file configured
- [ ] Git log watching set up
- [ ] Fix plan progress tracking ready
- [ ] Notifications configured (optional)

### Ready?
- [ ] First 5 tasks reviewed manually
- [ ] AGENT.md tested with single task
- [ ] Rollback plan understood

Выводы

  1. Подготовка решает всё. 80% успеха Ralph Loop определяется качеством AGENT.md, спецификации и fix plan.

  2. Начните с ручного режима. Запустите одну итерацию вручную, убедитесь, что агент понимает конвенции, затем автоматизируйте.

  3. Безопасность не опциональна. Изолированная ветка, лимиты затрат, запрет push -- это не перестраховка, а необходимость.

  4. Мониторинг обязателен. Особенно первые 10 итераций. Агент может уйти не в ту сторону, и чем раньше вы это заметите, тем меньше времени потеряете.

  5. Итерируйте над процессом. Каждый запуск Ralph Loop учит вас писать лучший AGENT.md, лучшие спецификации и лучшие fix plans.