diff --git a/.beads/config.yaml b/.beads/config.yaml index f242785..03e75b3 100644 --- a/.beads/config.yaml +++ b/.beads/config.yaml @@ -42,7 +42,7 @@ # This setting persists across clones (unlike database config which is gitignored). # Can also use BEADS_SYNC_BRANCH env var for local override. # If not set, bd sync will require you to run 'bd config set sync.branch '. -# sync-branch: "beads-sync" +sync-branch: "claude/beads-sync" # Multi-repo configuration (experimental - bd-307) # Allows hydrating from multiple repositories and routing writes to the correct JSONL @@ -59,4 +59,4 @@ # - linear.url # - linear.api-key # - github.org -# - github.repo +# - github.repo \ No newline at end of file diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index fdf8ac8..e2c75c9 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,4 +1,5 @@ {"id":"claudev-0ax","title":"Создать config.yaml шаблон","description":"Создать шаблон конфигурации для целевого проекта\n\n**Файл:** templates/config.template.yaml\n\n**Содержимое:**\n```yaml\n# Claudev configuration\n# Копируется в .claudev/config.yaml при установке\n\nci: false # GitHub Actions CI\ncd: false # GitHub Actions CD (releases)\nmax_parallel_executors: 3 # Параллельных Executor'ов\n\ntimeouts:\n task: 10m # Таймаут на задачу\n user_input: 30m # Таймаут ожидания ответа user\n\nretry_limit: 3 # Попыток до эскалации\nlog_tokens: false # Логировать расход токенов\n\ncleanup:\n enabled: false # Удалять старые логи\n keep_days: 30 # Хранить N дней если enabled\n```\n\n**done_when:**\n- [ ] Файл templates/config.template.yaml создан\n- [ ] Все параметры из PROJECT.md включены\n- [ ] Комментарии на русском объясняют каждый параметр","status":"open","priority":1,"issue_type":"task","created_at":"2026-01-23T15:06:58.702022+03:00","created_by":"m","updated_at":"2026-01-23T16:50:26.854267+03:00"} +{"id":"claudev-100","title":"B3: Runtime dependency check","description":"Проверка зависимостей в начале orchestrator.sh.\n\n**Проблема:** Если jq/bd/claude удалены после install.sh — система ломается с непонятными ошибками.\n\n**Решение:**\n```bash\ncheck_dependencies() {\n local missing=()\n command -v bd \u0026\u003e/dev/null || missing+=(\"bd\")\n command -v claude \u0026\u003e/dev/null || missing+=(\"claude\")\n command -v jq \u0026\u003e/dev/null || missing+=(\"jq\")\n command -v git \u0026\u003e/dev/null || missing+=(\"git\")\n \n if [[ ${#missing[@]} -gt 0 ]]; then\n log \"FATAL\" \"Missing: ${missing[*]}\"\n exit 1\n fi\n}\n```\n\n**Вызов:** Самое начало orchestrator, до любой логики.\n\n**done_when:**\n- [ ] Функция check_dependencies() добавлена\n- [ ] Проверяет bd, claude, jq, git\n- [ ] Fail fast с понятным сообщением","status":"open","priority":1,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-01-25T06:47:58.550736049Z","created_by":"Claude","updated_at":"2026-01-25T06:47:58.550736049Z"} {"id":"claudev-11j","title":"Решить: user silence handling","description":"После таймаута Tech Writer сохраняет draft. При следующем запуске: автоматически показать вопрос или ждать команды?","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-23T11:26:05.653367+03:00","created_by":"m","updated_at":"2026-01-23T12:16:37.554973+03:00","closed_at":"2026-01-23T12:16:37.554973+03:00","close_reason":"Решено: см. PROJECT.md (23 января)"} {"id":"claudev-1at","title":"Подтвердить: безопасность secrets","description":"Предложение: агенты не читают .env, тесты через mocks, CI через GitHub Secrets, проверка на hardcoded secrets. Нужно подтверждение.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-23T11:26:05.540935+03:00","created_by":"m","updated_at":"2026-01-23T12:07:59.052158+03:00","closed_at":"2026-01-23T12:07:59.052158+03:00","close_reason":"Решено: средний уровень — .gitignore + gitleaks pre-commit + инструкции агентам"} {"id":"claudev-1dw","title":"test status","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-23T12:14:01.974254+03:00","created_by":"m","updated_at":"2026-01-23T12:14:07.059908+03:00","closed_at":"2026-01-23T12:14:07.059908+03:00","close_reason":"test"} @@ -18,6 +19,10 @@ {"id":"claudev-8b1","title":"Написать промпт: Analyst-Architecture","description":"Написать промпт Analyst-Architecture\n\n**Файл:** core/agents/analyst-architecture.md\n\n**Frontmatter:**\n```yaml\n---\nname: analyst-architecture\ndescription: Проверяет архитектуру, добавляет задачи\nmodel: sonnet\n---\n```\n\n**Роль:** Architecture аналитик. Проверяет структуру и паттерны.\n\n**Критические правила:**\n- ТОЛЬКО добавлять задачи\n- Добавлять label: added-by:analyst-architecture\n- НЕ дублировать работу главного Architect\n\n**Что проверять:**\n- Separation of concerns?\n- Single responsibility?\n- Dependency direction (внутрь)?\n- Coupling между модулями?\n- Naming conventions?\n- File structure consistency?\n- Code duplication risks?\n\n**Алгоритм:**\n1. Claim: bd update run-analyst-architecture --claim\n2. Прочитать SPEC.md и план\n3. Найти архитектурные проблемы\n4. Для каждой:\n```bash\nbd create --title=\"Architecture: \u003cпроблема\u003e\" --type=task --priority=2 --label=added-by:analyst-architecture\n```\n5. bd close run-analyst-architecture\n\n**done_when:**\n- [ ] Frontmatter с model: sonnet\n- [ ] Чеклист архитектурных аспектов\n- [ ] Формат задач с label\n- [ ] Логирование через log.sh","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-23T15:35:32.847592+03:00","created_by":"m","updated_at":"2026-01-23T16:57:52.380327+03:00"} {"id":"claudev-8fj","title":"Manager и оркестрация","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-22T17:27:44.838454+03:00","created_by":"m","updated_at":"2026-01-22T18:03:01.344082+03:00","closed_at":"2026-01-22T18:03:01.344082+03:00","close_reason":"Обсудили: Manager = Sonnet, stateless, определяет фазу по beads"} {"id":"claudev-95v","title":"Создать tech-writer.md агента","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-23T15:06:58.814443+03:00","created_by":"m","updated_at":"2026-01-23T15:36:04.826956+03:00","closed_at":"2026-01-23T15:36:04.826956+03:00","close_reason":"Дубликаты: заменены на детальные задачи 'Написать промпт'","dependencies":[{"issue_id":"claudev-95v","depends_on_id":"claudev-hkb","type":"blocks","created_at":"2026-01-23T15:07:11.963227+03:00","created_by":"m"}]} +{"id":"claudev-96","title":"A1: Auto-install beads в sandbox","description":"Создать core/scripts/ensure-beads.sh — автоустановка bd через Go build в ограниченных окружениях (iOS sandbox, CI).\n\n**Логика:**\n1. Проверить command -v bd\n2. Если нет — собрать через GOTOOLCHAIN=local CGO_ENABLED=0 go install\n3. Добавить в PATH\n4. Fallback с инструкцией\n\n**done_when:**\n- [ ] Скрипт ensure-beads.sh создан\n- [ ] Работает в sandbox без network\n- [ ] Вызывается из orchestrator.sh","status":"open","priority":1,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-01-25T06:47:11.821959291Z","created_by":"Claude","updated_at":"2026-01-25T06:47:11.821959291Z"} +{"id":"claudev-97","title":"A2: Обязательный sync задач в git","description":"Добавить в orchestrator.sh три точки синхронизации beads:\n\n1. **СТАРТ** — bd sync import (загрузить из git)\n2. **ПОСЛЕ ФАЗЫ** — bd sync export + git add\n3. **ЗАВЕРШЕНИЕ ИТЕРАЦИИ** — git commit\n\n**Почему после фазы:**\n- Атомарность — фаза либо завершена, либо нет\n- Меньше I/O операций\n- Коммит только в конце (не засоряем историю)\n\n**done_when:**\n- [ ] Import при старте orchestrator\n- [ ] Export после каждой фазы\n- [ ] Commit при finalize_iteration","status":"open","priority":1,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-01-25T06:47:23.392864498Z","created_by":"Claude","updated_at":"2026-01-25T06:47:23.392864498Z"} +{"id":"claudev-98","title":"A3: Detect sandbox mode","description":"Добавить функцию detect_environment() в orchestrator.sh.\n\n**Признаки sandbox:**\n- Нет write доступа к /usr/local/bin\n- Нет brew и нет apt\n- Нет network (curl github.com timeout)\n\n**Переменная:** CLAUDEV_ENV=normal|sandbox\n\n**Где используется:**\n- Установка зависимостей: brew/apt vs go build\n- GitHub PR: gh pr create vs local merge + warn\n- Network timeouts: 30s vs 5s\n\n**done_when:**\n- [ ] Функция detect_environment() добавлена\n- [ ] CLAUDEV_ENV экспортируется\n- [ ] Логируется при старте","status":"open","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-01-25T06:47:34.932905083Z","created_by":"Claude","updated_at":"2026-01-25T06:47:34.932905083Z"} +{"id":"claudev-99","title":"B1: Claude CLI health check","description":"Добавить проверку доступности Claude перед запуском агентов.\n\n**Проблема:** Если Claude недоступен — каждый агент висит 10 мин. 3 retry = 30+ мин впустую.\n\n**Решение:** Ping в начале каждого цикла:\n```bash\ncheck_claude_available() {\n timeout 10s claude --model haiku --print 'ping' \u0026\u003e/dev/null\n}\n```\n\n**Поведение при недоступности:**\n- Не crash, а sleep 60s и retry\n- Логируем WARN (не FATAL)\n- Система восстановится когда Claude вернётся\n\n**done_when:**\n- [ ] Функция check_claude_available() добавлена\n- [ ] Вызывается в начале каждого цикла\n- [ ] При fail — sleep 60s и continue","status":"open","priority":0,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-01-25T06:47:47.457492653Z","created_by":"Claude","updated_at":"2026-01-25T06:47:47.457492653Z"} {"id":"claudev-9j0","title":"Обновить orchestrator.sh под новые фазы и роли","description":"Переписать orchestrator под новую архитектуру\n\n**Файл:** core/scripts/orchestrator.sh\n\n**Новая логика:**\n\n1. **Lock file (single instance):**\n```bash\nLOCK_FILE=\".claudev/orchestrator.lock\"\nif [ -f \"$LOCK_FILE\" ]; then\n OLD_PID=$(cat \"$LOCK_FILE\")\n if kill -0 \"$OLD_PID\" 2\u003e/dev/null; then\n echo \"Already running (PID $OLD_PID)\"; exit 1\n else\n rm -f \"$LOCK_FILE\" # stale lock\n fi\nfi\necho $$ \u003e \"$LOCK_FILE\"\ntrap \"rm -f $LOCK_FILE\" EXIT\n```\n\n2. **Beads daemon check:**\n```bash\nbd sync --status || { log \"ORCHESTRATOR\" \"FATAL\" \"Beads daemon not running\"; exit 1; }\n```\n\n3. **Frontmatter parsing (модель агента):**\n```bash\nget_model() {\n local agent_file=$1\n grep \"^model:\" \"$agent_file\" | cut -d: -f2 | tr -d ' '\n}\n```\n\n4. **Timeout enforcement:**\n```bash\ntimeout 10m claude --model \"$MODEL\" -p \"...\"\n```\n\n5. **Мониторинг каждые 2h:**\n```bash\n# Логировать: \"Iteration running for Xh, Y tasks remaining\"\n```\n\n6. **Вызов detect-phase.sh** вместо логики в промпте\n\n7. **Использовать log.sh** вместо локальной функции log()\n\n**done_when:**\n- [ ] Lock file mechanism работает\n- [ ] Beads daemon проверяется при старте и каждые 10 циклов\n- [ ] Модель агента читается из frontmatter\n- [ ] Timeout 10m для каждого вызова claude\n- [ ] Использует ./scripts/detect-phase.sh\n- [ ] Использует source ./scripts/log.sh\n- [ ] Логирует через log \"ORCHESTRATOR\" \"EVENT\" \"message\"","status":"open","priority":1,"issue_type":"task","created_at":"2026-01-23T15:22:49.334544+03:00","created_by":"m","updated_at":"2026-01-23T16:50:59.036704+03:00","dependencies":[{"issue_id":"claudev-9j0","depends_on_id":"claudev-naw","type":"blocks","created_at":"2026-01-23T15:23:03.666885+03:00","created_by":"m"},{"issue_id":"claudev-9j0","depends_on_id":"claudev-rh5","type":"blocks","created_at":"2026-01-23T15:23:03.760924+03:00","created_by":"m"},{"issue_id":"claudev-9j0","depends_on_id":"claudev-qru","type":"blocks","created_at":"2026-01-23T16:23:59.059785+03:00","created_by":"m"}]} {"id":"claudev-a28","title":"Обновить run-helpers.sh → run-analysts.sh","description":"Переименовать и обновить скрипт запуска аналитиков\n\n**Файл:** core/scripts/run-analysts.sh (был run-helpers.sh)\n\n**Логика:**\n1. Получает список из 5 analysts: ux, security, ops, reliability, architecture\n2. Для каждого запускает в background:\n```bash\ntimeout 10m claude --model sonnet -p \"Следуй .claude/agents/analyst-$NAME.md\" \u0026\n```\n3. Ждёт завершения всех (wait)\n4. Не проверяет результат — это делает Manager через bd\n\n**Важно:**\n- НЕ создаёт задачи-триггеры (это делает Manager)\n- Просто запускает 5 процессов параллельно\n- Использует source ./scripts/log.sh для логирования\n\n**done_when:**\n- [ ] Файл переименован в run-analysts.sh\n- [ ] Запускает 5 analysts параллельно\n- [ ] Timeout 10m на каждого\n- [ ] Модель sonnet для всех\n- [ ] Логирует старт/финиш каждого","status":"open","priority":1,"issue_type":"task","created_at":"2026-01-23T15:22:49.105242+03:00","created_by":"m","updated_at":"2026-01-23T16:51:16.066075+03:00","dependencies":[{"issue_id":"claudev-a28","depends_on_id":"claudev-hkb","type":"blocks","created_at":"2026-01-23T15:23:03.478606+03:00","created_by":"m"},{"issue_id":"claudev-a28","depends_on_id":"claudev-rh5","type":"blocks","created_at":"2026-01-23T15:23:03.952374+03:00","created_by":"m"}]} {"id":"claudev-aak","title":"Роли и ответственности","notes":"Частично обсуждено: Tech Writer, Manager. Осталось: Architect, Analysts, Executors, Senior roles","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-22T17:27:44.418493+03:00","created_by":"m","updated_at":"2026-01-23T11:25:55.484894+03:00","closed_at":"2026-01-23T11:25:55.484894+03:00","close_reason":"Решено: MVP scope через Tech Writer, формат задачи (title/files/done_when), все роли определены"} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ceb2b98 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +CLAUDE.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fa22f9c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,43 @@ +# Changelog + +## [0.4] - 2026-01-24 + +### Added +- Architect обязан повышать версию и обновлять changelog в FINAL_REVIEW +- VERSION файл для хранения текущей версии (универсально для любого стека) +- SemVer: MAJOR (breaking) / MINOR (features) / PATCH (bugfixes) + +### Changed +- architect.md: расширена секция MODE: final_review с версионированием + +## [0.3] - 2026-01-24 + +### Added +- Auto-close features и epics когда все children завершены +- Новый скрипт `close-completed-parents.sh` +- Использует встроенную команду beads `bd epic close-eligible` + +### Changed +- orchestrator.sh вызывает auto-close каждый цикл (шаг 7) + +## [0.2] - 2026-01-24 + +### Added +- One-liner установка: `curl ... | bash` +- Полная автоустановка зависимостей (homebrew, beads, gh, jq, claude-code) +- Поддержка Windows через WSL (автоопределение + инструкции) +- README для пользователей + +### Changed +- Очистка .claudev/ от файлов разработки после установки +- Пользователь видит только рабочие файлы (core/, templates/, install.sh) + +## [0.1] - 2026-01-24 + +### Added +- Многоагентная система разработки +- 10 агентов: Tech Writer, Manager, Architect, Executor, Senior Executor, 5 Analysts +- Orchestrator с atomic lock, graceful shutdown +- Beads интеграция для управления задачами +- 7 фаз проекта: INIT → PLANNING → HELPERS → PLAN_REVIEW → IMPLEMENTATION → FINAL_REVIEW → DONE +- Архитектурный аудит: 19 угроз найдено и закрыто diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index a9f63a2..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,116 +0,0 @@ -# Claudev — Project Instructions - -## Что это за проект - -**Claudev** — многоагентная система автоматической разработки на базе Claude Code. - -Система позволяет запустить полностью автономную разработку проекта: менеджер координирует работу архитектора, кодеров, ревьюеров и помощников. Состояние хранится в Beads, работа идёт через bash orchestrator. - -## Текущая задача - -Мы дорабатываем прототип системы и приводим его к production-ready состоянию. - -**Цель:** система должна легко интегрироваться в любой проект через `git clone`. - -## Структура проекта - -``` -claudev/ -├── CLAUDE.md # ← Этот файл (инструкции для Claude Code) -├── core/ # Ядро системы -│ ├── agents/ # Шаблоны агентов (manager, architect, coder...) -│ ├── commands/ # Slash-команды (/start, /status) -│ └── scripts/ # Bash скрипты (orchestrator, claim-task...) -├── templates/ # Шаблоны для целевого проекта -│ ├── SPEC.template.md # Шаблон спецификации -│ └── CLAUDE.template.md # Шаблон CLAUDE.md для проекта -├── install.sh # Установщик в целевой проект -└── docs/ # Документация - └── architecture.md # Архитектура системы -``` - -## ВАЖНО: Работа с файлами агентов - -Файлы в `core/agents/*.md` — это **КОД ПРОЕКТА**, а не инструкции для текущей сессии Claude. - -При работе над claudev я редактирую эти файлы как обычный исходный код. Они станут инструкциями только когда система будет установлена в целевой проект и запущена через orchestrator. - -## Как система интегрируется в проект - -```bash -# В целевом проекте: -git clone git@github.com:user/claudev.git .claudev -.claudev/install.sh - -# Результат: -target-project/ -├── .claudev/ # Клонированное ядро -├── .claude/ # Симлинки на agents и commands -│ ├── agents -> ../.claudev/core/agents -│ └── commands -> ../.claudev/core/commands -├── scripts -> .claudev/core/scripts -├── SPEC.md # Спецификация проекта (заполняет пользователь) -└── CLAUDE.md # Project instructions -``` - -## Ключевые компоненты системы - -### Агенты (core/agents/) - -| Агент | Модель | Роль | -|-------|--------|------| -| manager | Sonnet | Координатор, хранит состояние в Beads, принимает решения | -| architect | Opus | Создаёт план из SPEC.md, назначает модели задачам | -| coder | По задаче | Реализует ОДНУ задачу за сессию | -| reviewer | Sonnet | Проверяет код, создаёт баг-репорты | -| analyst | Opus | Оценивает готовность плана | -| helper-* | Sonnet | Аудит плана (architecture, reliability, ux, ops) | - -### Скрипты (core/scripts/) - -| Скрипт | Назначение | -|--------|------------| -| orchestrator.sh | Главный цикл, пингует менеджера каждые N секунд | -| init-manager.sh | Инициализация состояния менеджера в Beads | -| claim-task.sh | Атомарный захват задачи (без race conditions) | -| detect-phase.sh | Определение текущей фазы проекта | -| run-helpers.sh | Параллельный запуск помощников | -| run-coders.sh | Параллельный запуск кодеров | - -### Фазы проекта - -``` -INIT → PLANNING → HELPERS → PLAN_REVIEW → IMPLEMENTATION → FINAL_REVIEW → DONE -``` - -## Зависимости - -- **Beads** — система управления задачами (bd CLI) -- **Claude Code** — CLI для запуска агентов -- **Bash** — для orchestrator и скриптов - -## Команды для разработки - -```bash -# Посмотреть текущую структуру -ls -la core/ - -# Протестировать скрипт -bash core/scripts/detect-phase.sh - -# Проверить синтаксис агента -cat core/agents/manager.md -``` - -## Текущий статус - -Базовая структура готова: -- [x] core/ — агенты, команды, скрипты -- [x] templates/ — шаблоны SPEC.md и CLAUDE.md -- [x] install.sh — установщик -- [x] docs/ — документация - -**Следующие шаги:** -- [ ] Протестировать интеграцию в тестовый проект -- [ ] Проверить работу orchestrator -- [ ] Доработать агентов по результатам тестов diff --git a/PROJECT.md b/PROJECT.md new file mode 100644 index 0000000..7d3905e --- /dev/null +++ b/PROJECT.md @@ -0,0 +1,1626 @@ +# Claudev — Project Context + +## Что это за проект + +**Claudev** — многоагентная система автоматической разработки на базе Claude Code. + +Система позволяет запустить полностью автономную разработку проекта: менеджер координирует работу архитектора, кодеров, ревьюеров и помощников. Состояние хранится в Beads, работа идёт через bash orchestrator. + +## Цель + +Система должна легко интегрироваться в любой проект через `git clone`. + +## Структура проекта + +``` +claudev/ +├── CLAUDE.md # Персональный ассистент (переносится между проектами) +├── PROJECT.md # ← Этот файл (контекст проекта) +├── core/ # Ядро системы +│ ├── agents/ # Шаблоны агентов (manager, architect, coder...) +│ ├── commands/ # Slash-команды (/start, /status) +│ └── scripts/ # Bash скрипты (orchestrator, claim-task...) +├── templates/ # Шаблоны для целевого проекта +│ ├── SPEC.template.md # Шаблон спецификации +│ └── CLAUDE.template.md # Шаблон CLAUDE.md для проекта +├── install.sh # Установщик в целевой проект +└── docs/ # Документация + └── architecture.md # Архитектура системы +``` + +## ВАЖНО: Работа с файлами агентов + +Файлы в `core/agents/*.md` — это **КОД ПРОЕКТА**, а не инструкции для текущей сессии Claude. + +При работе над claudev я редактирую эти файлы как обычный исходный код. Они станут инструкциями только когда система будет установлена в целевой проект и запущена через orchestrator. + +## Как система интегрируется в проект + +**One-liner установка:** +```bash +curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash +``` + +**Или вручную:** +```bash +git clone git@github.com:user/claudev.git .claudev +.claudev/install.sh + +# Результат: +target-project/ +├── .claudev/ # Клонированное ядро +├── .claude/ # Симлинки на agents и commands +│ ├── agents -> ../.claudev/core/agents +│ └── commands -> ../.claudev/core/commands +├── scripts -> .claudev/core/scripts +├── SPEC.md # Спецификация проекта (заполняет пользователь) +└── CLAUDE.md # Project instructions +``` + +## Ключевые компоненты системы + +### Агенты (core/agents/) + +| Агент | Модель | Роль | +|-------|--------|------| +| manager | Sonnet | Stateless координатор, определяет фазу по beads, единая точка входа | +| tech-writer | Opus | Собирает требования, задаёт вопросы, формирует SPEC.md | +| architect | Opus | Создаёт план, назначает модели задачам, расставляет dependencies | +| analyst-ux | Sonnet | Проверяет UX, добавляет задачи (только добавляет, не удаляет) | +| analyst-security | Sonnet | Проверяет безопасность, добавляет задачи | +| analyst-ops | Sonnet | Проверяет операционные аспекты, добавляет задачи | +| analyst-reliability | Sonnet | Проверяет надёжность, edge cases, добавляет задачи | +| analyst-architecture | Sonnet | Проверяет архитектуру, добавляет задачи | +| executor | По задаче | Реализует ОДНУ задачу, работает в своей git ветке | +| senior-executor | Opus | Последовательно валидирует код, мержит в main | + +### Формат промптов агентов + +Каждый файл агента (`core/agents/*.md`) содержит: + +```markdown +--- +name: agent-name +description: Краткое описание роли +model: opus|sonnet|haiku +--- + +# Роль: Название + +Краткое описание что делает агент. + +## КРИТИЧЕСКИЕ ПРАВИЛА +- Что НИКОГДА не делать +- Что ВСЕГДА делать первым + +## Алгоритм работы +1. Первый шаг (с примером команды) +2. Второй шаг +3. ... + +## Инструменты +- `bd` команды которые использует +- `git` операции если нужны +- Другие скрипты + +## Завершение +- Как агент понимает что закончил +- Что делает в конце (close задачи, log, etc.) +``` + +**Принципы написания промптов для LLM:** +- Простые изолированные команды (одна операция = одна команда) +- Явные примеры с `bd create`, `bd close`, `git commit` +- Чёткие критерии завершения +- Минимум условной логики (if/else) + +### Скрипты (core/scripts/) + +| Скрипт | Назначение | +|--------|------------| +| orchestrator.sh | Главный цикл, пингует менеджера каждые N секунд | +| detect-phase.sh | Определение текущей фазы проекта | +| run-analysts.sh | Параллельный запуск 5 analysts | +| run-executors.sh | Параллельный запуск executors (до MAX_PARALLEL) | +| close-completed-parents.sh | Auto-close features/epics когда все children done | +| log.sh | Хелпер для логирования в logs/claudev.log | + +**Устаревшие (удалить):** +- claim-task.sh — заменён на `bd update --claim` +- init-manager.sh — Manager stateless, не нужна инициализация +| run-helpers.sh | Параллельный запуск помощников | +| run-coders.sh | Параллельный запуск кодеров | + +### Фазы проекта + +``` +INIT → PLANNING → HELPERS → PLAN_REVIEW → IMPLEMENTATION → FINAL_REVIEW → DONE +``` + +## Зависимости + +- **Beads** — система управления задачами (bd CLI) +- **Claude Code** — CLI для запуска агентов +- **Bash** — для orchestrator и скриптов + +## Ключевые требования + +### Целевая аудитория +- Непрограммисты, которые могут чётко отвечать на вопросы +- От словесного описания → к готовому продукту + +### Принципы системы +- **Полная автономность** — не copilot, а отдел разработки +- **Итеративность** — MVP → доработка → доработка (не overthinking) +- **Короткие задачи** — каждый task в beads = 1-5 минут Sonnet +- **Персистентность** — всё в Beads, любой воркер может упасть + +### Пайплайн ролей +``` +Vision (заказчик) + ↓ +Tech Writer (собирает требования, задаёт вопросы, формирует ТЗ + config) + ↓ +Architect (план, разбивка на задачи, зависимости) + ↓ +Analysts (UX / Security / OPS / Reliability / Architecture) + ↓ +Architect (доработка плана по feedback аналитиков) + ↓ +Executors (реализация задач) + ↓ +Senior Executor (код ревью, merge, релиз) + ↓ +Architect (FINAL_REVIEW — проверка целостности) + ↓ +CI/CD GitHub (опционально) +``` + +### Управление процессом +- Manager в цикле (пока нет лучшего решения) +- Таймауты для управления падениями (задача > 10 мин = проблема) +- Beads как единственный источник правды + +--- + +## Текущий статус + +**Статус:** РЕАЛИЗАЦИЯ ЗАВЕРШЕНА (24 января 2026) + +Все 52 задачи закрыты. Система готова к использованию. + +**Реализовано:** +- ✅ core/agents/ — 10 промптов агентов (Tech Writer, Manager, Architect, Executor, Senior Executor, 5 Analysts) +- ✅ core/scripts/ — orchestrator.sh, detect-phase.sh, run-executors.sh, run-analysts.sh, close-completed-parents.sh, log.sh +- ✅ templates/ — config.template.sh, SPEC.template.md, CLAUDE.template.md +- ✅ install.sh — dependency check, git init, beads init, pre-commit hook, .gitignore +- ✅ docs/architecture.md — полная документация + +**Архитектурный аудит:** +- ✅ Первое прохождение (23 января): 10 угроз → решения #11-#20 +- ✅ Второе прохождение (24 января): 9 угроз → решения #21-#25 +- ✅ Все P0 блокеры закрыты (config validation, backpressure) + +**Следующий шаг:** Первый реальный запуск системы на тестовом проекте. + +**Обсуждено (22 января 2026):** +- ✅ Tech Writer — Opus, сам пишет в beads, режимы (новый/итерация) +- ✅ Manager — Sonnet, stateless, определяет фазу по beads +- ✅ Архитектура — subagents + beads, каждый агент сам пишет состояние +- ✅ Отказоустойчивость — retry 3x, эскалация к Architect, лимит 2 +- ✅ **Timeout enforcement:** + - Orchestrator запускает агентов через `timeout 10m claude -p "..."` + - При таймауте: процесс убивается, логируется, retry counter++ + - Retry history хранится в notes задачи: + ``` + retry 1: 2026-01-23 15:30 - timeout + retry 2: 2026-01-23 15:45 - timeout + ``` + - После 3 retry → эскалация к Architect +- ✅ UX — 4 статуса, варианты для user, clarification vs decision +- ✅ Итерации — SPEC.md с секциями Iteration N + +**Обсуждено (23 января 2026):** +- ✅ Senior Analyst — убран, избыточен +- ✅ Противоречия между аналитиками — решает Architect +- ✅ Приоритет: Security > UX (избыточные меры убираем итерациями) +- ✅ Аналитики только ДОБАВЛЯЮТ задачи, Architect может УДАЛЯТЬ (дубликаты, избыточность) +- ✅ Manager — единая точка координации, Architect не ждёт аналитиков сам +- ✅ Формат задачи в beads для Executor: + ``` + title: краткое описание (1-2 предложения) + files: какие файлы трогать (1-3) + done_when: чёткий критерий готовности + ``` +- ✅ Гранулярность задач — эвристика: "если есть 'и' — это 2 задачи", "больше 3 файлов — разбей" + +- ✅ Analysts — оставляем всех 5 (UX, Security, OPS, Reliability, Architecture). Дёшево запустить, дорого пропустить ошибки. + +- ✅ **Executors — git workflow:** + - Architect назначает модель (haiku/sonnet/opus) каждой задаче по сложности + - Architect расставляет dependencies для возможности параллельной работы + - Executor создаёт ветку `task/beads-xxx`, работает, коммитит + - Executor помечает задачу done → разблокирует зависимые + - **КРИТИЧНО:** Захват задачи ТОЛЬКО через `bd update --claim` + - ✅ Проверено: bd CLI гарантирует атомарность (fails if already claimed) + - Race condition между Executors невозможен + +- ✅ **Senior Executor (Opus):** + - Работает последовательно — quality gate перед merge + - Проверяет код, мержит через PR (не локальный merge): + - `gh pr create` из task/beads-xxx в main + - `gh pr merge --squash` после проверки + - GitHub гарантирует атомарность, при падении PR остаётся open + - После merge — cleanup веток: + - `git push origin --delete task/beads-xxx` + - `git branch -d task/beads-xxx` + - Merge conflict — сам решает, максимум эскалирует к Architect + - Если код плохой — НЕ закрывает задачу, возвращает в `bd ready` (меняет статус, обновляет description с причиной) + +- ✅ **Тестирование:** Architect включает тесты в задачу. "Сделай X + напиши тест" — Executor видит это в `done_when`. + +- ✅ **Старт системы (гибрид):** + - Если SPEC.md есть → Manager сразу к Architect + - Если SPEC.md нет → Manager запускает Tech Writer + - Tech Writer задаёт вопросы → формирует SPEC.md → потом Architect + +- ✅ **Финиш системы:** + - Manager проверяет: `bd list --status=open` = 0 (все задачи closed) + - Если да → фаза DONE, уведомление в логе + - Учитываются ВСЕ задачи, включая добавленные Analysts + +- ✅ **Взаимодействие с пользователем:** + - Terminal prompt (stdin/stdout) + - Интерактивный процесс — вопрос → ответ → возможны уточнения + - Система паузит пока не получит ответ + +- ✅ **MVP scope:** Tech Writer спрашивает "что минимум нужно для запуска?" + +- ✅ **Стек и язык:** Architect выбирает, если не указано в ТЗ на этапе Tech Writer + +- ✅ **CI/CD — опционально (GitHub Actions):** + - **CI есть:** Senior Executor после merge ждёт CI (`gh run watch`), CI failed → bug issue + - **CI нет:** Senior Executor проверяет только код + тесты локально + - **CD есть:** релиз через `gh release create` + - **CD нет:** релиз = merge в main + git tag + +- ✅ **Параллельность Executors:** + - Переменная `MAX_PARALLEL_EXECUTORS` (default: 3) + - Architect может переопределить в SPEC.md если нужно больше/меньше + +- ✅ **Бюджет:** + - Рассчитано на подписку MAX ($200/мес) + - ~2.5-3M токенов на итерацию — укладываемся с запасом + - Логируем расход для анализа (в будущем) + +- ✅ **Quality gate (Senior Executor проверяет):** + - Код ревью (обязательно) + - Тесты проходят (обязательно, локально) + - Линтинг (если настроен) + - Покрытие не упало (если настроено) + - CI green (если CI настроен) + - Сборка артефактов (если CD настроен) + +- ✅ **Логирование (детально):** + + **Структура:** + - Основной лог: `logs/claudev.log` — всё в одном месте для отладки + - Ротация по итерации: `mv logs/claudev.log logs/archive/iteration-N.log` (атомарно) + - Race condition safe: `log.sh` использует `>>` (append), создаёт новый файл если старый перемещён + + **Формат (plaintext, человекочитаемый):** + ``` + 2026-01-23 15:30:45 [AGENT] EVENT: описание + 2026-01-23 15:30:45 [MANAGER] PHASE: IMPLEMENTATION + 2026-01-23 15:30:46 [EXECUTOR] TASK_START: claudev-abc "Добавить кнопку" + 2026-01-23 15:35:12 [EXECUTOR] TASK_DONE: claudev-abc + 2026-01-23 15:35:13 [EXECUTOR] ERROR: git push failed - remote rejected + ``` + + **Что логируется (обязательно):** + - Старт/финиш каждого агента + - Переходы между фазами (INIT → PLANNING → ...) + - Задачи: взял (TASK_START), завершил (TASK_DONE), вернул (TASK_RETURNED) + - Git операции: commit, merge, revert, push + - Все ошибки с контекстом (ERROR: что случилось) + - Решения агентов (DECISION: почему выбрал X) + + **Что логируется (опционально, для анализа расхода):** + - Токены: `TOKENS: input=1234 output=567 total=1801` + - Включается через `config.yaml: log_tokens: true` + + **Хелпер для агентов:** + ```bash + # core/scripts/log.sh + log() { + local agent=$1 event=$2 message=$3 + echo "$(date '+%Y-%m-%d %H:%M:%S') [$agent] $event: $message" >> logs/claudev.log + } + # Использование: log "MANAGER" "PHASE" "IMPLEMENTATION" + ``` + + **Безопасность логов:** + - НИКОГДА не логировать: пароли, токены API, содержимое .env + - Логировать только ID задач, не полное содержимое + +- ✅ **Релизный процесс (после итерации):** + - Manager видит: все задачи closed (+ CI green если CI настроен) + - Определяется тип версии: bugfix→patch, feature→minor, breaking→major + - Обновляется version в package.json / mix.exs / etc. + - Генерируется CHANGELOG.md из closed задач итерации + - Создаётся git tag + - **Если CD настроен:** `gh release create` с артефактами + - **Если CD нет:** итерация завершена, tag в main + +- ✅ **Secrets и безопасность (средний уровень):** + - `.gitignore`: .env, .env.*, *.pem, *.key, credentials.*, secrets/ + - Pre-commit hook: `gitleaks protect --staged` (install.sh добавляет) + - Для тестов — mocks, не реальные API + - CI использует GitHub Secrets (агенты их не видят) + - Инструкция агентам: "НИКОГДА не читай .env, не логируй secrets, не пиши secrets в beads" + - Senior Executor проверяет diff на паттерны: sk-, api_key=, password= + - **Остаточный риск:** агент технически может прочитать .env — митигируем инструкциями + - **Pre-commit hook fail:** не пропускаем, считаем как обычный fail → retry → эскалация к Architect + +- ✅ **Merge conflicts:** + - Простой конфликт (разные места) — Senior Executor решает сам + - Семантический (одна функция) — откладывает merge, создаёт задачу для Architect + - Architect решает: переписать или объединить + +- ✅ **Rollback при проблемах после merge:** + - **Если CI есть и упал:** Senior Executor делает `git revert`, задача → open с "CI failed: [error]" + - **Если CI нет:** Senior Executor проверяет тесты локально ДО merge, rollback не нужен + - Executor получает задачу снова с контекстом ошибки + +- ✅ **User silence (таймаут 30 мин):** + - Tech Writer сохраняет draft, завершается + - При следующем запуске: Manager автоматически показывает незакрытый вопрос user'у + +- ✅ **Кто делает релиз:** Senior Executor + - Логичное продолжение: проверил → замержил → CI passed → релиз + +- ✅ **Статусы задач в beads:** + - `open` → задача создана, ждёт исполнителя + - `in_progress` → Executor работает (через `bd update --claim`) + - `in_progress` + label `needs-review` → Executor закончил, ждёт Senior Executor + - `closed` → Senior Executor замержил, CI passed + - `open` (возврат) → CI failed после merge, задача вернулась с ошибкой в notes + +- ✅ **Конфигурация проекта:** + - **Bootstrap:** install.sh копирует `templates/config.template.yaml` → `.claudev/config.yaml` + - Tech Writer может обновить config если user хочет CI/CD + - Система стартует с defaults, не блокируется на отсутствии конфига + - Defaults: + ```yaml + ci: false + cd: false + max_parallel_executors: 3 + timeouts: + task: 10m + user_input: 30m + retry_limit: 3 + log_tokens: false + cleanup: + enabled: false # по умолчанию храним всё + keep_days: 30 # если enabled: удаляем старше 30 дней + ``` + - **Cleanup** (если enabled): `find logs/archive stats -mtime +$KEEP_DAYS -delete` + +- ✅ **Приоритет задач:** + - `bd ready` сортирует по приоритету (P0 → P4) + - Executor берёт первую из списка + - Manager НЕ назначает задачи — избыточно + +- ✅ **Атомарный claim задачи:** (проверено в bd CLI) + - Executor использует `bd update --claim` + - Beads гарантирует атомарность (fails if already claimed) + - Если занято — Executor берёт следующую задачу + - Race condition между параллельными Executors невозможен + +- ✅ **Лимит эскалаций исчерпан:** + - После 2 эскалаций → задача получает label `blocked:escalation-limit` + - В `notes` задачи — полная история: что пробовали, почему не получилось + - Зависимое дерево автоматически блокируется (через deps) + - Система продолжает работать по независимым задачам + - В финальном отчёте — секция "Blocked tasks" с объяснениями + +- ✅ **Лимит времени итерации:** + - Жёсткого лимита нет — большой проект может легитимно занять много часов + - Лимиты через retry/эскалации уже защищают от зависания + - **Мониторинг:** + - Каждые 2h: `log "ORCHESTRATOR" "INFO" "Iteration running for Xh, Y tasks remaining"` + - Если ВСЕ оставшиеся задачи blocked: `log "ORCHESTRATOR" "WARN" "All remaining tasks blocked, stopping"` → система останавливается + - User может посмотреть лог и остановить вручную если нужно + +- ✅ **Circular dependencies:** + - Architect после создания задач запускает `bd dep cycles` + - Если есть циклы — исправляет сам + - Manager перепроверяет перед переходом в IMPLEMENTATION (safety net) + +- ✅ **Senior Executor — последовательный by design:** + - Quality gate перед main — параллелить нельзя (race conditions, конфликты) + - Очередь PR = система работает быстрее чем можем безопасно мержить + - Bottleneck здесь — фича, не баг + +- ✅ **Tech Writer — подход к SPEC.md:** + - SPEC.md — результат диалога, не заполнение шаблона + - Tech Writer адаптируется под клиента, а не наоборот + - **Если Architect не понимает SPEC.md:** + - Создаёт задачу: `bd create --title="Clarify SPEC.md: <что непонятно>" --type=task --priority=0` + - Логирует и завершает работу + - Manager видит P0 → запускает Tech Writer + - Tech Writer читает reason, задаёт user уточняющий вопрос + - **Поведение:** + - Слушает что хочет клиент + - Задаёт уточняющие вопросы по неясным местам + - Предлагает популярные решения если клиент не знает: + - "Обычно для такого используют PostgreSQL, подойдёт?" + - "Для авторизации чаще всего JWT или сессии. Вам важна разница?" + - Не требует ответа на всё — неопределённое отдаёт Architect + - **Валидация перед передачей Architect:** + - Не "есть ли секция X", а: + - Понятно ЧТО система должна делать? + - Понятно ДЛЯ КОГО? + - Понятно что МИНИМУМ нужно для первого релиза? + - Если да — структурирует и передаёт + - **Результат:** Architect получает хорошо структурированную суть, не формальный документ + +- ✅ **Beads daemon down:** + - Система падает, пишет user + - Не пытаемся работать без sync — это путь к потере данных + - **Проверка:** Orchestrator вызывает `bd sync --status` + - При старте (обязательно) + - В цикле каждые 10 итераций (не каждый раз, чтобы не замедлять) + - При падении: `log "ORCHESTRATOR" "FATAL" "Beads daemon not running"` + exit 1 + +- ✅ **Single instance (lock file):** + - Orchestrator при старте создаёт `.claudev/orchestrator.lock` с PID + - Если lock есть и процесс жив (`kill -0`) → exit "already running" + - Если lock от мёртвого процесса → stale lock, удаляем и продолжаем + - `trap "rm -f .claudev/orchestrator.lock" EXIT` для cleanup + - **Stale lock recovery** (при SIGKILL trap не срабатывает): + ```bash + if [ -f "$LOCK_FILE" ]; then + OLD_PID=$(cat "$LOCK_FILE") + if kill -0 "$OLD_PID" 2>/dev/null; then + echo "Orchestrator already running (PID $OLD_PID)"; exit 1 + else + echo "Removing stale lock file"; rm -f "$LOCK_FILE" + fi + fi + ``` + +- ✅ **Merge conflicts (промпт Senior Executor):** + - Мержить по приоритету задач (P0 первым) + - Pull перед каждым merge (свежий main) + - Простой конфликт (разные файлы/места) — решает сам + - Семантический конфликт (один кусок кода) — откладывает merge, создаёт задачу для Architect + +- ✅ **Подписка и статистика:** + - Используем Claude Code Max 20x + - Таймаутов достаточно для защиты от зависаний + - После итерации генерируется `stats/iteration-N.yaml`: + ```yaml + tokens: + total: 125000 + by_role: + manager: 5000 + tech_writer: 15000 + architect: 25000 + analysts: 30000 + executors: 40000 + senior_executor: 10000 + tasks: + total: 24 + completed: 22 + blocked: 2 + time: + start: 2026-01-23T10:00:00 + end: 2026-01-23T12:30:00 + ``` + +- ✅ **Завершение фазы HELPERS (analysts):** + - Manager перед запуском создаёт 5 задач-триггеров: + - `run-analyst-ux`, `run-analyst-security`, `run-analyst-ops`, `run-analyst-reliability`, `run-analyst-architecture` + - Запускает 5 агентов параллельно через `timeout 10m` + - Каждый analyst: claim своей задачи → работа → close + - Manager проверяет: все 5 closed → переход в PLAN_REVIEW + - **Timeout handling:** + - `timeout` убивает зависший процесс + - Задача-триггер остаётся open (analyst не успел close) + - Manager в следующем цикле видит: "4 closed, 1 open" → перезапускает только зависшего + - Retry counter в notes задачи-триггера + - После 3 retry → эскалация к Architect + +- ✅ **Фаза PLAN_REVIEW:** + - Analysts создают задачи БЕЗ dependencies (только `--label=added-by:analyst-*`) + - Architect в PLAN_REVIEW расставляет deps для новых задач + - Manager создаёт задачу-триггер `run-plan-review` + - Architect: + 1. Claim `run-plan-review` + 2. Находит задачи: `bd list --label=added-by:analyst-*` + 3. Убирает дубликаты: `bd close --reason="Дубликат claudev-xxx"` + 4. Разрешает противоречия: `bd close --reason="Противоречит Security: ..."` + 5. Close `run-plan-review` + - Manager видит closed → переход в IMPLEMENTATION + +- ✅ **Коммиты Executor:** + - Один коммит в конце работы (перед close задачи) + - Задачи короткие (1-5 мин), потеря при падении = перезапуск + - Retry 3x покрывает случайные падения + - Не усложняем промежуточными коммитами + +- ✅ **Rebase перед push (Executor):** + - Перед push Executor делает: + ```bash + git fetch origin main + git rebase origin/main + git push --force-with-lease -u origin task/beads-xxx + ``` + - `--force-with-lease` — безопасно перезаписывает личную ветку при retry + - Простой конфликт (разные файлы) — решает сам + - Сложный конфликт (семантический) — эскалация к Architect + - Senior Executor получает уже актуальные ветки + +- ✅ **Идемпотентность агентов (git/gh ошибки):** + - **Общее правило для ВСЕХ агентов:** + - При ошибке git/gh команды: логируем, НЕ меняем статус задачи, завершаем работу + - Manager перезапустит в следующем цикле + - Агент должен быть идемпотентным — повторный запуск даёт тот же результат + - **Executor при старте (идемпотентность):** + ```bash + git fetch origin + git branch -D task/beads-xxx 2>/dev/null # удаляем локальную если есть + git checkout -b task/beads-xxx origin/main + ``` + - **Потеря при падении:** максимум 1-5 минут работы (задачи короткие) — приемлемо + +- ✅ **Фаза FINAL_REVIEW:** + - Architect проверяет целостность результата перед релизом + - Не дублирует Senior Executor (тот проверяет каждый PR отдельно) + - **Что проверяет:** + - Все features из SPEC.md реализованы? + - Архитектура соответствует изначальному плану? + - Нет пропущенных edge cases? + - **Если всё ок:** подтверждает готовность → переход в DONE + - **Если проблемы:** создаёт задачи на доработку → обратно в IMPLEMENTATION + +- ✅ **Запуск агентов (формат команды):** + ```bash + # Статичный промпт + динамический контекст + timeout 10m claude --model sonnet --print << EOF + $(cat .claude/agents/manager.md) + + --- + PROJECT_ROOT: $(pwd) + CURRENT_PHASE: $(./scripts/detect-phase.sh) + EOF + ``` + - Промпт агента — файл (версионируется, редактируется) + - Контекст — добавляется в конце через heredoc + - `--print` — результат в stdout для логирования + - Для Executor: добавляется `TASK_ID` и `TASK: $(bd show $TASK_ID --format=yaml)` + +- ✅ **Модель для Executor:** + - Architect назначает через label: `model:haiku`, `model:sonnet`, `model:opus` + - run-executors.sh парсит: `bd show $TASK_ID --format=json | jq ...` + - Если label нет → default `sonnet` + +- ✅ **Интерактивность vs цикл orchestrator:** + - **INIT фаза** (Tech Writer) — интерактивный режим, без timeout, stdin/stdout напрямую + - **Остальные фазы** — автономный режим, с timeout, параллельные агенты + - Orchestrator умеет работать в обоих режимах (switch по фазе) + - User silence 30min — внутри Tech Writer (сам следит, завершается с draft) + +- ✅ **install.sh (cold start, recovery):** + - Git нет → `git init` автоматически + - Remote нет → спрашивает: добавить URL или работать локально + - Beads CLI нет → ошибка с инструкцией (не можем установить за пользователя) + - Beads не инициализирован → `bd init` автоматически + - Атомарность: собираем во temp dir, потом move + - Идемпотентность: повторный запуск безопасен + +- ✅ **Graceful shutdown:** + - `trap cleanup SIGINT SIGTERM` в orchestrator + - cleanup: SIGTERM детям → ждём 10s → SIGKILL если завис → rm lock + - Задачи `in_progress` остаются — это ОК + - При старте orchestrator сбрасывает все `in_progress` → `open` с notes "Reset: orchestrator restart" + - Идемпотентность агентов покрывает повторный запуск + +--- + +## Архитектурные решения + +**Контекст:** Перед стартом реализации прогнали архитектурный чеклист (failure modes, bottlenecks, data flow, edge cases) и закрыли все найденные пробелы. + +### 1. Draft Tech Writer — привязка к задаче + +**Проблема:** User тайм-аут, Tech Writer должен сохранить draft и завершиться. Но как продолжить при возврате? + +**Решение:** `SPEC.draft.md` + путь в notes задачи + +**Workflow:** +```bash +# Tech Writer при timeout: +echo "..." > SPEC.draft.md +bd update --notes="Draft saved: SPEC.draft.md. Awaiting user input." +bd close + +# Manager следующая итерация: +if [ -f SPEC.draft.md ] && user_active; then + bd create --title="Finalize SPEC from draft + user input" --type=task +fi +``` + +**Чеклист:** +- ✅ Failure: Tech Writer упал → draft в файле + notes указывает путь +- ✅ Data flow: draft → notes → Manager → new task +- ✅ Edge case: User удалил draft → новый Tech Writer начинает с нуля +- ✅ LLM-friendly: простые команды, явный маркер (файл + notes) + +--- + +### 2. Iteration numbering — timestamp вместо счётчика + +**Проблема:** `iteration.txt` с инкрементом → crash между инкрементом и архивацией → сломанная нумерация + +**Решение:** timestamp в имени файла, никакого state file + +**Workflow:** +```bash +mv logs/current.log "logs/archive/iteration-$(date +%Y%m%d-%H%M%S).log" +``` + +**Чеклист:** +- ✅ Failure: crash в любой момент → ничего не сломается, timestamp уникален +- ✅ Bottleneck: нет state file = нет race conditions +- ✅ Data flow: одна операция, атомарная +- ✅ Edge case: два mv одновременно (невозможно, orchestrator один) → разные timestamps +- ✅ LLM-friendly: одна команда, без арифметики + +--- + +### 3. Cleanup — раз в сутки по timestamp + +**Проблема:** cleanup при каждом старте orchestrator (iteration_delay=5min) → избыточные проверки ФС + +**Решение:** `.claudev/last_cleanup.txt` с timestamp, проверка раз в 24h + +**Workflow:** +```bash +LAST=$(cat .claudev/last_cleanup.txt 2>/dev/null || echo 0) +NOW=$(date +%s) +if [ $((NOW - LAST)) -gt 86400 ]; then # 24 hours + find logs/archive -mtime +$KEEP_DAYS -delete + echo $NOW > .claudev/last_cleanup.txt +fi +``` + +**Чеклист:** +- ✅ Failure: cleanup упал → last_cleanup.txt не обновился → попробует снова (OK) +- ✅ Bottleneck: проверка раз в сутки, не каждые 5 минут +- ✅ LLM-friendly: простая проверка, один state file + +--- + +### 4. Stats tokens — оценка по размеру + +**Проблема:** Claude Code не даёт детальную токен-статистику через API + +**Решение:** считаем chars, оцениваем tokens как `chars / 4` + +**Workflow:** +```bash +INPUT_CHARS=$(wc -c < prompts/architect.md) +OUTPUT_CHARS=$(wc -c < output.log) +ESTIMATED_TOKENS=$(( (INPUT_CHARS + OUTPUT_CHARS) / 4 )) + +cat > stats/iteration-$TIMESTAMP.yaml < --notes="Reviewed & released" +# 3. If FAIL: +bd create +bd close --notes="Review failed, fixes created" +# Manager sees fail → phase back to IMPLEMENTATION +``` + +**Чеклист:** +- ✅ Failure: review failed → нет висячей release task +- ✅ Edge case: нет промежуточного состояния +- ✅ LLM-friendly: одна задача = review + conditional release +- ✅ Изоляция: Senior Executor владеет всем процессом + +--- + +### 6. PR workflow — fail hard без remote + +**Проблема:** Local merge без PR = no code review, опасно автоматизировать + +**Решение:** если нет GitHub remote → error, остановка, ждём User + +**Workflow:** +```bash +if ! git remote -v | grep -q github; then + log "ERROR: No GitHub remote. Cannot auto-release. Manual action required." + exit 1 +fi + +gh pr create && gh pr merge +``` + +**Чеклист:** +- ✅ Edge case: локальный проект → явная ошибка, не silent fail +- ✅ Safety: не делаем то что может быть опасным (local merge без review) +- ✅ LLM-friendly: простая проверка + +--- + +### 7. Config reload — каждую итерацию + +**Проблема:** config read только при старте → срочные изменения применяются через iteration_delay (может быть 30+ минут) + +**Решение:** orchestrator читает config в начале каждой итерации + +**Workflow:** +```bash +while true; do + source .claudev/config.yaml # read fresh config + log "Iteration started with config: iteration_delay=$ITERATION_DELAY" + + detect_phase + run_agents + + sleep $ITERATION_DELAY +done +``` + +**Чеклист:** +- ✅ Data flow: config → iteration start → применяется сразу +- ✅ Предсказуемость: изменения применяются максимум через iteration_delay +- ✅ Edge case: срочные изменения → User останавливает orchestrator и перезапускает +- ✅ LLM-friendly: одна команда `source` + +--- + +### 8. GitHub remote — early detection + graceful degradation + +**Проблема:** Если нет GitHub remote → система работает до Senior Executor → падает при merge + +**Решение:** Проверка в начале (Manager INIT) + локальный merge как fallback + +**Workflow:** +```bash +# Manager при первом запуске (INIT фаза): +if ! git remote -v | grep -q github; then + log "WARN" "No GitHub remote detected. Final merge will require manual action." + bd create --title="Setup GitHub remote for automated PR workflow" \ + --type=task --priority=4 --label=optional +fi + +# Senior Executor при merge: +if ! git remote -v | grep -q github; then + log "INFO" "No GitHub remote. Performing local merge (no PR review)." + git checkout main + git merge --no-ff task/beads-$TASK_ID + git push || log "WARN" "Cannot push to remote. Manual push required." +else + gh pr create && gh pr merge +fi +``` + +**Чеклист:** +- ✅ Failure: User узнаёт о проблеме в начале, не в конце +- ✅ Edge case: локальные проекты работают (merge без PR) +- ✅ LLM-friendly: простая проверка + if/else +- ✅ Safety: опциональная задача P4 для настройки remote + +--- + +### 9. Executor rebase conflicts — всегда эскалировать + +**Проблема:** LLM плохо классифицирует "простой vs сложный" конфликт → риск неправильного разрешения + +**Решение:** Любой rebase conflict → abort + эскалация к Architect + +**Workflow:** +```bash +# Executor при rebase: +git fetch origin main +git rebase origin/main + +if [ $? -ne 0 ]; then + git rebase --abort + log "WARN" "Rebase conflict detected, escalating to Architect" + + bd update $TASK_ID --status=open \ + --notes="Rebase conflict with main. Files: $(git diff --name-only origin/main...HEAD)" + + bd create --title="Resolve conflict: $TASK_TITLE" \ + --type=task --priority=0 --assignee=architect + + exit 0 # Штатная эскалация, не ошибка +fi + +git push --force-with-lease -u origin task/beads-$TASK_ID +``` + +**Чеклист:** +- ✅ Failure: Executor не принимает решения о конфликтах (меньше риска) +- ✅ LLM-friendly: простейшая логика (failed? → abort + escalate) +- ✅ Safety: Architect (Opus) с полным контекстом разрешает любой конфликт +- ✅ Data flow: конфликт → open task → P0 для Architect + +--- + +### 10. Stats tokens — измерять input, оценивать output + +**Проблема:** Claude Code output в stdout смешан с системными сообщениями → сложно парсить точно + +**Решение:** Измерять input chars, оценивать output (~50% от input), считать tokens через `/4` + +**Workflow:** +```bash +# Orchestrator при запуске агента: +run_agent() { + local agent=$1 model=$2 task_id=$3 + + # Формируем промпт во temp файл + local prompt_file=".claudev/prompts/${agent}-${task_id}.txt" + cat ".claude/agents/${agent}.md" > "$prompt_file" + echo -e "\n---\nTASK_ID: $task_id\n..." >> "$prompt_file" + + # Считаем input + local input_chars=$(wc -c < "$prompt_file") + + # Запускаем (output в общий лог) + { + echo "=== AGENT START: $agent (task: $task_id) ===" + timeout 10m claude --model $model --print < "$prompt_file" + echo "=== AGENT END: $agent ===" + } | tee -a logs/claudev.log + + # Логируем stats + log "STATS" "RUN" "agent=$agent model=$model input_chars=$input_chars task=$task_id" + + rm "$prompt_file" +} + +# Stats script (конец итерации): +grep "STATS.*RUN" logs/claudev.log | \ + awk '{ + for(i=1;i<=NF;i++) { + if($i ~ /input_chars=/) { + split($i,a,"="); total += a[2] + } + } + } END { + estimated_output = total * 0.5 + estimated_tokens = (total + estimated_output) / 4 + print "input_chars: " total + print "estimated_output_chars: " estimated_output + print "estimated_tokens: " int(estimated_tokens) + }' > stats/iteration-$(date +%Y%m%d-%H%M%S).yaml +``` + +**Чеклист:** +- ✅ Data flow: промпт → temp файл → измерение → запуск → cleanup +- ✅ Failure: падение агента → input залогирован (log перед запуском) +- ✅ LLM-friendly: простые команды (cat, wc, awk) +- ✅ Точность: ~60%, достаточно для планирования бюджета (не billing) + +--- + +### 11. Orchestrator lock — atomic через noclobber (FINAL) + +**Проблема:** Race condition при параллельном старте — два процесса могут создать lock file одновременно + +**Решение:** Atomic file creation через `set -C` (noclobber mode) + +**Workflow:** +```bash +LOCK_FILE=".claudev/orchestrator.lock" + +# Atomic lock: noclobber fails если файл существует +if ! (set -C; echo $$ > "$LOCK_FILE") 2>/dev/null; then + # Lock exists, check if stale + OLD_PID=$(cat "$LOCK_FILE" 2>/dev/null || echo "0") + if kill -0 "$OLD_PID" 2>/dev/null; then + echo "Orchestrator already running (PID $OLD_PID)" + exit 1 + else + echo "Removing stale lock (PID $OLD_PID not found)" + rm -f "$LOCK_FILE" + # Retry once + if ! (set -C; echo $$ > "$LOCK_FILE") 2>/dev/null; then + echo "Failed to acquire lock (race with another process?)" + exit 1 + fi + fi +fi + +trap "rm -f '$LOCK_FILE'" EXIT +``` + +**Чеклист:** +- ✅ Race condition невозможен (atomic FS operation) +- ✅ Stale lock detection (kill -0 проверка) +- ✅ Graceful cleanup (trap EXIT) +- ✅ LLM-friendly: простая логика + +--- + +### 12. Config — bash напрямую (FINAL) + +**Проблема:** YAML parsing сложен, race conditions с timestamp, нужна синхронизация + +**Решение:** Отказ от YAML, config.sh напрямую (bash syntax) + +**Workflow:** +```bash +# .claudev/config.sh (User редактирует напрямую) +CI_ENABLED=false +CD_ENABLED=false +MAX_PARALLEL_EXECUTORS=3 +TASK_TIMEOUT="10m" +USER_INPUT_TIMEOUT="30m" +RETRY_LIMIT=3 +LOG_TOKENS=false +CLEANUP_ENABLED=false +CLEANUP_KEEP_DAYS=30 + +# Orchestrator просто source: +source .claudev/config.sh +``` + +**Чеклист:** +- ✅ Нет парсинга (меньше кода, меньше багов) +- ✅ Нет race conditions (атомарный read) +- ✅ User-friendly (bash синтаксис простой, комментарии в файле) +- ✅ Reload каждую итерацию без доп. логики + +--- + +### 13. GitHub check — через gh CLI с fallback (FINAL) + +**Проблема:** `grep github` не ловит enterprise/custom domains, что если gh CLI не установлен? + +**Решение:** Проверка через gh CLI + graceful fallback к local merge + +**Workflow:** +```bash +# Хелпер для проверки +check_github_pr_available() { + command -v gh &>/dev/null && gh auth status &>/dev/null +} + +# Senior Executor при merge: +if check_github_pr_available; then + gh pr create --fill + gh pr merge --squash --auto +else + log "INFO" "No gh CLI or not authenticated, performing local merge" + git checkout main + git merge --no-ff "task/beads-$TASK_ID" + git push 2>/dev/null || log "WARN" "Cannot push (no remote or no access)" +fi +``` + +**Чеклист:** +- ✅ Ловит любые варианты GitHub (enterprise, custom) +- ✅ Проверяет наличие gh CLI + авторизацию +- ✅ Graceful degradation (local merge если gh недоступен) +- ✅ LLM-friendly: простая функция-хелпер + +--- + +### 14. Beads daemon — проверка каждую итерацию (FINAL) + +**Проблема:** Редкая проверка (каждые 10 итераций) → daemon упал → работаем без sync → data loss + +**Решение:** Проверка в начале КАЖДОЙ итерации (дёшево, критично) + +**Workflow:** +```bash +while true; do + # 1. Check daemon (fast, ~10-50ms) + if ! bd sync --status &>/dev/null; then + log "FATAL" "Beads daemon not running. Run: bd daemon start" + exit 1 + fi + + # 2. Load config + source .claudev/config.sh + + # 3. Detect phase & run agents + ... + + sleep "$ITERATION_DELAY" +done +``` + +**Чеклист:** +- ✅ Fail fast (защита от data loss) +- ✅ Дёшево (~10-50ms overhead) +- ✅ Критично (sync обязателен для корректности) + +--- + +### 15. Executor rebase — WIP commit для сохранности (FINAL) + +**Проблема:** Conflict → abort → вся работа потеряна (задачи маленькие, но гарантия не помешает) + +**Решение:** WIP commit перед rebase + squash в конце (clean history) + +**Workflow:** +```bash +# 1. WIP commit (сохраняем работу) +git add -A +git commit -m "WIP: task-$TASK_ID (pre-rebase)" + +# 2. Rebase +git fetch origin main +if ! git rebase origin/main; then + # Conflict detected + git rebase --abort + + log "WARN" "Rebase conflict, escalating to Architect" + + # Работа сохранена в WIP commit, можно push + git push --force-with-lease -u origin "task/beads-$TASK_ID" + + # Эскалация + bd create --title="Resolve rebase conflict: $TASK_TITLE" \ + --type=task --priority=0 --assignee=architect \ + --notes="Branch: task/beads-$TASK_ID, conflicts with main" + + bd update "$TASK_ID" --status=blocked --label=needs-rebase + exit 0 +fi + +# 3. Squash WIP commit (clean history) +git reset --soft HEAD~1 +git commit -m "$COMMIT_MESSAGE" +git push --force-with-lease -u origin "task/beads-$TASK_ID" + +bd update "$TASK_ID" --label=needs-review +``` + +**Чеклист:** +- ✅ Работа НИКОГДА не теряется (WIP commit) +- ✅ Clean history в итоге (squash перед push) +- ✅ Architect получает ветку с работой +- ✅ Не усложняет (~5 строк кода) + +--- + +### 16. Executors backpressure — лимит open PR (FINAL) + +**Проблема:** Executors создают PR быстрее чем Senior Executor мержит → очередь растёт бесконечно + +**Решение:** Queue limit через MAX_PARALLEL_EXECUTORS + +**Workflow:** +```bash +# run-executors.sh перед запуском: +OPEN_PRS=$(gh pr list --state open --json number --jq 'length' 2>/dev/null || echo 0) + +if [ "$OPEN_PRS" -ge "$MAX_PARALLEL_EXECUTORS" ]; then + log "INFO" "PR queue full ($OPEN_PRS/$MAX_PARALLEL_EXECUTORS), waiting" + exit 0 +fi + +# Иначе запускаем новых Executors +... +``` + +**Чеклист:** +- ✅ Natural flow control (Senior Executor мержит → слот освобождается) +- ✅ Bottleneck управляется автоматически +- ✅ LLM-friendly: простая проверка + +--- + +### 17. Stats tokens — простая оценка для статистики (FINAL) + +**Проблема:** Claude Code не даёт точную токен-статистику, нужна хотя бы оценка + +**Решение:** Простой подсчёт chars → tokens (для info, не для billing) + +**Workflow:** +```bash +# Orchestrator при запуске агента: +run_agent() { + local prompt_file=".claudev/prompts/${agent}-${task_id}.txt" + + # Формируем промпт + cat ".claude/agents/${agent}.md" > "$prompt_file" + echo -e "\n---\nTASK_ID: $task_id\n..." >> "$prompt_file" + + # Считаем input + local input_chars=$(wc -c < "$prompt_file") + local estimated_tokens=$((input_chars / 4)) + + # Запускаем + timeout 10m claude --model $model --print < "$prompt_file" | tee -a logs/claudev.log + + # Логируем stats + echo "$agent,$input_chars,$estimated_tokens" >> stats/current-iteration.csv + + rm "$prompt_file" +} +``` + +**Чеклист:** +- ✅ Простая оценка (примерная, но достаточно) +- ✅ CSV для постобработки +- ✅ LLM-friendly: одна команда wc + +--- + +### 18. Graceful shutdown — smart reset (5min threshold) (FINAL) + +**Проблема:** Сбрасываем все `in_progress` → дублирование работы если агент успел close но мы не увидели + +**Решение:** Reset только старых задач (>5min), свежие оставляем + +**Workflow:** +```bash +cleanup() { + log "INFO" "Shutting down gracefully..." + + # SIGTERM детям (даём время завершиться) + pkill -P $$ -TERM + sleep 5 + pkill -P $$ -KILL 2>/dev/null + + # Reset только старых задач (>5min in_progress) + for task_id in $(bd list --status=in_progress --format=json | jq -r '.[].id'); do + claimed_ts=$(bd show "$task_id" --format=json | jq -r '.updated_at') + claimed_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "$claimed_ts" +%s 2>/dev/null || date -d "$claimed_ts" +%s) + now_epoch=$(date +%s) + age=$((now_epoch - claimed_epoch)) + + if [ "$age" -gt 300 ]; then # 5 minutes + log "INFO" "Resetting stale task $task_id (age: ${age}s)" + bd update "$task_id" --status=open --notes="Reset: stale at shutdown (${age}s old)" + else + log "INFO" "Keeping recent task $task_id (age: ${age}s)" + fi + done + + rm -f "$LOCK_FILE" + exit 0 +} + +trap cleanup SIGINT SIGTERM +``` + +**Чеклист:** +- ✅ Свежие задачи (<5min) не трогаем +- ✅ Старые задачи (>5min) сбрасываем +- ✅ Minimal duplication + +--- + +### 19. Tech Writer draft — TTL 24h (FINAL) + +**Проблема:** Draft устаревает (user вернулся через 2 недели), но Manager пытается продолжить + +**Решение:** TTL 24h + архивация старых drafts + +**Workflow:** +```bash +# Manager при INIT фазе: +if [ -f SPEC.draft.md ]; then + draft_age=$(( $(date +%s) - $(stat -f %m SPEC.draft.md 2>/dev/null || stat -c %Y SPEC.draft.md) )) + + if [ "$draft_age" -gt 86400 ]; then + # Draft >24h old + log "INFO" "Found old draft (${draft_age}s old), archiving" + mv SPEC.draft.md "SPEC.draft.$(date +%Y%m%d).old" + + # Start fresh + bd create --title="Gather requirements (fresh start)" \ + --type=task --assignee=tech-writer --priority=0 + else + # Draft fresh, continue + bd create --title="Finalize SPEC from draft" \ + --type=task --assignee=tech-writer --priority=0 \ + --notes="Continue from SPEC.draft.md" + fi +fi +``` + +**Чеклист:** +- ✅ 24h TTL (разумный баланс) +- ✅ Старый draft архивируется (не теряется) +- ✅ User видит что началось заново + +--- + +### 20. Circular dependencies — check после каждого add (FINAL) + +**Проблема:** Architect добавляет deps пачкой → цикл обнаруживается поздно, сложно откатить + +**Решение:** Инструкция в промпте — проверка после КАЖДОЙ зависимости + +**Промпт Architect (секция dependencies):** +```markdown +## Добавление зависимостей + +**КРИТИЧНО:** Проверяй cycles ПОСЛЕ КАЖДОЙ зависимости: + +```bash +# Для каждой пары: +bd dep add + +# СРАЗУ проверяем +if bd dep cycles 2>&1 | grep -q "cycle"; then + echo "ERROR: Cycle detected with last dependency" + bd dep remove + # Пересмотри dependency graph +fi +``` + +**Если cycles detection failed после всех deps:** +1. Выведи граф: `bd dep graph` +2. Найди цикл вручную +3. Удали одну зависимость из цикла +4. Залогируй: почему удалил именно эту +``` + +**Чеклист:** +- ✅ Обнаруживаем цикл сразу (easy rollback) +- ✅ Architect знает какая зависимость создала проблему +- ✅ LLM-friendly (простая инструкция) + +--- + +### 21. Iteration lock concept — одна итерация за раз (FINAL) + +**Проблема:** Timestamp collision в logs, параллельные итерации могут сломать состояние + +**Решение:** Концептуально: одна итерация = один orchestrator процесс = один lock file + +**Гарантии:** +- Orchestrator.lock (решение #11) уже обеспечивает единственность процесса +- Одна итерация = от старта orchestrator до фазы DONE (или stop) +- Параллельные итерации невозможны (atomic lock) +- Timestamp в logs = время архивации, не нумерация итераций + +**Workflow:** +```bash +# Orchestrator lock уже защищает от параллельного запуска +# При завершении итерации (фаза DONE): +mv logs/claudev.log "logs/archive/iteration-$(date +%Y%m%d-%H%M%S).log" +mv stats/current-iteration.md "stats/iteration-$(date +%Y%m%d-%H%M%S).md" +``` + +**Чеклист:** +- ✅ Параллельные итерации невозможны (lock file) +- ✅ Timestamp collision невозможен (одна итерация за раз) +- ✅ Каждая итерация = один релиз + +--- + +### 22. Stats format — Markdown вместо CSV (FINAL) + +**Проблема:** CSV без header, сложно читать, нет контекста + +**Решение:** Markdown report с таблицами и метриками + +**Workflow:** +```bash +# stats/iteration-TIMESTAMP.md +cat > stats/iteration-$(date +%Y%m%d-%H%M%S).md </dev/null || missing+=("beads") + command -v gh &>/dev/null || missing+=("gh") + command -v gitleaks &>/dev/null || missing+=("gitleaks") + command -v claude &>/dev/null || missing+=("claude-code") + + if [ ${#missing[@]} -gt 0 ]; then + echo "Missing dependencies: ${missing[*]}" + echo "" + echo "Install commands:" + [[ " ${missing[*]} " =~ " beads " ]] && echo " npm install -g @beadsland/beads" + [[ " ${missing[*]} " =~ " gh " ]] && echo " brew install gh # or: apt install gh" + [[ " ${missing[*]} " =~ " gitleaks " ]] && echo " brew install gitleaks # optional (security)" + [[ " ${missing[*]} " =~ " claude-code " ]] && echo " npm install -g @anthropic/claude-code" + echo "" + + if [ "$AUTO_INSTALL" = "true" ]; then + echo "Auto-installing npm packages..." + [[ " ${missing[*]} " =~ " beads " ]] && npm install -g @beadsland/beads + [[ " ${missing[*]} " =~ " claude-code " ]] && npm install -g @anthropic/claude-code + echo "Note: gh and gitleaks require manual install (brew/apt)" + else + echo "Run with --auto-install to install npm packages automatically" + exit 1 + fi + fi +} + +# Usage: ./install.sh [--auto-install] +``` + +**Чеклист:** +- ✅ Проверяет все критичные deps (beads, claude, gh, gitleaks) +- ✅ Показывает инструкции для установки +- ✅ Опционально auto-install npm пакетов (безопасно) +- ✅ Pre-commit hook добавляется только если gitleaks установлен + +--- + +### 25. SPEC.draft.md cleanup — mv при финализации (FINAL) + +**Проблема:** Tech Writer создаёт draft, кто удаляет после финализации? + +**Решение:** Tech Writer при успешном завершении перезаписывает + +**Workflow:** +```bash +# Tech Writer при timeout (30min): +cat > SPEC.draft.md </dev/null || echo "0.0.0" + +# 2. Определить тип (по closed задачам): +# - breaking changes → MAJOR +# - features → MINOR +# - bugfixes/tasks → PATCH + +# 3. Обновить VERSION +echo "0.3.0" > VERSION + +# 4. Сгенерировать CHANGELOG.md из closed задач + +# 5. Закоммитить +git add VERSION CHANGELOG.md +git commit -m "Release v$(cat VERSION)" + +# 6. Подтвердить +echo "FINAL_REVIEW: PASSED" +``` + +**Почему Architect (а не Senior Executor):** +- Architect знает что было сделано в итерации +- Architect понимает тип изменений (breaking/feature/bugfix) +- Senior Executor делает только technical release (tag, push) + +**Чеклист:** +- ✅ SemVer: MAJOR.MINOR.PATCH +- ✅ VERSION файл в корне (универсально для любого стека) +- ✅ CHANGELOG.md генерируется из closed задач +- ✅ Коммит "Release vX.Y.Z" перед PASSED + +**Workflow:** +```bash +# core/scripts/close-completed-parents.sh + +# 1. Закрываем features где все tasks closed +for feature_id in $(bd list --type=feature --status=open --json | jq -r '.[].id'); do + children=$(bd children "$feature_id" --json) + total=$(echo "$children" | jq 'length') + closed=$(echo "$children" | jq '[.[] | select(.status == "closed")] | length') + + if [ "$total" -gt 0 ] && [ "$total" = "$closed" ]; then + bd close "$feature_id" --reason="All $total children completed" + fi +done + +# 2. Закрываем epics (встроенная команда beads) +bd epic close-eligible +``` + +**Почему Manager + скрипт (а не Senior Executor или FINAL_REVIEW):** +- Не усложняет промпты агентов +- Скрипт изолирован, легко тестировать +- Использует встроенную команду beads для epics +- `bd stats` и `bd epic status` актуальны в любой момент +- Real-time не важен — закрытие каждый цикл (~5 мин) достаточно + +**Чеклист:** +- ✅ Features закрываются автоматически когда все tasks done +- ✅ Epics закрываются автоматически когда все features done +- ✅ LLM-friendly: агенты не знают об этой логике +- ✅ Порядок: сначала features, потом epics (правильная иерархия) + +--- + +**Отложено на следующие итерации:** +- [ ] OS Notifications (macOS/Linux) +- [ ] Webhook уведомления (Telegram, Slack) +- [ ] Автодокументация (README, API docs) diff --git a/README.md b/README.md new file mode 100644 index 0000000..23e0a25 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Claudev + +Виртуальный отдел разработки на базе AI. Опишите что хотите — получите готовый продукт. + +## Как это работает + +1. Вы описываете идею словами +2. AI-команда задаёт уточняющие вопросы +3. Архитектор создаёт план +4. Разработчики пишут код +5. Ревьюер проверяет качество +6. Вы получаете готовый проект + +Весь процесс автоматический. Вам нужно только отвечать на вопросы. + +## Установка + +Откройте терминал в папке вашего проекта и выполните: + +```bash +curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash +``` + +Установщик проверит зависимости и подскажет если чего-то не хватает. + +## Требования + +- macOS, Linux или Windows (через WSL) +- Всё остальное установится автоматически + +### Windows + +На Windows нужен WSL. Откройте PowerShell как администратор: + +```powershell +wsl --install +``` + +После перезагрузки откройте Ubuntu из меню Пуск и запустите команду установки. + +## Запуск + +После установки: + +```bash +./scripts/orchestrator.sh +``` + +Система спросит что вы хотите создать и начнёт работу. + +## Полезные команды + +```bash +bd ready # Посмотреть текущие задачи +bd list # Все задачи проекта +bd stats # Статистика +``` + +## Вопросы? + +Создайте issue в этом репозитории. diff --git a/core/agents/analyst-architecture.md b/core/agents/analyst-architecture.md new file mode 100644 index 0000000..cba2939 --- /dev/null +++ b/core/agents/analyst-architecture.md @@ -0,0 +1,65 @@ +--- +name: analyst-architecture +description: Анализирует архитектуру, структуру кода, зависимости +model: sonnet +--- + +# Роль: Analyst Architecture + +Ты Analyst Architecture — проверяешь план на архитектурные проблемы. Ищешь плохие зависимости, нарушения принципов. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты ТОЛЬКО ДОБАВЛЯЕШЬ задачи — НИКОГДА не удаляешь +2. Все твои задачи с label `added-by:analyst-architecture` +3. НЕ расставляй dependencies (это делает Architect) +4. После работы закрой свою trigger-задачу + +## Твой фокус + +- Separation of concerns +- Circular dependencies между модулями +- Coupling и cohesion +- Abstractions и interfaces +- Consistent naming +- File structure + +## Алгоритм + +### 1. Прочитай план + +```bash +bd list --format=json | jq '.[] | {id, title, description}' +``` + +### 2. Найди пропущенное + +Задай себе вопросы: +- Логична ли структура проекта? +- Нет ли циклических зависимостей? +- Соблюдается ли единый стиль? +- Достаточно ли абстракций? +- Не слишком ли большие модули? + +### 3. Создай задачи + +```bash +bd create --title="[Architecture] Extract API client to separate module" --type=task --priority=2 \ + --label=added-by:analyst-architecture --label=model:sonnet \ + --description="files: src/services/api.ts, src/lib/apiClient.ts +done_when: API client extracted, used by all services" +``` + +### 4. Закрой trigger + +```bash +bd close $TRIGGER_TASK --reason="Architecture analysis complete, added N tasks" +``` + +## Примеры задач + +- `[Architecture] Split large module into smaller units` +- `[Architecture] Add interface for external service` +- `[Architecture] Move shared types to common module` +- `[Architecture] Fix circular dependency between A and B` +- `[Architecture] Rename files to follow convention` diff --git a/core/agents/analyst-ops.md b/core/agents/analyst-ops.md new file mode 100644 index 0000000..05dfb1c --- /dev/null +++ b/core/agents/analyst-ops.md @@ -0,0 +1,66 @@ +--- +name: analyst-ops +description: Анализирует тестирование, деплой, мониторинг +model: sonnet +--- + +# Роль: Analyst OPS + +Ты Analyst OPS — проверяешь план на операционные аспекты. Ищешь пробелы в тестировании, деплое, мониторинге. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты ТОЛЬКО ДОБАВЛЯЕШЬ задачи — НИКОГДА не удаляешь +2. Все твои задачи с label `added-by:analyst-ops` +3. НЕ расставляй dependencies (это делает Architect) +4. После работы закрой свою trigger-задачу + +## Твой фокус + +- Тестирование: unit, integration, e2e +- CI/CD pipeline +- Деплой и rollback +- Мониторинг и alerting +- Логирование +- Health checks +- Документация для ops + +## Алгоритм + +### 1. Прочитай план + +```bash +bd list --format=json | jq '.[] | {id, title, description}' +``` + +### 2. Найди пропущенное + +Задай себе вопросы: +- Есть ли тесты для критичных функций? +- Как деплоить? Как откатить? +- Что мониторить? +- Как понять что сервис упал? +- Есть ли README для ops? + +### 3. Создай задачи + +```bash +bd create --title="[OPS] Add health check endpoint" --type=task --priority=2 \ + --label=added-by:analyst-ops --label=model:haiku \ + --description="files: src/api/health.ts +done_when: GET /health returns 200 with status" +``` + +### 4. Закрой trigger + +```bash +bd close $TRIGGER_TASK --reason="OPS analysis complete, added N tasks" +``` + +## Примеры задач + +- `[OPS] Add health check endpoint` +- `[OPS] Setup CI pipeline with GitHub Actions` +- `[OPS] Add integration tests for API` +- `[OPS] Create deployment documentation` +- `[OPS] Add error tracking (Sentry)` diff --git a/core/agents/analyst-reliability.md b/core/agents/analyst-reliability.md new file mode 100644 index 0000000..b30af6d --- /dev/null +++ b/core/agents/analyst-reliability.md @@ -0,0 +1,65 @@ +--- +name: analyst-reliability +description: Анализирует надёжность, edge cases, отказоустойчивость +model: sonnet +--- + +# Роль: Analyst Reliability + +Ты Analyst Reliability — проверяешь план на надёжность. Ищешь edge cases, race conditions, failure modes. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты ТОЛЬКО ДОБАВЛЯЕШЬ задачи — НИКОГДА не удаляешь +2. Все твои задачи с label `added-by:analyst-reliability` +3. НЕ расставляй dependencies (это делает Architect) +4. После работы закрой свою trigger-задачу + +## Твой фокус + +- Failure modes: что если сервис упадёт? +- Race conditions: параллельные операции +- Edge cases: пустые данные, большие данные, невалидные данные +- Retries и timeouts +- Graceful degradation +- Data consistency + +## Алгоритм + +### 1. Прочитай план + +```bash +bd list --format=json | jq '.[] | {id, title, description}' +``` + +### 2. Найди пропущенное + +Задай себе вопросы: +- Что если внешний сервис недоступен? +- Что если операция прервётся посередине? +- Что если данных слишком много? +- Что если данных нет? +- Есть ли timeout для долгих операций? + +### 3. Создай задачи + +```bash +bd create --title="[Reliability] Add timeout for external API calls" --type=task --priority=1 \ + --label=added-by:analyst-reliability --label=model:sonnet \ + --description="files: src/services/external.ts +done_when: all external calls have 10s timeout" +``` + +### 4. Закрой trigger + +```bash +bd close $TRIGGER_TASK --reason="Reliability analysis complete, added N tasks" +``` + +## Примеры задач + +- `[Reliability] Add retry logic for database connections` +- `[Reliability] Handle empty response from API` +- `[Reliability] Add circuit breaker for external service` +- `[Reliability] Limit batch size to prevent OOM` +- `[Reliability] Add graceful shutdown handler` diff --git a/core/agents/analyst-security.md b/core/agents/analyst-security.md new file mode 100644 index 0000000..b5d7e04 --- /dev/null +++ b/core/agents/analyst-security.md @@ -0,0 +1,68 @@ +--- +name: analyst-security +description: Анализирует безопасность и защиту данных +model: sonnet +--- + +# Роль: Analyst Security + +Ты Analyst Security — проверяешь план на проблемы безопасности. Ищешь уязвимости, незащищённые данные. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты ТОЛЬКО ДОБАВЛЯЕШЬ задачи — НИКОГДА не удаляешь +2. Все твои задачи с label `added-by:analyst-security` +3. НЕ расставляй dependencies (это делает Architect) +4. Security > всё остальное (твои задачи приоритетнее) +5. После работы закрой свою trigger-задачу + +## Твой фокус + +- OWASP Top 10: SQL injection, XSS, CSRF, etc. +- Authentication и authorization +- Секреты и credentials (не хардкодить) +- Input validation +- Rate limiting +- HTTPS, CORS +- Логирование (не логировать secrets) + +## Алгоритм + +### 1. Прочитай план + +```bash +bd list --format=json | jq '.[] | {id, title, description}' +cat SPEC.md +``` + +### 2. Найди пропущенное + +Задай себе вопросы: +- Как защищены endpoints? +- Проверяется ли input? +- Откуда берутся secrets? +- Есть ли rate limiting для public API? +- Логируются ли sensitive данные? + +### 3. Создай задачи + +```bash +bd create --title="[Security] Add input validation for user form" --type=task --priority=1 \ + --label=added-by:analyst-security --label=model:sonnet \ + --description="files: src/api/users.ts +done_when: all user inputs validated, sanitized" +``` + +### 4. Закрой trigger + +```bash +bd close $TRIGGER_TASK --reason="Security analysis complete, added N tasks" +``` + +## Примеры задач + +- `[Security] Add CSRF protection to forms` +- `[Security] Implement rate limiting for auth endpoints` +- `[Security] Remove hardcoded API keys` +- `[Security] Add input sanitization for user-generated content` +- `[Security] Enable HTTPS redirect` diff --git a/core/agents/analyst-ux.md b/core/agents/analyst-ux.md new file mode 100644 index 0000000..a6b45c5 --- /dev/null +++ b/core/agents/analyst-ux.md @@ -0,0 +1,64 @@ +--- +name: analyst-ux +description: Анализирует UX проблемы и пользовательские сценарии +model: sonnet +--- + +# Роль: Analyst UX + +Ты Analyst UX — проверяешь план на UX проблемы. Ищешь пропущенные сценарии, проблемы юзабилити. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты ТОЛЬКО ДОБАВЛЯЕШЬ задачи — НИКОГДА не удаляешь +2. Все твои задачи с label `added-by:analyst-ux` +3. НЕ расставляй dependencies (это делает Architect) +4. После работы закрой свою trigger-задачу + +## Твой фокус + +- Состояния UI: loading, error, empty, success +- Пользовательские сценарии: happy path и edge cases +- Cancel/undo flows +- Мобильная адаптация +- Обратная связь пользователю (feedback, notifications) +- Accessibility (a11y) + +## Алгоритм + +### 1. Прочитай план + +```bash +bd list --format=json | jq '.[] | {id, title, description}' +``` + +### 2. Найди пропущенное + +Задай себе вопросы: +- Что видит пользователь при загрузке? +- Что если данных нет? +- Что если ошибка? +- Как отменить действие? +- Работает ли на мобильном? + +### 3. Создай задачи + +```bash +bd create --title="[UX] Add loading state for user list" --type=task --priority=2 \ + --label=added-by:analyst-ux --label=model:sonnet \ + --description="files: src/components/UserList.tsx +done_when: loading spinner shows while fetching" +``` + +### 4. Закрой trigger + +```bash +bd close $TRIGGER_TASK --reason="UX analysis complete, added N tasks" +``` + +## Примеры задач + +- `[UX] Add empty state for dashboard` +- `[UX] Show error message on API failure` +- `[UX] Add confirmation dialog for delete action` +- `[UX] Improve mobile navigation` diff --git a/core/agents/analyst.md b/core/agents/analyst.md deleted file mode 100644 index 129ccfc..0000000 --- a/core/agents/analyst.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: analyst -description: Оценивает готовность плана к реализации -model: opus ---- - -# Роль: Аналитик - -Оцениваешь готовность плана и решаешь какие помощники нужны. - -## КРИТИЧЕСКИЕ ПРАВИЛА - -1. НЕ создаёшь задачи -2. НЕ изменяешь план -3. ОБЯЗАТЕЛЬНО возвращаешь JSON в конце - -## Алгоритм - -```bash -bd list --json | jq 'length' -bd list --json | jq '[.[] | select(.labels | any(startswith("source:")))] | length' -bd dep cycles -``` - -## Критерии готовности - -- Нет циклических зависимостей -- Каждая задача имеет model:* -- Есть задачи на тестирование -- Требования из SPEC.md покрыты - -## ОБЯЗАТЕЛЬНЫЙ JSON в конце ответа: - -```json -{ - "verdict": "READY", - "helpers_to_run": [], - "cycle": 1, - "reason": "План полный" -} -``` - -или - -```json -{ - "verdict": "NEEDS_REFINEMENT", - "helpers_to_run": ["ux", "ops"], - "cycle": 1, - "reason": "Не хватает UX состояний и тестов" -} -``` - -Помощники: arch, rel, ux, ops - -Максимум 2 цикла. Если cycle=2 — выдай READY. diff --git a/core/agents/architect.md b/core/agents/architect.md index 051e11c..9db9a1b 100644 --- a/core/agents/architect.md +++ b/core/agents/architect.md @@ -1,72 +1,288 @@ --- name: architect -description: Главный архитектор. Планирует, создаёт задачи, назначает модели. +description: Создаёт план, расставляет dependencies, ревьюит model: opus --- -# Роль: Архитектор +# Роль: Architect -Ты главный архитектор проекта. Отвечаешь за техническое видение, планирование и качество архитектуры. +Ты Architect — главный технический эксперт системы. Создаёшь план проекта, разбиваешь на задачи, расставляешь зависимости, разрешаешь конфликты. ## КРИТИЧЕСКИЕ ПРАВИЛА -1. ВСЕГДА задавай уточняющие вопросы перед планированием -2. Создавай задачи ТОЛЬКО в Beads через `bd create` -3. КАЖДОЙ задаче назначай модель через label: `-l model:opus|sonnet|haiku` -4. Выстраивай зависимости через `bd dep add` -5. Ставь milestone labels после завершения фаз +1. Ты НИКОГДА не пишешь код (это работа Executor) +2. Ты ВСЕГДА разбиваешь большие задачи на маленькие (1-5 минут каждая) +3. Ты ВСЕГДА расставляешь dependencies между задачами +4. Ты ВСЕГДА назначаешь модель каждой задаче (model:haiku/sonnet/opus) +5. При добавлении dependency — СРАЗУ проверяй cycles -## При создании плана (первый вызов) +## Режимы работы + +Смотри переменную MODE в контексте: +- `create_plan` — создание плана из SPEC.md +- `plan_review` — ревью добавлений от Analysts +- `final_review` — финальная проверка перед релизом +- `resolve_conflict` — разрешение конфликта при rebase + +--- + +## MODE: create_plan + +### 1. Прочитай SPEC.md -### Шаг 1: Изучи ТЗ ```bash cat SPEC.md ``` -### Шаг 2: Задай уточняющие вопросы СРАЗУ одним списком +### 2. Выбери стек (если не указан) + +- Для веба: выбирай проверенные стеки (Next.js, Rails, Phoenix) +- Для CLI: Go, Rust, Node.js +- Для API: выбирай по требованиям (REST/GraphQL) + +### 3. Разбей на задачи + +Эвристики: +- Если есть "и" в описании — это 2 задачи +- Если больше 3 файлов — разбей +- Каждая задача = 1-5 минут для LLM + +### 4. Создай задачи в beads + +```bash +bd create --title="Setup project structure" --type=task --priority=1 \ + --label=model:haiku --label=implementation \ + --description="files: package.json, tsconfig.json +done_when: npm install succeeds" + +bd create --title="Implement user model" --type=task --priority=1 \ + --label=model:sonnet --label=implementation \ + --description="files: src/models/user.ts, src/models/user.test.ts +done_when: tests pass" +``` + +### 5. Расставь dependencies + +**КРИТИЧНО:** Проверяй cycles ПОСЛЕ КАЖДОЙ зависимости! + +```bash +bd dep add + +# СРАЗУ проверяем +if bd dep cycles 2>&1 | grep -q "cycle"; then + echo "ERROR: Cycle detected!" + bd dep remove + # Пересмотри dependency graph +fi +``` + +### 6. Выбери модель для каждой задачи + +- `model:haiku` — простые задачи (config, boilerplate, docs) +- `model:sonnet` — стандартные задачи (CRUD, тесты, рефакторинг) +- `model:opus` — сложные задачи (архитектура, интеграции, безопасность) + +### 7. Пометь завершение планирования + +```bash +bd create --title="Planning complete" --type=task --label=milestone:planning-done +bd close +``` + +--- + +## MODE: plan_review + +### 1. Найди задачи от Analysts + +```bash +bd list --format=json | jq '.[] | select(.labels[]? | startswith("added-by:analyst-"))' +``` + +### 2. Удали дубликаты + +```bash +bd close --reason="Дубликат claudev-xxx" +``` + +### 3. Разреши противоречия -### Шаг 3: После получения ответов — создай план +Приоритет: Security > Reliability > UX > Performance ```bash -# Эпик -bd create "EPIC: [Название]" -t epic -p 0 +bd close --reason="Противоречит Security: ..." +``` -# Архитектурные задачи (Opus) -bd create "Спроектировать архитектуру" -t task -p 0 -l model:opus,phase:design +### 4. Расставь dependencies для новых задач -# Задачи реализации (Sonnet) -bd create "Реализовать модуль X" -t feature -p 1 -l model:sonnet,phase:impl +Новые задачи от Analysts не имеют deps — добавь их. -# Простые задачи (Haiku) -bd create "Настроить линтер" -t chore -p 2 -l model:haiku,phase:setup +### 5. Закрой trigger -# Зависимости -bd dep add bd-IMPL bd-DESIGN --type blocks +```bash +bd update run-plan-review --status=in_progress +# ... работа ... +bd close run-plan-review + +bd create --title="Plan reviewed" --type=task --label=milestone:plan-reviewed +bd close ``` -### Шаг 4: Поставь milestone +--- + +## MODE: final_review + +### 1. Проверь что все features реализованы + ```bash -EPIC_ID=$(bd list --json | jq -r '.[] | select(.type == "epic") | .id' | head -1) -bd label add "$EPIC_ID" "milestone:planning-done" +cat SPEC.md # Что было запланировано +bd list --status=closed # Что сделано ``` -## Критерии выбора модели +### 2. Проверь архитектуру + +- Соответствует ли код изначальному плану? +- Нет ли пропущенных edge cases? -| Тип задачи | Модель | -|------------|--------| -| Архитектура, сложные решения | opus | -| Стандартная разработка, тесты | sonnet | -| Рутина, конфиги, документация | haiku | +### 3. Если есть проблемы — создай задачи и выйди + +```bash +bd create --title="Fix: <описание проблемы>" --type=task --priority=0 +echo "FINAL_REVIEW: NEEDS_FIXES" +# НЕ продолжай к версионированию! +``` -## При ревью плана (после помощников) +### 4. Если всё ок — версионирование -1. `bd list --json` — все задачи -2. Проверь дублирование, зависимости, модели -3. `bd dep cycles` — циклические зависимости -4. Скорректируй если нужно +**ОБЯЗАТЕЛЬНО:** Перед завершением итерации ты должен повысить версию и обновить changelog. -## При финальном ревью +#### 4.1 Прочитай текущую версию -1. Проверь все задачи закрыты -2. Проверь тесты: `mix test` -3. Поставь: `bd label add "$EPIC_ID" "milestone:project-done"` +```bash +cat VERSION 2>/dev/null || echo "0.0.0" +``` + +#### 4.2 Определи тип изменений + +Проанализируй closed задачи этой итерации: + +```bash +bd list --status=closed --format=json | jq -r '.[] | "\(.type) \(.title)"' +``` + +Правила SemVer: +- **MAJOR** (X.0.0): есть breaking changes (label `breaking:` или явное нарушение обратной совместимости) +- **MINOR** (0.X.0): есть новые features (type=feature) +- **PATCH** (0.0.X): только bugfixes и tasks (type=bug, type=task) + +#### 4.3 Обнови VERSION + +```bash +# Пример: была 0.2.0, добавили features → 0.3.0 +echo "0.3.0" > VERSION +``` + +#### 4.4 Сгенерируй CHANGELOG.md + +Формат: + +```bash +cat > CHANGELOG_NEW.md << 'EOF' +# Changelog + +## [0.3.0] - $(date +%Y-%m-%d) + +### Added +- <новые features из bd list> + +### Changed +- <изменения из bd list> + +### Fixed +- + +EOF + +# Добавь старый changelog (без первой строки "# Changelog") +tail -n +3 CHANGELOG.md >> CHANGELOG_NEW.md 2>/dev/null || true +mv CHANGELOG_NEW.md CHANGELOG.md +``` + +#### 4.5 Закоммить версию + +```bash +git add VERSION CHANGELOG.md +git commit -m "Release v$(cat VERSION)" +``` + +#### 4.6 Подтверди завершение + +```bash +echo "FINAL_REVIEW: PASSED" +echo "VERSION: $(cat VERSION)" +``` + +--- + +## MODE: resolve_conflict + +### 1. Получи контекст + +```bash +bd show $TASK_ID +git diff --name-only origin/main...HEAD +git log --oneline origin/main...HEAD +``` + +### 2. Реши конфликт + +```bash +git checkout task/beads-$TASK_ID +git fetch origin main +git rebase origin/main +# Разреши конфликты вручную +git add . +git rebase --continue +git push --force-with-lease +``` + +### 3. Обнови задачу + +```bash +bd update $TASK_ID --status=open --notes="Conflict resolved, ready for executor" +``` + +--- + +## Эскалации к тебе + +Ты получаешь эскалации от: +- Executor (после 3 retry) +- Senior Executor (сложный merge conflict) +- Manager (circular dependencies) + +При эскалации: +1. Прочитай notes задачи — там история +2. Прими решение +3. Либо реши сам, либо разбей на подзадачи + +## Формат задачи + +```yaml +title: краткое описание (1-2 предложения) +description: | + files: file1.ts, file2.ts + done_when: чёткий критерий +labels: + - model:sonnet + - implementation +``` + +## Лимит эскалаций + +Если задача эскалировалась 2 раза — пометь как blocked: + +```bash +bd update $TASK_ID --label=blocked:escalation-limit \ + --notes="Escalation limit reached. History: ..." +``` diff --git a/core/agents/coder.md b/core/agents/coder.md deleted file mode 100644 index 52a5c19..0000000 --- a/core/agents/coder.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: coder -description: Реализует задачи из плана -model: dynamic ---- - -# Роль: Кодер - -Реализуешь ОДНУ задачу из Beads. - -## КРИТИЧЕСКИЕ ПРАВИЛА - -1. ТОЛЬКО ОДНА задача за сессию -2. После завершения — ОСТАНОВИСЬ -3. НЕ бери следующую задачу сам -4. Всегда пиши тесты - -## Алгоритм - -1. Получи задачу (передадут ID или используй claim): -```bash -TASK_JSON=$(./scripts/claim-task.sh "coder-$$") -TASK_ID=$(echo "$TASK_JSON" | jq -r '.id') -``` - -2. Изучи: `bd show $TASK_ID --json` - -3. Реализуй + тесты - -4. Проверь: `mix test` - -5. При блокере: -```bash -bd update $TASK_ID --status blocked -bd create "BLOCKER: описание" -t bug -p 0 -l blocker -``` - -6. После успеха: -```bash -git add . && git commit -m "feat($TASK_ID): описание" -bd close $TASK_ID --reason "Реализовано" -bd sync -``` - -7. ОСТАНОВИСЬ diff --git a/core/agents/executor.md b/core/agents/executor.md new file mode 100644 index 0000000..3404005 --- /dev/null +++ b/core/agents/executor.md @@ -0,0 +1,139 @@ +--- +name: executor +description: Реализует одну задачу в своей git ветке +model: по задаче (label model:*) +--- + +# Роль: Executor + +Ты Executor — реализуешь ОДНУ задачу из beads. Работаешь в своей git ветке, коммитишь, пушишь. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты работаешь ТОЛЬКО над ОДНОЙ задачей (TASK_ID из контекста) +2. Ты ВСЕГДА работаешь в своей ветке `task/beads-{TASK_ID}` +3. Ты НИКОГДА не мержишь в main (это работа Senior Executor) +4. Ты НИКОГДА не читаешь .env и не логируешь secrets +5. При любой git ошибке — НЕ меняй статус задачи, просто завершись + +## Алгоритм работы + +### 1. Получи задачу + +```bash +TASK_ID="${TASK_ID}" # Из контекста +bd show $TASK_ID +``` + +### 2. Создай ветку (идемпотентно) + +```bash +git fetch origin +git branch -D "task/beads-$TASK_ID" 2>/dev/null || true +git checkout -b "task/beads-$TASK_ID" origin/main +``` + +### 3. Прочитай что нужно сделать + +Из description задачи: +- `files:` — какие файлы трогать +- `done_when:` — критерий готовности + +### 4. Реализуй + +- Пиши чистый код +- Следуй существующему стилю проекта +- Добавь тесты если указано в done_when +- НИКОГДА не добавляй .env, credentials, secrets + +### 5. WIP commit (сохраняем работу) + +```bash +git add -A +git commit -m "WIP: task-$TASK_ID (pre-rebase)" +``` + +### 6. Rebase на main + +```bash +git fetch origin main +if ! git rebase origin/main; then + # Конфликт — abort и эскалируй + git rebase --abort + + # Работа сохранена в WIP commit + git push --force-with-lease -u origin "task/beads-$TASK_ID" + + # Эскалация к Architect + bd create --title="Resolve rebase conflict: $TASK_TITLE" \ + --type=task --priority=0 --assignee=architect \ + --notes="Branch: task/beads-$TASK_ID, conflicts with main" + + bd update $TASK_ID --status=open --label=needs-rebase + exit 0 +fi +``` + +### 7. Squash и финальный commit + +```bash +git reset --soft HEAD~1 +git commit -m "$(cat </dev/null || stat -c %Y SPEC.draft.md) )) + if [ "$draft_age" -gt 86400 ]; then + mv SPEC.draft.md "SPEC.draft.$(date +%Y%m%d).old" + echo "Old draft archived, starting fresh" + fi +fi + +# Запускаем Tech Writer (интерактивный режим, без timeout) +claude --model opus --print < .claude/agents/tech-writer.md +``` + +### PLANNING +Есть SPEC.md, нужен план. Запускаем Architect. + +```bash +timeout 10m claude --model opus --print < /dev/null 2>&1; then + bd create --title="run-analyst-$analyst" --type=task --priority=1 + fi +done + +# Запускаем analysts +./scripts/run-analysts.sh ``` -### PHASE:HELPERS -Нужен аудит помощников. Запусти всех: +### PLAN_REVIEW +Analysts закончили, Architect ревьюит добавления. + ```bash -./scripts/run-helpers.sh +# Проверяем что все analyst triggers closed +OPEN_TRIGGERS=$(bd list --status=open --format=json | jq '[.[] | select(.title | startswith("run-analyst-"))] | length') +if [ "$OPEN_TRIGGERS" -gt 0 ]; then + echo "Waiting for analysts to complete ($OPEN_TRIGGERS remaining)" + exit 0 +fi + +# Создаём trigger для plan review +if ! bd list --format=json | jq -e '.[] | select(.title == "run-plan-review")' > /dev/null 2>&1; then + bd create --title="run-plan-review" --type=task --priority=0 +fi + +# Запускаем Architect для ревью +timeout 10m claude --model opus --print <&1 | grep -q "cycle"; then + bd create --title="Resolve circular dependencies" --type=task --priority=0 --assignee=architect + echo "ERROR: Circular dependencies detected" + exit 1 +fi ``` -Затем запусти Аналитика: +### IMPLEMENTATION +Есть открытые задачи — запускаем Executors. + ```bash -claude --model sonnet -p "Ты Аналитик. Оцени готовность плана к реализации. Следуй инструкциям из .claude/agents/analyst.md. ОБЯЗАТЕЛЬНО верни JSON в конце ответа." +# Проверяем что plan review завершён +if bd list --status=open --format=json | jq -e '.[] | select(.title == "run-plan-review")' > /dev/null 2>&1; then + echo "Waiting for plan review to complete" + exit 0 +fi + +# Запускаем executors +./scripts/run-executors.sh ``` -Парси JSON из ответа Аналитика: -- Если `"verdict": "READY"` → переходи к реализации -- Если `"verdict": "NEEDS_REFINEMENT"`: - ```bash - ./scripts/run-helpers.sh ${helpers_to_run} - ``` - Затем снова PLAN_REVIEW. Максимум 2 цикла. +### FINAL_REVIEW +Все задачи closed — финальная проверка Architect. -### PHASE:IMPLEMENTATION -План готов, есть открытые задачи: ```bash -./scripts/run-coders.sh +timeout 10m claude --model opus --print <&1 | tee logs/final-tests.log -claude --model opus -p "Ты Архитектор. Проведи финальное ревью проекта. Все задачи закрыты. Проверь код и тесты." +bd create --title="Project complete" --type=task --label=milestone:project-done +bd close +echo "PROJECT_COMPLETE" ``` -### PHASE:DONE -Проект завершён: +### DONE +Проект завершён. + ```bash -./scripts/notify.sh "Проект завершён! 🎉" "Все задачи выполнены" +./scripts/notify.sh "Project complete" "All tasks done" +echo "PROJECT_COMPLETE" +exit 0 ``` -## Обработка блокеров +## Обработка blocked задач -Периодически проверяй: ```bash -BLOCKED=$(bd list --status blocked --json 2>/dev/null | jq 'length') +BLOCKED=$(bd list --label=blocked --format=json | jq 'length') if [ "$BLOCKED" -gt 0 ]; then - bd list --status blocked --json | jq -r '.[] | "\(.id): \(.title)"' + echo "WARNING: $BLOCKED blocked tasks" + bd list --label=blocked --format=json | jq -r '.[] | " - \(.id): \(.title)"' fi ``` -Если есть blocked задачи — запусти Архитектора для принятия решения. +## Обработка ошибок -## Логирование +При любой ошибке: +```bash +./scripts/log.sh MANAGER ERROR "описание ошибки" +``` +При критической ошибке: ```bash -echo "$(date '+%Y-%m-%d %H:%M:%S') [MANAGER] $ACTION" >> logs/manager.log +./scripts/log.sh MANAGER FATAL "описание" +echo "CRITICAL_ERROR" +exit 1 +``` + +## Формат вывода + +В конце КАЖДОГО запуска выведи: + +``` +=== MANAGER DECISION === +Cycle: N +Phase: CURRENT_PHASE +Action: что сделал +Next: что ожидаем дальше +======================== ``` diff --git a/core/agents/reviewer.md b/core/agents/reviewer.md deleted file mode 100644 index 337ced7..0000000 --- a/core/agents/reviewer.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: reviewer -description: Проверяет код после Кодера -model: sonnet -tools: Read, Glob, Grep, Bash ---- - -# Роль: Ревьюер - -Проверяешь код и создаёшь баги если нужно. - -## КРИТИЧЕСКИЕ ПРАВИЛА - -1. НЕ пишешь код сам -2. НЕ закрываешь задачи -3. ТОЛЬКО проверяешь и создаёшь bug-задачи - -## Алгоритм - -1. Получи ID задачи -2. Найди коммиты: `git log --oneline | grep $TASK_ID` -3. Посмотри diff: `git show $COMMIT` - -## Проверь - -- Код решает задачу? -- Тесты есть и проходят? -- Нет очевидных багов? -- Нет security проблем? - -## При проблемах - -```bash -bd create "[BUG] Описание" -t bug -p 1 -l model:sonnet,found-by:reviewer,related:$TASK_ID -``` - -## После ревью - -```bash -bd label add $TASK_ID reviewed -``` diff --git a/core/agents/senior-executor.md b/core/agents/senior-executor.md new file mode 100644 index 0000000..89b8c88 --- /dev/null +++ b/core/agents/senior-executor.md @@ -0,0 +1,176 @@ +--- +name: senior-executor +description: Ревьюит код, мержит PR, делает релиз +model: opus +--- + +# Роль: Senior Executor + +Ты Senior Executor — quality gate перед main. Проверяешь код, мержишь через PR, отвечаешь за релизы. + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. Ты работаешь ПОСЛЕДОВАТЕЛЬНО — один PR за раз +2. Ты НИКОГДА не пропускаешь код без ревью +3. Ты НИКОГДА не мержишь если тесты падают +4. Ты проверяешь diff на secrets (sk-, api_key=, password=) +5. При сомнениях — возвращай задачу, не мержи + +## Алгоритм работы + +### 1. Найди задачу для ревью + +```bash +TASK=$(bd list --format=json | jq -r '.[] | select(.labels[]? == "needs-review") | .id' | head -1) +if [ -z "$TASK" ]; then + echo "No tasks to review" + exit 0 +fi +bd show $TASK +``` + +### 2. Claim задачу + +```bash +bd update $TASK --status=in_progress --label=reviewing +``` + +### 3. Проверь ветку + +```bash +git fetch origin +git checkout "task/beads-$TASK" +git log --oneline origin/main..HEAD +git diff origin/main..HEAD +``` + +### 4. Security check + +```bash +# Проверь на secrets +if git diff origin/main..HEAD | grep -qiE "(sk-|api_key=|password=|secret=|\.env)"; then + echo "WARNING: Potential secrets detected!" + bd update $TASK --status=open --notes="SECURITY: Potential secrets in diff. Review required." + exit 1 +fi +``` + +### 5. Запусти тесты + +```bash +# Определи команду тестов из проекта +if [ -f package.json ]; then + npm test +elif [ -f mix.exs ]; then + mix test +elif [ -f Cargo.toml ]; then + cargo test +elif [ -f go.mod ]; then + go test ./... +fi +``` + +### 6. Код ревью + +Проверь: +- Код соответствует задаче (не больше, не меньше) +- Стиль соответствует проекту +- Нет очевидных багов +- Тесты покрывают изменения (если требовались) + +### 7. Решение + +**Если код хороший — мержим:** + +```bash +# Проверяем доступность GitHub +if command -v gh &>/dev/null && gh auth status &>/dev/null; then + # PR workflow + gh pr create --title "$TASK_TITLE" --body "Task: $TASK" --base main --head "task/beads-$TASK" + gh pr merge --squash --auto + + # Ждём CI если есть + if gh run list --limit 1 &>/dev/null; then + gh run watch + fi + + # Cleanup ветки + git push origin --delete "task/beads-$TASK" + git branch -d "task/beads-$TASK" +else + # Local merge + git checkout main + git merge --no-ff "task/beads-$TASK" -m "Merge: $TASK_TITLE" + git push 2>/dev/null || echo "WARN: Cannot push to remote" + git branch -d "task/beads-$TASK" +fi + +bd close $TASK --notes="Merged and deployed" +``` + +**Если код плохой — возвращаем:** + +```bash +bd update $TASK --status=open \ + --notes="Review failed: <причина>. Fix and resubmit." +# Убираем label needs-review чтобы executor переделал +bd label remove $TASK needs-review +``` + +### 8. Rollback (если CI упал после merge) + +```bash +git revert HEAD --no-edit +git push +bd update $TASK --status=open --notes="CI failed: . Reverted." +``` + +## Релиз (после всех задач closed) + +```bash +# Определи тип версии +# bugfix → patch, feature → minor, breaking → major +VERSION_TYPE="minor" # или patch/major + +# Обнови версию +npm version $VERSION_TYPE 2>/dev/null || true + +# Создай tag +TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.1.0") +NEW_TAG=$(echo $TAG | awk -F. '{print $1"."$2+1".0"}') +git tag $NEW_TAG + +# Push +git push --tags + +# GitHub Release (если gh доступен) +if command -v gh &>/dev/null; then + gh release create $NEW_TAG --generate-notes +fi +``` + +## Merge conflicts + +**Простой (разные файлы):** +```bash +git checkout main +git merge --no-ff "task/beads-$TASK" +# Resolve и commit +``` + +**Сложный (семантический):** +```bash +bd create --title="Resolve conflict: $TASK" --type=task --priority=0 --assignee=architect +bd update $TASK --status=open --notes="Semantic conflict, escalated to Architect" +exit 0 +``` + +## Формат вывода + +``` +=== SENIOR EXECUTOR COMPLETE === +Task: $TASK_ID +Action: merged | returned | escalated +Details: ... +================================ +``` diff --git a/core/agents/tech-writer.md b/core/agents/tech-writer.md new file mode 100644 index 0000000..e6f598f --- /dev/null +++ b/core/agents/tech-writer.md @@ -0,0 +1,137 @@ +--- +name: tech-writer +description: Собирает требования от пользователя, формирует SPEC.md +model: opus +--- + +# Роль: Tech Writer + +Ты Tech Writer — первый агент в пайплайне. Твоя задача — через диалог с пользователем сформировать чёткую спецификацию проекта (SPEC.md). + +## КРИТИЧЕСКИЕ ПРАВИЛА + +1. НИКОГДА не пиши код +2. НИКОГДА не принимай технические решения (это работа Architect) +3. ВСЕГДА слушай что хочет пользователь +4. ВСЕГДА задавай уточняющие вопросы по неясным местам +5. НИКОГДА не требуй ответа на всё — неопределённое отдай Architect + +## Алгоритм работы + +### 1. Проверь есть ли draft + +```bash +if [ -f SPEC.draft.md ]; then + cat SPEC.draft.md + echo "Продолжаем с draft..." +fi +``` + +### 2. Начни диалог с пользователем + +**Если новый проект:** +- "Расскажите, что вы хотите создать?" +- "Для кого этот продукт?" +- "Что минимально должно работать в первой версии?" + +**Если есть draft:** +- Покажи что уже собрано +- Спроси что осталось уточнить + +### 3. Уточняй неясное + +Если пользователь говорит неопределённо, предложи популярные решения: +- "Обычно для такого используют PostgreSQL, подойдёт?" +- "Для авторизации чаще всего JWT или сессии. Вам важна разница?" +- "Хотите email уведомления или push?" + +### 4. Проверь готовность + +Спецификация готова если понятно: +- ЧТО система должна делать (основные функции) +- ДЛЯ КОГО (целевая аудитория) +- Что МИНИМУМ нужно для первого релиза (MVP scope) + +НЕ нужно: +- Полный список всех фич +- Технические детали реализации +- Точные сроки + +### 5. Сформируй SPEC.md + +```markdown +# Project Specification + +## Vision +[1-2 предложения что это и зачем] + +## Target Audience +[Для кого продукт] + +## MVP Scope +[Что минимум нужно для первого релиза] + +### Must Have +- Feature 1 +- Feature 2 + +### Nice to Have +- Feature 3 + +## User Stories +- As a [user], I want [feature] so that [benefit] + +## Open Questions (for Architect) +[Что осталось неопределённым — Architect решит] +``` + +## Обработка user silence + +Если пользователь не отвечает 30 минут: + +```bash +# Сохраняем draft +cat > SPEC.draft.md </dev/null || true + +# Или создаём новый +cat > SPEC.md </dev/null && echo " $id <- model:$DEFAULT_MODEL" -done - -echo "" -echo "Готово. Теперь измени конкретные задачи на opus/haiku:" -echo " bd label remove bd-XXXX model:sonnet" -echo " bd label add bd-XXXX model:opus" diff --git a/core/scripts/claim-task.sh b/core/scripts/claim-task.sh deleted file mode 100755 index 9e9d7d1..0000000 --- a/core/scripts/claim-task.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -# Атомарно захватывает одну готовую задачу -# Использование: ./claim-task.sh [agent_id] [required_model] - -set -e - -LOCK_DIR="/tmp/beads-claim-lock" -AGENT_ID="${1:-coder-$$-$(date +%s)}" -REQUIRED_MODEL="${2:-}" - -cleanup() { rmdir "$LOCK_DIR" 2>/dev/null || true; } -trap cleanup EXIT - -# Захват лока через mkdir (атомарно) -for attempt in 1 2 3 4 5 6 7 8 9 10; do - if mkdir "$LOCK_DIR" 2>/dev/null; then break; fi - if [ "$attempt" -eq 10 ]; then - echo '{"status":"locked","task":null}' - exit 0 - fi - sleep 0.$((RANDOM % 5 + 1)) -done - -# Получаем ready задачи -READY_JSON=$(bd ready --json 2>/dev/null || echo "[]") - -# Фильтруем по модели -if [ -n "$REQUIRED_MODEL" ]; then - FILTERED=$(echo "$READY_JSON" | jq -c --arg m "model:$REQUIRED_MODEL" '[.[] | select(.labels | index($m))]') -else - FILTERED="$READY_JSON" -fi - -# Исключаем in_progress -IN_PROGRESS_IDS=$(bd list --status in_progress --json 2>/dev/null | jq -r '.[].id' | tr '\n' '|' | sed 's/|$//') -[ -z "$IN_PROGRESS_IDS" ] && IN_PROGRESS_IDS="^$" - -TASK=$(echo "$FILTERED" | jq -c --arg taken "$IN_PROGRESS_IDS" ' - [.[] | select(.status == "open")] | - if ($taken == "^$") then .[0] else [.[] | select(.id | test($taken) | not)][0] end -') - -if [ "$TASK" == "null" ] || [ -z "$TASK" ]; then - echo '{"status":"no_tasks","task":null}' - exit 0 -fi - -TASK_ID=$(echo "$TASK" | jq -r '.id') - -# Двойная проверка -CURRENT=$(bd show "$TASK_ID" --json 2>/dev/null | jq -r '.status' || echo "unknown") -if [ "$CURRENT" != "open" ]; then - echo '{"status":"already_taken","task":null}' - exit 0 -fi - -# Захватываем -bd update "$TASK_ID" --status in_progress 2>/dev/null -bd label add "$TASK_ID" "assignee:$AGENT_ID" 2>/dev/null || true - -echo "$TASK" | jq -c --arg a "$AGENT_ID" '. + {status:"claimed",assignee:$a}' diff --git a/core/scripts/close-completed-parents.sh b/core/scripts/close-completed-parents.sh new file mode 100755 index 0000000..4e98ab8 --- /dev/null +++ b/core/scripts/close-completed-parents.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# core/scripts/close-completed-parents.sh +# Автоматически закрывает features и epics когда все их children завершены. +# +# Вызывается из orchestrator.sh каждый цикл. +# Использует встроенную команду beads для epics + аналогичную логику для features. + +set -euo pipefail + +SCRIPT_DIR=$(dirname "$0") +source "$SCRIPT_DIR/log.sh" + +# === Close completed features === +# Features закрываются когда все их children (tasks) имеют статус closed + +close_completed_features() { + local closed_count=0 + + # Получаем все open features + local features + features=$(bd list --type=feature --status=open --json 2>/dev/null || echo "[]") + + # Проверяем каждую feature + for feature_id in $(echo "$features" | jq -r '.[].id' 2>/dev/null); do + # Получаем children этой feature + local children + children=$(bd children "$feature_id" --json 2>/dev/null || echo "[]") + + local total closed + total=$(echo "$children" | jq 'length') + closed=$(echo "$children" | jq '[.[] | select(.status == "closed")] | length') + + # Если есть children и все closed — закрываем feature + if [ "$total" -gt 0 ] && [ "$total" = "$closed" ]; then + bd close "$feature_id" --reason="All $total children completed" 2>/dev/null + log "MANAGER" "AUTO_CLOSE" "Feature $feature_id closed (all $total children done)" + ((closed_count++)) + fi + done + + echo "$closed_count" +} + +# === Close completed epics === +# Использует встроенную команду beads + +close_completed_epics() { + local output + output=$(bd epic close-eligible 2>&1 || true) + + # Логируем если что-то закрылось + if echo "$output" | grep -q "Closed"; then + log "MANAGER" "AUTO_CLOSE" "Epics auto-closed: $output" + fi +} + +# === Main === + +main() { + # 1. Сначала закрываем features (они могут быть children epics) + local features_closed + features_closed=$(close_completed_features) + + # 2. Потом закрываем epics (теперь их children features могут быть closed) + close_completed_epics + + # Выводим summary если что-то закрылось + if [ "$features_closed" -gt 0 ]; then + echo "Auto-closed $features_closed feature(s)" + fi +} + +main "$@" diff --git a/core/scripts/detect-phase.sh b/core/scripts/detect-phase.sh index dc3ae83..4c38eca 100755 --- a/core/scripts/detect-phase.sh +++ b/core/scripts/detect-phase.sh @@ -1,60 +1,124 @@ #!/bin/bash -# Определяет текущую фазу проекта из состояния Beads +# core/scripts/detect-phase.sh +# Определяет текущую фазу проекта из состояния Beads и файлов. +# +# Фазы: INIT → PLANNING → HELPERS → PLAN_REVIEW → IMPLEMENTATION → FINAL_REVIEW → DONE +# +# Использование: ./scripts/detect-phase.sh +# Выводит: PHASE_NAME (одно слово, для использования в скриптах) -set -e +set -euo pipefail +# Находим корень проекта +find_project_root() { + local dir="$PWD" + while [ "$dir" != "/" ]; do + if [ -d "$dir/.claudev" ]; then + echo "$dir" + return 0 + fi + dir=$(dirname "$dir") + done + echo "$PWD" +} + +PROJECT_ROOT=$(find_project_root) + +# Проверяем beads if ! command -v bd &> /dev/null; then - echo "PHASE:ERROR" - echo "ACTION:install-beads" - echo "REASON:Beads (bd) не установлен" + echo "ERROR" + >&2 echo "Beads (bd) не установлен" exit 1 fi -TOTAL=$(bd list --json 2>/dev/null | jq 'length' 2>/dev/null || echo "0") -OPEN=$(bd list --status open --json 2>/dev/null | jq 'length' 2>/dev/null || echo "0") -IN_PROGRESS=$(bd list --status in_progress --json 2>/dev/null | jq 'length' 2>/dev/null || echo "0") -CLOSED=$(bd list --status closed --json 2>/dev/null | jq 'length' 2>/dev/null || echo "0") -BLOCKED=$(bd list --status blocked --json 2>/dev/null | jq 'length' 2>/dev/null || echo "0") - -HAS_PLANNING_DONE=$(bd list --json 2>/dev/null | jq '[.[] | select(.labels | index("milestone:planning-done"))] | length' 2>/dev/null || echo "0") -HAS_HELPERS_DONE=$(bd list --json 2>/dev/null | jq '[.[] | select(.labels | index("milestone:helpers-done"))] | length' 2>/dev/null || echo "0") -HAS_PLAN_REVIEWED=$(bd list --json 2>/dev/null | jq '[.[] | select(.labels | index("milestone:plan-reviewed"))] | length' 2>/dev/null || echo "0") -HAS_PROJECT_DONE=$(bd list --json 2>/dev/null | jq '[.[] | select(.labels | index("milestone:project-done"))] | length' 2>/dev/null || echo "0") - -if [ "$TOTAL" -eq 0 ]; then - echo "PHASE:INIT" - echo "ACTION:run-architect" - echo "REASON:План отсутствует" -elif [ "$HAS_PROJECT_DONE" -gt 0 ]; then - echo "PHASE:DONE" - echo "ACTION:none" - echo "REASON:Проект завершён" -elif [ "$HAS_PLANNING_DONE" -eq 0 ]; then - echo "PHASE:PLANNING" - echo "ACTION:run-architect" - echo "REASON:Нет milestone:planning-done" -elif [ "$HAS_HELPERS_DONE" -eq 0 ]; then - echo "PHASE:HELPERS" - echo "ACTION:run-helpers" - echo "REASON:Нет milestone:helpers-done" -elif [ "$HAS_PLAN_REVIEWED" -eq 0 ]; then - echo "PHASE:PLAN_REVIEW" - echo "ACTION:run-architect-review" - echo "REASON:Нет milestone:plan-reviewed" -elif [ "$OPEN" -gt 0 ] || [ "$IN_PROGRESS" -gt 0 ]; then - echo "PHASE:IMPLEMENTATION" - echo "ACTION:run-coders" - echo "REASON:open=$OPEN, in_progress=$IN_PROGRESS, blocked=$BLOCKED" -elif [ "$CLOSED" -gt 0 ] && [ "$OPEN" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ]; then - echo "PHASE:FINAL_REVIEW" - echo "ACTION:run-final-review" - echo "REASON:Все задачи закрыты" -else - echo "PHASE:UNKNOWN" - echo "ACTION:manual" - echo "REASON:Не удалось определить" -fi - ->&2 echo "---" ->&2 echo "Stats: total=$TOTAL, open=$OPEN, in_progress=$IN_PROGRESS, closed=$CLOSED, blocked=$BLOCKED" ->&2 echo "Milestones: planning=$HAS_PLANNING_DONE, helpers=$HAS_HELPERS_DONE, reviewed=$HAS_PLAN_REVIEWED, done=$HAS_PROJECT_DONE" +# Собираем статистику из beads +get_count() { + local filter=$1 + bd list $filter --format=json 2>/dev/null | jq 'length' 2>/dev/null || echo "0" +} + +has_label() { + local label=$1 + bd list --format=json 2>/dev/null | jq "[.[] | select(.labels[]? == \"$label\")] | length" 2>/dev/null || echo "0" +} + +has_open_task() { + local title_pattern=$1 + bd list --status=open --format=json 2>/dev/null | jq "[.[] | select(.title | test(\"$title_pattern\"))] | length" 2>/dev/null || echo "0" +} + +# Статистика +TOTAL=$(get_count "") +OPEN=$(get_count "--status=open") +IN_PROGRESS=$(get_count "--status=in_progress") +CLOSED=$(get_count "--status=closed") + +# Milestones (через labels) +HAS_PLANNING_DONE=$(has_label "milestone:planning-done") +HAS_ANALYSTS_DONE=$(has_label "milestone:analysts-done") +HAS_PLAN_REVIEWED=$(has_label "milestone:plan-reviewed") +HAS_PROJECT_DONE=$(has_label "milestone:project-done") + +# Trigger tasks для analysts +ANALYST_TRIGGERS_OPEN=$(has_open_task "^run-analyst-") +PLAN_REVIEW_OPEN=$(has_open_task "^run-plan-review$") + +# === Определение фазы === + +# DONE: проект завершён +if [ "$HAS_PROJECT_DONE" -gt 0 ]; then + echo "DONE" + exit 0 +fi + +# INIT: нет SPEC.md → нужен Tech Writer +if [ ! -f "$PROJECT_ROOT/SPEC.md" ]; then + # Проверяем есть ли draft + if [ -f "$PROJECT_ROOT/SPEC.draft.md" ]; then + echo "INIT" # Продолжаем с draft + else + echo "INIT" # Начинаем с нуля + fi + exit 0 +fi + +# PLANNING: есть SPEC.md, но нет плана (milestone:planning-done) +if [ "$HAS_PLANNING_DONE" -eq 0 ]; then + echo "PLANNING" + exit 0 +fi + +# HELPERS (Analysts): план есть, но analysts не завершили +if [ "$HAS_ANALYSTS_DONE" -eq 0 ]; then + # Проверяем: есть ли открытые trigger-задачи analysts + if [ "$ANALYST_TRIGGERS_OPEN" -gt 0 ]; then + echo "HELPERS" # Ждём завершения analysts + else + echo "HELPERS" # Нужно запустить analysts + fi + exit 0 +fi + +# PLAN_REVIEW: analysts закончили, Architect ревьюит +if [ "$HAS_PLAN_REVIEWED" -eq 0 ]; then + echo "PLAN_REVIEW" + exit 0 +fi + +# IMPLEMENTATION: есть открытые или in_progress задачи +if [ "$OPEN" -gt 0 ] || [ "$IN_PROGRESS" -gt 0 ]; then + echo "IMPLEMENTATION" + exit 0 +fi + +# FINAL_REVIEW: все задачи closed, финальная проверка +if [ "$CLOSED" -gt 0 ] && [ "$OPEN" -eq 0 ] && [ "$IN_PROGRESS" -eq 0 ]; then + echo "FINAL_REVIEW" + exit 0 +fi + +# UNKNOWN: не удалось определить +echo "UNKNOWN" +>&2 echo "Stats: total=$TOTAL, open=$OPEN, in_progress=$IN_PROGRESS, closed=$CLOSED" +>&2 echo "Milestones: planning=$HAS_PLANNING_DONE, analysts=$HAS_ANALYSTS_DONE, reviewed=$HAS_PLAN_REVIEWED, done=$HAS_PROJECT_DONE" +exit 1 diff --git a/core/scripts/init-manager.sh b/core/scripts/init-manager.sh deleted file mode 100755 index 041c183..0000000 --- a/core/scripts/init-manager.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash -# scripts/init-manager.sh -# Инициализирует или сбрасывает состояние менеджера в Beads -# -# Использование: -# ./scripts/init-manager.sh # Создать если нет -# ./scripts/init-manager.sh --reset # Сбросить в начальное состояние -# ./scripts/init-manager.sh --phase X # Установить конкретную фазу - -set -e - -RESET=false -PHASE="INIT" -HELPER_CYCLES=0 - -while [[ $# -gt 0 ]]; do - case $1 in - --reset) - RESET=true - shift - ;; - --phase) - PHASE="$2" - shift 2 - ;; - --helper-cycles) - HELPER_CYCLES="$2" - shift 2 - ;; - *) - echo "Unknown option: $1" - exit 1 - ;; - esac -done - -# Найди существующую задачу менеджера -MANAGER_ID=$(bd list --json 2>/dev/null | jq -r '.[] | select(.labels | index("role:manager")) | .id' || echo "") - -if [ "$RESET" = true ] && [ -n "$MANAGER_ID" ] && [ "$MANAGER_ID" != "null" ]; then - echo "Удаление старого состояния: $MANAGER_ID" - bd delete "$MANAGER_ID" 2>/dev/null || true - MANAGER_ID="" -fi - -if [ -z "$MANAGER_ID" ] || [ "$MANAGER_ID" == "null" ]; then - echo "Создание состояния менеджера..." - - STATE=$(cat << STATEJSON -{ - "phase": "$PHASE", - "cycle": 0, - "helper_cycles": $HELPER_CYCLES, - "last_action": null, - "last_decision": "Initial state", - "blockers_seen": [], - "decisions": [] -} -STATEJSON -) - - bd create "MANAGER: Project State" -t meta -p 0 -l role:manager -d "$STATE" - - MANAGER_ID=$(bd list --json | jq -r '.[] | select(.labels | index("role:manager")) | .id') - echo "✓ Создано: $MANAGER_ID" -else - echo "Состояние менеджера уже существует: $MANAGER_ID" -fi - -echo "" -echo "=== MANAGER STATE ===" -bd show "$MANAGER_ID" --json | jq '.description | fromjson' diff --git a/core/scripts/log.sh b/core/scripts/log.sh new file mode 100755 index 0000000..ad7541c --- /dev/null +++ b/core/scripts/log.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# core/scripts/log.sh +# Хелпер для логирования в Claudev. +# +# Формат: YYYY-MM-DD HH:MM:SS [AGENT] EVENT: message +# Файл: logs/claudev.log +# +# Использование: +# source ./scripts/log.sh +# log "MANAGER" "INFO" "Starting phase detection" +# log "EXECUTOR" "TASK_START" "claudev-abc" +# log "ORCHESTRATOR" "FATAL" "Beads daemon not running" +# +# Или напрямую: +# ./scripts/log.sh MANAGER INFO "Starting phase detection" + +# Находим корень проекта (где .claudev/) +find_project_root() { + local dir="$PWD" + while [ "$dir" != "/" ]; do + if [ -d "$dir/.claudev" ]; then + echo "$dir" + return 0 + fi + dir=$(dirname "$dir") + done + echo "$PWD" +} + +PROJECT_ROOT=$(find_project_root) +LOGS_DIR="$PROJECT_ROOT/logs" +LOG_FILE="$LOGS_DIR/claudev.log" + +# Создаём директорию если нет +mkdir -p "$LOGS_DIR" + +# Функция логирования +log() { + local agent=$1 + local event=$2 + local message=$3 + local timestamp + timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + echo "$timestamp [$agent] $event: $message" >> "$LOG_FILE" + + # Также выводим в stdout для интерактивного использования + if [ -t 1 ]; then + echo "$timestamp [$agent] $event: $message" + fi +} + +# Если запущен напрямую (не source) +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + if [ $# -lt 3 ]; then + echo "Usage: $0 AGENT EVENT MESSAGE" + echo "Example: $0 MANAGER INFO 'Starting phase detection'" + exit 1 + fi + log "$1" "$2" "$3" +fi diff --git a/core/scripts/orchestrator.sh b/core/scripts/orchestrator.sh index e01fd4e..04d6b43 100755 --- a/core/scripts/orchestrator.sh +++ b/core/scripts/orchestrator.sh @@ -1,92 +1,246 @@ #!/bin/bash -# scripts/orchestrator.sh -# Пинает менеджера в цикле. Менеджер сам решает что делать. +# core/scripts/orchestrator.sh +# Главный цикл Claudev — координирует работу агентов через Manager. # # Использование: # ./scripts/orchestrator.sh # Интерактивно # ./scripts/orchestrator.sh & # В фоне # nohup ./scripts/orchestrator.sh & # Переживёт закрытие терминала -set -e +set -euo pipefail PROJECT_DIR=$(pwd) +CLAUDEV_DIR="$PROJECT_DIR/.claudev" LOGS_DIR="$PROJECT_DIR/logs" -MAX_CYCLES="${MAX_CYCLES:-100}" -PAUSE_SECONDS="${PAUSE_SECONDS:-10}" +LOCK_FILE="$CLAUDEV_DIR/orchestrator.lock" +CONFIG_FILE="$CLAUDEV_DIR/config.sh" + +# === Lock file (single instance) === + +acquire_lock() { + mkdir -p "$CLAUDEV_DIR" + + if ! (set -C; echo $$ > "$LOCK_FILE") 2>/dev/null; then + OLD_PID=$(cat "$LOCK_FILE" 2>/dev/null || echo "0") + if kill -0 "$OLD_PID" 2>/dev/null; then + echo "ERROR: Orchestrator already running (PID $OLD_PID)" + exit 1 + else + echo "Removing stale lock (PID $OLD_PID not found)" + rm -f "$LOCK_FILE" + if ! (set -C; echo $$ > "$LOCK_FILE") 2>/dev/null; then + echo "ERROR: Failed to acquire lock (race condition?)" + exit 1 + fi + fi + fi +} + +# === Logging === mkdir -p "$LOGS_DIR" log() { - echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOGS_DIR/orchestrator.log" + local level=$1 + local message=$2 + echo "$(date '+%Y-%m-%d %H:%M:%S') [ORCHESTRATOR] $level: $message" | tee -a "$LOGS_DIR/claudev.log" } -log "==========================================" -log "ORCHESTRATOR STARTED" -log "Project: $PROJECT_DIR" -log "Max cycles: $MAX_CYCLES" -log "Pause: ${PAUSE_SECONDS}s" -log "==========================================" - -CYCLE=0 - -while [ $CYCLE -lt $MAX_CYCLES ]; do - ((CYCLE++)) - - log "--- Cycle $CYCLE ---" - log "Вызов менеджера..." - - # Вызываем менеджера - MANAGER_OUT=$(claude --model sonnet -p " -Ты Менеджер проекта. Продолжи работу. - -Следуй инструкциям из .claude/agents/manager.md - -КРИТИЧНО: -1. СНАЧАЛА прочитай своё состояние из Beads (задача с label role:manager) -2. Определи текущую фазу и что делать -3. Выполни ОДНО действие -4. ОБЯЗАТЕЛЬНО сохрани новое состояние в Beads -5. Если проект завершён — напиши PROJECT_COMPLETE - -Не забудь вывести своё решение в формате: -=== MANAGER DECISION === -Cycle: N -Phase: OLD → NEW -Action: что делаешь -Reason: почему -======================== -" 2>&1 | tee "$LOGS_DIR/manager-$CYCLE.log") - - # Проверяем завершение - if echo "$MANAGER_OUT" | grep -q "PROJECT_COMPLETE"; then - log "==========================================" - log "PROJECT COMPLETE" - log "==========================================" - ./scripts/notify.sh "Проект завершён! 🎉" "Все задачи выполнены" 2>/dev/null || true - - # Показываем финальную статистику - echo "" - echo "=== ФИНАЛЬНАЯ СТАТИСТИКА ===" - bd list --json 2>/dev/null | jq 'group_by(.status) | map({status: .[0].status, count: length})' || true - - exit 0 +# === Config validation === + +validate_config() { + local errors=0 + + # Validate integers + validate_int() { + local name=$1 + local value=$2 + if ! [[ "$value" =~ ^[0-9]+$ ]]; then + log "FATAL" "Invalid $name in config.sh: must be integer, got '$value'" + ((errors++)) + fi + } + + # Validate booleans + validate_bool() { + local name=$1 + local value=$2 + if [[ "$value" != "true" && "$value" != "false" ]]; then + log "FATAL" "Invalid $name in config.sh: must be true/false, got '$value'" + ((errors++)) + fi + } + + # Validate timeout format (Nm or Ns) + validate_timeout() { + local name=$1 + local value=$2 + if ! [[ "$value" =~ ^[0-9]+[ms]$ ]]; then + log "FATAL" "Invalid $name in config.sh: must be Nm or Ns (e.g. 10m), got '$value'" + ((errors++)) + fi + } + + # Run validations + validate_int "MAX_PARALLEL_EXECUTORS" "$MAX_PARALLEL_EXECUTORS" + validate_int "RETRY_LIMIT" "$RETRY_LIMIT" + validate_int "ITERATION_DELAY" "$ITERATION_DELAY" + validate_int "CLEANUP_KEEP_DAYS" "$CLEANUP_KEEP_DAYS" + + validate_bool "CI_ENABLED" "$CI_ENABLED" + validate_bool "CD_ENABLED" "$CD_ENABLED" + validate_bool "LOG_TOKENS" "$LOG_TOKENS" + validate_bool "CLEANUP_ENABLED" "$CLEANUP_ENABLED" + + validate_timeout "TASK_TIMEOUT" "$TASK_TIMEOUT" + validate_timeout "USER_INPUT_TIMEOUT" "$USER_INPUT_TIMEOUT" + + if [ "$errors" -gt 0 ]; then + log "FATAL" "Config validation failed ($errors errors). Fix .claudev/config.sh" + exit 1 fi - - # Проверяем критические ошибки - if echo "$MANAGER_OUT" | grep -qi "CRITICAL_ERROR\|FATAL"; then - log "CRITICAL ERROR detected!" - ./scripts/notify.sh "Критическая ошибка" "Смотри logs/manager-$CYCLE.log" 2>/dev/null || true + + log "INFO" "Config loaded: MAX_PARALLEL=$MAX_PARALLEL_EXECUTORS, RETRY=$RETRY_LIMIT, DELAY=${ITERATION_DELAY}s" +} + +load_config() { + if [ ! -f "$CONFIG_FILE" ]; then + log "FATAL" "Config not found: $CONFIG_FILE. Run install.sh first." + exit 1 + fi + + # shellcheck source=/dev/null + source "$CONFIG_FILE" + validate_config +} + +# === Beads daemon check === + +check_beads() { + if ! bd sync --status &>/dev/null; then + log "FATAL" "Beads daemon not running. Run: bd daemon start" exit 1 fi - - # Логируем решение менеджера - DECISION=$(echo "$MANAGER_OUT" | grep -A5 "MANAGER DECISION" | head -6 || echo "No decision found") - log "Decision: $(echo "$DECISION" | tr '\n' ' ')" - - log "Пауза ${PAUSE_SECONDS}s..." - sleep $PAUSE_SECONDS -done - -log "Достигнут лимит циклов ($MAX_CYCLES)" -./scripts/notify.sh "Лимит циклов" "Orchestrator остановлен после $MAX_CYCLES циклов" 2>/dev/null || true -exit 1 +} + +# === Graceful shutdown === + +cleanup() { + log "INFO" "Shutting down gracefully..." + + # SIGTERM children + pkill -P $$ -TERM 2>/dev/null || true + sleep 5 + pkill -P $$ -KILL 2>/dev/null || true + + # Reset stale in_progress tasks (>5min old) + for task_id in $(bd list --status=in_progress --format=json 2>/dev/null | jq -r '.[].id' 2>/dev/null || true); do + local updated_at + updated_at=$(bd show "$task_id" --format=json 2>/dev/null | jq -r '.updated_at' 2>/dev/null || echo "") + if [ -n "$updated_at" ]; then + local claimed_epoch now_epoch age + claimed_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "${updated_at%%.*}" +%s 2>/dev/null || date -d "$updated_at" +%s 2>/dev/null || echo "0") + now_epoch=$(date +%s) + age=$((now_epoch - claimed_epoch)) + + if [ "$age" -gt 300 ]; then + log "INFO" "Resetting stale task $task_id (age: ${age}s)" + bd update "$task_id" --status=open --notes="Reset: stale at shutdown (${age}s old)" 2>/dev/null || true + fi + fi + done + + rm -f "$LOCK_FILE" + log "INFO" "Shutdown complete" + exit 0 +} + +trap cleanup SIGINT SIGTERM + +# === Detect phase === + +detect_phase() { + ./scripts/detect-phase.sh 2>/dev/null || echo "UNKNOWN" +} + +# === Main loop === + +main() { + acquire_lock + + log "INFO" "==========================================" + log "INFO" "ORCHESTRATOR STARTED (PID $$)" + log "INFO" "Project: $PROJECT_DIR" + log "INFO" "==========================================" + + # Record iteration start time + date '+%Y-%m-%d %H:%M:%S' > "$CLAUDEV_DIR/iteration_start.txt" + + local cycle=0 + local max_cycles="${MAX_CYCLES:-1000}" + + while [ $cycle -lt "$max_cycles" ]; do + ((cycle++)) + + # 1. Check beads daemon (every iteration, fast ~10-50ms) + check_beads + + # 2. Load config (allows hot reload) + load_config + + # 3. Detect current phase + local phase + phase=$(detect_phase) + log "INFO" "--- Cycle $cycle | Phase: $phase ---" + + # 4. Run Manager agent + local manager_out + manager_out=$(timeout "$TASK_TIMEOUT" claude --model sonnet --print <&1 || true) +$(cat .claude/agents/manager.md 2>/dev/null || echo "# Manager agent not found") + +--- +PROJECT_ROOT: $PROJECT_DIR +CURRENT_PHASE: $phase +CYCLE: $cycle +EOF + + # Log manager output + echo "$manager_out" >> "$LOGS_DIR/manager-$cycle.log" + + # 5. Check for completion + if echo "$manager_out" | grep -q "PROJECT_COMPLETE"; then + log "INFO" "==========================================" + log "INFO" "PROJECT COMPLETE" + log "INFO" "==========================================" + + # Archive logs + local timestamp + timestamp=$(date +%Y%m%d-%H%M%S) + mkdir -p "$LOGS_DIR/archive" + mv "$LOGS_DIR/claudev.log" "$LOGS_DIR/archive/iteration-$timestamp.log" 2>/dev/null || true + + ./scripts/notify.sh "Project complete" "All tasks done" 2>/dev/null || true + rm -f "$LOCK_FILE" + exit 0 + fi + + # 6. Check for critical errors + if echo "$manager_out" | grep -qi "CRITICAL_ERROR\|FATAL"; then + log "ERROR" "Critical error detected in Manager output" + ./scripts/notify.sh "Critical error" "Check logs/manager-$cycle.log" 2>/dev/null || true + fi + + # 7. Auto-close completed features and epics + ./scripts/close-completed-parents.sh 2>/dev/null || true + + # 8. Pause before next iteration + log "INFO" "Pause ${ITERATION_DELAY}s..." + sleep "$ITERATION_DELAY" + done + + log "WARN" "Max cycles reached ($max_cycles)" + rm -f "$LOCK_FILE" + exit 1 +} + +main "$@" diff --git a/core/scripts/run-analysts.sh b/core/scripts/run-analysts.sh new file mode 100755 index 0000000..592e7be --- /dev/null +++ b/core/scripts/run-analysts.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# core/scripts/run-analysts.sh +# Запускает 5 Analyst агентов параллельно. +# Каждый analyst claim своей trigger-задачи и закрывает её по завершении. +# +# Analysts: ux, security, ops, reliability, architecture +# +# Использование: ./scripts/run-analysts.sh + +set -euo pipefail + +PROJECT_DIR=$(pwd) +LOGS_DIR="$PROJECT_DIR/logs" +CONFIG_FILE="$PROJECT_DIR/.claudev/config.sh" + +# Load config +if [ -f "$CONFIG_FILE" ]; then + # shellcheck source=/dev/null + source "$CONFIG_FILE" +fi + +TASK_TIMEOUT="${TASK_TIMEOUT:-10m}" + +mkdir -p "$LOGS_DIR" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [RUN-ANALYSTS] $1: $2" | tee -a "$LOGS_DIR/claudev.log" +} + +# All analysts +ANALYSTS=("ux" "security" "ops" "reliability" "architecture") + +# Run single analyst +run_analyst() { + local analyst=$1 + local trigger_task="run-analyst-$analyst" + local agent_file=".claude/agents/analyst-$analyst.md" + + log "INFO" "Starting analyst-$analyst" + + # Find trigger task + local task_id + task_id=$(bd list --format=json 2>/dev/null | jq -r ".[] | select(.title == \"$trigger_task\") | .id" | head -1) + + if [ -z "$task_id" ]; then + log "WARN" "No trigger task for analyst-$analyst" + return 0 + fi + + # Claim trigger task + if ! bd update "$task_id" --status=in_progress 2>/dev/null; then + log "INFO" "Trigger $trigger_task already claimed" + return 0 + fi + + # Check if agent file exists + if [ ! -f "$agent_file" ]; then + log "WARN" "Agent file not found: $agent_file" + bd close "$task_id" --reason="Agent file not found" + return 0 + fi + + # Run analyst with timeout + local output_file="$LOGS_DIR/analyst-$analyst.log" + + timeout "$TASK_TIMEOUT" claude --model sonnet --print < "$output_file" 2>&1 || { + local exit_code=$? + if [ $exit_code -eq 124 ]; then + log "WARN" "Analyst $analyst timeout" + bd update "$task_id" --status=open --notes="Timeout at $(date '+%Y-%m-%d %H:%M:%S')" + else + log "ERROR" "Analyst $analyst failed (exit: $exit_code)" + bd update "$task_id" --status=open --notes="Failed (exit: $exit_code)" + fi + return 0 + } +$(cat "$agent_file" 2>/dev/null) + +--- +ANALYST: $analyst +TRIGGER_TASK: $task_id +PROJECT_ROOT: $PROJECT_DIR +EOF + + # Close trigger task + bd close "$task_id" --reason="Analyst $analyst completed" + log "INFO" "Analyst $analyst completed" +} + +# Main +main() { + log "INFO" "==========================================" + log "INFO" "RUN-ANALYSTS STARTED" + log "INFO" "Analysts: ${ANALYSTS[*]}" + log "INFO" "==========================================" + + # Check that all trigger tasks exist + local missing=0 + for analyst in "${ANALYSTS[@]}"; do + if ! bd list --format=json 2>/dev/null | jq -e ".[] | select(.title == \"run-analyst-$analyst\")" > /dev/null 2>&1; then + log "WARN" "Trigger task run-analyst-$analyst not found" + ((missing++)) + fi + done + + if [ "$missing" -eq "${#ANALYSTS[@]}" ]; then + log "ERROR" "No trigger tasks found. Create them first." + exit 1 + fi + + # Run all analysts in parallel + for analyst in "${ANALYSTS[@]}"; do + run_analyst "$analyst" & + done + + # Wait for all + wait + + # Check if all done + local open_triggers + open_triggers=$(bd list --status=open --format=json 2>/dev/null | jq '[.[] | select(.title | startswith("run-analyst-"))] | length' 2>/dev/null || echo "0") + + if [ "$open_triggers" -eq 0 ]; then + log "INFO" "All analysts completed" + # Set milestone + bd create --title="Analysts complete" --type=task --label=milestone:analysts-done 2>/dev/null || true + local milestone_id + milestone_id=$(bd list --format=json | jq -r '.[] | select(.labels[]? == "milestone:analysts-done") | .id' | head -1) + [ -n "$milestone_id" ] && bd close "$milestone_id" 2>/dev/null || true + else + log "INFO" "Some analysts still open ($open_triggers remaining)" + fi + + bd sync 2>/dev/null || true + log "INFO" "RUN-ANALYSTS FINISHED" +} + +main "$@" diff --git a/core/scripts/run-coders.sh b/core/scripts/run-coders.sh deleted file mode 100755 index c12d0cb..0000000 --- a/core/scripts/run-coders.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# Запускает кодеров параллельно -# Использование: ./run-coders.sh [num_coders] - -set -e - -PROJECT_DIR=$(pwd) -LOGS_DIR="$PROJECT_DIR/logs" -NUM="${1:-2}" -MAX_TASKS=20 - -mkdir -p "$LOGS_DIR" - -run_coder() { - local id=$1 - local done=0 - - while [ $done -lt $MAX_TASKS ]; do - CLAIM=$("$PROJECT_DIR/scripts/claim-task.sh" "coder-$id") - STATUS=$(echo "$CLAIM" | jq -r '.status') - - [ "$STATUS" != "claimed" ] && break - - TASK_ID=$(echo "$CLAIM" | jq -r '.id') - MODEL=$(echo "$CLAIM" | jq -r '.labels | map(select(startswith("model:"))) | .[0] | split(":")[1] // "sonnet"') - - echo "[coder-$id] $TASK_ID ($MODEL)" - - claude --model "$MODEL" -p " -Ты Кодер (coder-$id). Задача: $TASK_ID -Следуй .claude/agents/coder.md -После завершения: bd close $TASK_ID --reason \"...\" && bd sync -ОСТАНОВИСЬ после закрытия. -" > "$LOGS_DIR/coder-$id-$TASK_ID.log" 2>&1 || true - - # Ревью - claude --model sonnet -p "Ты Ревьюер. Проверь $TASK_ID. Следуй .claude/agents/reviewer.md" \ - > "$LOGS_DIR/review-$TASK_ID.log" 2>&1 || true - bd label add "$TASK_ID" reviewed 2>/dev/null || true - - ((done++)) - sleep 2 - done - - touch "$PROJECT_DIR/.coder-done-$id" - echo "[coder-$id] Завершён ($done задач)" -} - -echo "$(date '+%H:%M:%S') Запуск $NUM кодеров" - -for i in $(seq 1 $NUM); do run_coder $i & done - -while true; do - DONE=0 - for i in $(seq 1 $NUM); do [ -f "$PROJECT_DIR/.coder-done-$i" ] && ((DONE++)); done - [ "$DONE" -eq "$NUM" ] && break - sleep 10 -done - -rm -f "$PROJECT_DIR"/.coder-done-* -bd sync 2>/dev/null || true - -echo "$(date '+%H:%M:%S') Кодеры завершены" -bd list --json | jq 'group_by(.status) | map({status: .[0].status, count: length})' -./scripts/notify.sh "Кодеры завершены" "Проверьте статус" 2>/dev/null || true diff --git a/core/scripts/run-executors.sh b/core/scripts/run-executors.sh new file mode 100755 index 0000000..02c614d --- /dev/null +++ b/core/scripts/run-executors.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# core/scripts/run-executors.sh +# Запускает Executor агентов параллельно с backpressure контролем. +# +# Backpressure: количество активных executors ограничено через MAX_PARALLEL_EXECUTORS. +# Считаем через beads (in_progress + label=executor), не через gh pr list. +# +# Использование: ./scripts/run-executors.sh + +set -euo pipefail + +PROJECT_DIR=$(pwd) +LOGS_DIR="$PROJECT_DIR/logs" +CONFIG_FILE="$PROJECT_DIR/.claudev/config.sh" + +# Load config +if [ -f "$CONFIG_FILE" ]; then + # shellcheck source=/dev/null + source "$CONFIG_FILE" +fi + +MAX_PARALLEL="${MAX_PARALLEL_EXECUTORS:-3}" +TASK_TIMEOUT="${TASK_TIMEOUT:-10m}" + +mkdir -p "$LOGS_DIR" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [RUN-EXECUTORS] $1: $2" | tee -a "$LOGS_DIR/claudev.log" +} + +# === Backpressure check === +# Считаем active executors через beads (работает всегда, не зависит от gh) + +count_active_executors() { + # Считаем задачи в in_progress с label executor или model:* + bd list --status=in_progress --format=json 2>/dev/null | \ + jq '[.[] | select(.labels[]? | test("^(executor|model:)"))] | length' 2>/dev/null || echo "0" +} + +# === Get ready tasks for executors === + +get_ready_tasks() { + # Получаем задачи готовые к работе (не blocked, не in_progress) + # Фильтруем только те что для executors (имеют model: label или тип task без специальных assignee) + bd ready --format=json 2>/dev/null | \ + jq -r '.[] | select(.type == "task") | select(.labels[]? | test("^model:") or . == "implementation") | .id' 2>/dev/null | \ + head -n "$MAX_PARALLEL" +} + +# === Run single executor === + +run_executor() { + local task_id=$1 + + # Try to claim the task + if ! bd update "$task_id" --status=in_progress --label=executor 2>/dev/null; then + log "INFO" "Task $task_id already claimed, skipping" + return 0 + fi + + # Get task details + local task_json + task_json=$(bd show "$task_id" --format=json 2>/dev/null || echo "{}") + + local task_title + task_title=$(echo "$task_json" | jq -r '.title // "Unknown"') + + # Get model from label (default: sonnet) + local model + model=$(echo "$task_json" | jq -r '.labels[]? | select(startswith("model:")) | split(":")[1]' 2>/dev/null | head -1) + model="${model:-sonnet}" + + log "INFO" "Starting executor for $task_id ($model): $task_title" + + # Run executor agent with timeout + local output_file="$LOGS_DIR/executor-$task_id.log" + + timeout "$TASK_TIMEOUT" claude --model "$model" --print < "$output_file" 2>&1 || { + local exit_code=$? + if [ $exit_code -eq 124 ]; then + log "WARN" "Executor timeout for $task_id" + # Increment retry counter + local current_retry + current_retry=$(echo "$task_json" | jq -r '.labels[]? | select(startswith("retry:")) | split(":")[1]' 2>/dev/null | head -1) + current_retry="${current_retry:-0}" + local new_retry=$((current_retry + 1)) + + bd update "$task_id" --status=open --label="retry:$new_retry" --notes="Timeout at $(date '+%Y-%m-%d %H:%M:%S')" 2>/dev/null || true + else + log "ERROR" "Executor failed for $task_id (exit: $exit_code)" + bd update "$task_id" --status=open --notes="Executor failed (exit: $exit_code)" 2>/dev/null || true + fi + return 0 + } +$(cat .claude/agents/executor.md 2>/dev/null || echo "# Executor agent not found") + +--- +TASK_ID: $task_id +TASK: $task_json +PROJECT_ROOT: $PROJECT_DIR +EOF + + log "INFO" "Executor completed for $task_id" +} + +# === Main === + +main() { + log "INFO" "==========================================" + log "INFO" "RUN-EXECUTORS STARTED" + log "INFO" "Max parallel: $MAX_PARALLEL" + log "INFO" "==========================================" + + # Check backpressure + local active + active=$(count_active_executors) + + if [ "$active" -ge "$MAX_PARALLEL" ]; then + log "INFO" "Executor queue full ($active/$MAX_PARALLEL), waiting for slots" + exit 0 + fi + + local available_slots=$((MAX_PARALLEL - active)) + log "INFO" "Available slots: $available_slots (active: $active)" + + # Get ready tasks + local tasks + tasks=$(get_ready_tasks) + + if [ -z "$tasks" ]; then + log "INFO" "No ready tasks for executors" + exit 0 + fi + + # Start executors in parallel (up to available slots) + local started=0 + for task_id in $tasks; do + if [ $started -ge $available_slots ]; then + break + fi + + run_executor "$task_id" & + ((started++)) + done + + log "INFO" "Started $started executors" + + # Wait for all background jobs + wait + + log "INFO" "All executors finished" + bd sync 2>/dev/null || true +} + +main "$@" diff --git a/core/scripts/run-helpers.sh b/core/scripts/run-helpers.sh deleted file mode 100755 index 244affe..0000000 --- a/core/scripts/run-helpers.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -# Запускает помощников параллельно -# Использование: ./run-helpers.sh [helper1 helper2 ...] -# Примеры: ./run-helpers.sh # все -# ./run-helpers.sh ux ops # только ux и ops - -set -e - -PROJECT_DIR=$(pwd) -LOGS_DIR="$PROJECT_DIR/logs" -TIMEOUT=1800 - -mkdir -p "$LOGS_DIR" - -[ $# -gt 0 ] && HELPERS=("$@") || HELPERS=("arch" "rel" "ux" "ops") - -declare -A NAMES=(["arch"]="architecture" ["rel"]="reliability" ["ux"]="ux" ["ops"]="ops") -declare -A PROMPTS=( - ["arch"]="Проанализируй план на архитектурные проблемы" - ["rel"]="Проанализируй план на проблемы надёжности и edge cases" - ["ux"]="Проанализируй план на UX проблемы" - ["ops"]="Проанализируй план на проблемы тестирования и деплоя" -) - -echo "$(date '+%H:%M:%S') Запуск: ${HELPERS[*]}" -rm -f "$PROJECT_DIR"/.helper-done-* 2>/dev/null - -for h in "${HELPERS[@]}"; do - ( - claude --model sonnet -p " -Ты helper-${NAMES[$h]}. ${PROMPTS[$h]} -Следуй инструкциям из .claude/agents/helper-${NAMES[$h]}.md -Создавай задачи с label source:helper-$h -После завершения: bd sync -" > "$LOGS_DIR/helper-$h.log" 2>&1 || true - touch "$PROJECT_DIR/.helper-done-$h" - ) & - echo " Запущен helper-$h (PID: $!)" -done - -START=$(date +%s) -while true; do - DONE=0 - for h in "${HELPERS[@]}"; do [ -f "$PROJECT_DIR/.helper-done-$h" ] && ((DONE++)); done - [ "$DONE" -eq "${#HELPERS[@]}" ] && break - [ $(($(date +%s) - START)) -gt $TIMEOUT ] && { echo "TIMEOUT"; pkill -f claude || true; break; } - sleep 5 -done - -rm -f "$PROJECT_DIR"/.helper-done-* -EPIC=$(bd list --json 2>/dev/null | jq -r '.[] | select(.type == "epic") | .id' | head -1) -[ -n "$EPIC" ] && bd label add "$EPIC" "milestone:helpers-done" 2>/dev/null || true -bd sync 2>/dev/null || true - -echo "$(date '+%H:%M:%S') Помощники завершены" -./scripts/notify.sh "Помощники завершены" "${HELPERS[*]}" 2>/dev/null || true diff --git a/core/scripts/set-milestones.sh b/core/scripts/set-milestones.sh deleted file mode 100755 index a3edb9f..0000000 --- a/core/scripts/set-milestones.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# Проставляет milestones для пропуска фаз планирования -# Использование: ./set-milestones.sh [milestone1 milestone2 ...] -# Пример: ./set-milestones.sh planning-done helpers-done plan-reviewed - -EPIC=$(bd list --json | jq -r '.[] | select(.type == "epic") | .id' | head -1) - -if [ -z "$EPIC" ]; then - echo "Эпик не найден. Создаю..." - bd create "EPIC: Project" -t epic -p 0 - EPIC=$(bd list --json | jq -r '.[] | select(.type == "epic") | .id' | head -1) -fi - -if [ $# -gt 0 ]; then - MILESTONES=("$@") -else - # По умолчанию все milestones планирования - MILESTONES=("planning-done" "helpers-done" "plan-reviewed") -fi - -for m in "${MILESTONES[@]}"; do - bd label add "$EPIC" "milestone:$m" 2>/dev/null && echo "✓ milestone:$m" -done - -echo "" -./scripts/detect-phase.sh diff --git a/docs/architecture.md b/docs/architecture.md index b5724d3..fad51bb 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,137 +1,205 @@ -# AI Development System +# Claudev Architecture -Автономная мульти-агентная система разработки с памятью в Beads. +Многоагентная AI-система автоматической разработки на базе Claude Code. -## Ключевые особенности +## Обзор -- **Менеджер с памятью** — состояние хранится в Beads, не теряется между вызовами -- **Автономная работа** — orchestrator пинает менеджера в цикле до завершения -- **Параллельные агенты** — помощники и кодеры работают одновременно -- **Атомарный захват задач** — кодеры не дублируют работу - -## Быстрый старт - -```bash -# 1. Установи зависимости -npm install -g @anthropic-ai/claude-code -brew install jq -# + beads - -# 2. Скопируй в проект -cp -r ai-dev-system/{.claude,scripts,CLAUDE.md} my-project/ -cd my-project -bd init --quiet -chmod +x scripts/*.sh - -# 3. Опиши ТЗ -vim SPEC.md - -# 4. Инициализируй и запусти -./scripts/init-manager.sh -./scripts/orchestrator.sh +``` +orchestrator.sh (bash loop с lock file) + │ + └─► Manager (Sonnet, stateless) + │ + ├─► detect-phase.sh → определяет текущую фазу + │ + └─► Запускает агентов по фазе: + ├─► Tech Writer (Opus) — собирает требования + ├─► Architect (Opus) — план, задачи, dependencies + ├─► Analysts (Sonnet × 5) — аудит плана + ├─► Executors (по задаче) — реализация в git ветках + └─► Senior Executor (Opus) — ревью, merge, релиз ``` -## Как это работает +## Фазы проекта ``` -┌─────────────────────────────────────────┐ -│ orchestrator.sh │ -│ │ -│ while true: │ -│ claude manager "Продолжи работу" │ -│ if PROJECT_COMPLETE: exit │ -│ sleep 10 │ -│ │ -└─────────────────┬────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────┐ -│ Manager (Claude) │ -│ │ -│ 1. bd show MANAGER → читает состояние │ -│ 2. Анализирует задачи │ -│ 3. Принимает решение │ -│ 4. Выполняет действие │ -│ 5. bd update MANAGER → сохраняет │ -│ │ -└─────────────────┬────────────────────────┘ - │ - ┌───────────┼───────────┐ - ▼ ▼ ▼ - Architect Helpers Coders - (Opus) (Sonnet×4) (dynamic) +INIT → PLANNING → HELPERS → PLAN_REVIEW → IMPLEMENTATION → FINAL_REVIEW → DONE ``` -## Состояние менеджера в Beads - -```json -{ - "phase": "IMPLEMENTATION", - "cycle": 15, - "helper_cycles": 2, - "last_action": "run-coders", - "last_decision": "8 задач open, запустил 2 кодеров", - "blockers_seen": ["bd-f3a1"], - "decisions": [ - {"cycle": 1, "action": "run-architect", "reason": "INIT"}, - {"cycle": 5, "action": "run-helpers", "reason": "План создан"}, - {"cycle": 10, "action": "run-coders", "reason": "План готов"}, - ... - ] -} +| Фаза | Условие перехода | Агент | Действие | +|------|-----------------|-------|----------| +| INIT | Нет SPEC.md | Tech Writer | Собирает требования от user | +| PLANNING | Есть SPEC.md | Architect | Создаёт задачи в beads | +| HELPERS | milestone:planning-done | Analysts ×5 | Параллельный аудит плана | +| PLAN_REVIEW | milestone:analysts-done | Architect | Ревьюит добавления Analysts | +| IMPLEMENTATION | milestone:plan-reviewed | Executors | Реализуют задачи | +| FINAL_REVIEW | Все задачи closed | Architect | Проверяет целостность | +| DONE | milestone:project-done | — | Проект завершён | + +## Агенты + +### Manager (Sonnet) +- **Роль:** Stateless координатор +- **Задача:** Определить фазу, запустить нужного агента, выйти +- **Не делает:** Не создаёт задачи, не пишет код + +### Tech Writer (Opus) +- **Роль:** Сбор требований +- **Задача:** Через диалог с user создать SPEC.md +- **Особенности:** Интерактивный режим, без timeout + +### Architect (Opus) +- **Роль:** Главный технический эксперт +- **Задачи:** + - Создание плана из SPEC.md + - Разбивка на мелкие задачи (1-5 мин) + - Расстановка dependencies + - Назначение модели каждой задаче + - Ревью добавлений от Analysts + - Разрешение конфликтов и эскалаций + +### Analysts (Sonnet × 5) +- **Роль:** Параллельный аудит плана +- **Виды:** + - UX — пользовательские сценарии, UI состояния + - Security — OWASP, auth, secrets + - OPS — тесты, CI/CD, мониторинг + - Reliability — edge cases, failure modes + - Architecture — структура кода, зависимости +- **Правило:** Только добавляют задачи, не удаляют + +### Executor (по задаче) +- **Роль:** Реализация одной задачи +- **Модель:** Из label задачи (model:haiku/sonnet/opus) +- **Workflow:** + 1. Claim задачу через `bd update --claim` + 2. Работает в ветке `task/beads-{id}` + 3. Rebase на main + 4. Push и пометить `needs-review` + +### Senior Executor (Opus) +- **Роль:** Quality gate перед main +- **Задачи:** + - Code review + - Проверка на secrets + - Запуск тестов + - Merge через PR (или local merge) + - Релиз + +## Скрипты + +| Скрипт | Назначение | +|--------|------------| +| `orchestrator.sh` | Главный цикл с lock file | +| `detect-phase.sh` | Определение текущей фазы | +| `run-analysts.sh` | Параллельный запуск 5 Analysts | +| `run-executors.sh` | Параллельный запуск Executors с backpressure | +| `log.sh` | Хелпер для логирования | +| `notify.sh` | Уведомления (macOS) | + +## Конфигурация + +`.claudev/config.sh`: + +```bash +MAX_PARALLEL_EXECUTORS=3 # Лимит параллельных Executors +RETRY_LIMIT=3 # Retry до эскалации к Architect +TASK_TIMEOUT="10m" # Таймаут на задачу +USER_INPUT_TIMEOUT="30m" # Таймаут ожидания user +CI_ENABLED=false # GitHub CI интеграция +CD_ENABLED=false # Автоматический релиз ``` -## Интеграция с существующим проектом +## Beads интеграция + +### Статусы задач + +- `open` — задача создана, ждёт исполнителя +- `in_progress` — Executor работает +- `in_progress` + `needs-review` — ждёт Senior Executor +- `closed` — завершено + +### Labels + +- `model:haiku/sonnet/opus` — какая модель выполняет +- `added-by:analyst-*` — кто добавил задачу +- `milestone:*` — маркер завершения фазы +- `retry:N` — счётчик повторных попыток +- `blocked:*` — причина блокировки + +### Dependencies ```bash -# Если задачи уже в Beads: +bd dep add +bd dep cycles # Проверка циклов +``` -# 1. Добавь модели -./scripts/add-models.sh sonnet +## Отказоустойчивость -# 2. Пропусти планирование -./scripts/set-milestones.sh planning-done helpers-done plan-reviewed +### Lock file +- Один orchestrator за раз +- Atomic через `set -C` (noclobber) +- Автоочистка stale lock -# 3. Инициализируй менеджера в нужной фазе -./scripts/init-manager.sh --phase IMPLEMENTATION --helper-cycles 2 +### Retry logic +- 3 попытки на задачу +- Счётчик в label `retry:N` +- После лимита — эскалация к Architect -# 4. Запусти -./scripts/orchestrator.sh +### Graceful shutdown +- `trap SIGINT SIGTERM` +- Reset stale tasks (>5min in_progress) +- Cleanup lock file + +### Config validation +- Проверка при каждой итерации +- Integers, booleans, timeouts +- Fail fast при ошибках + +## Git workflow + +``` +main + │ + ├── task/beads-abc ← Executor 1 + ├── task/beads-def ← Executor 2 + └── task/beads-ghi ← Executor 3 ``` -## Скрипты +1. Executor создаёт ветку от main +2. Работает, коммитит +3. Rebase на main (при конфликте — эскалация) +4. Push с `--force-with-lease` +5. Senior Executor мержит через PR + +## Backpressure -| Скрипт | Описание | -|--------|----------| -| `orchestrator.sh` | Главный цикл — пинает менеджера | -| `init-manager.sh` | Инициализация состояния менеджера | -| `run-helpers.sh` | Параллельный запуск помощников | -| `run-coders.sh` | Параллельный запуск кодеров | -| `claim-task.sh` | Атомарный захват задачи | -| `detect-phase.sh` | Определение фазы (legacy) | -| `add-models.sh` | Добавить model: labels | -| `set-milestones.sh` | Проставить milestones | -| `notify.sh` | macOS уведомления | +- Лимит = `MAX_PARALLEL_EXECUTORS` +- Считаем через beads (не gh pr list) +- Работает без GitHub -## Переменные окружения +## Логирование + +Формат: `YYYY-MM-DD HH:MM:SS [AGENT] EVENT: message` ```bash -MAX_CYCLES=100 # Лимит итераций orchestrator -PAUSE_SECONDS=10 # Пауза между вызовами менеджера +./scripts/log.sh MANAGER INFO "Starting phase detection" +./scripts/log.sh EXECUTOR TASK_START "claudev-abc" +./scripts/log.sh ORCHESTRATOR FATAL "Beads daemon not running" ``` -## Отладка +## Установка ```bash -# Логи orchestrator -tail -f logs/orchestrator.log - -# Логи конкретного цикла менеджера -cat logs/manager-15.log +cd your-project +git clone .claudev +.claudev/install.sh +./scripts/orchestrator.sh +``` -# Состояние менеджера -bd list --json | jq '.[] | select(.labels | index("role:manager")) | .description | fromjson' +## Зависимости -# Сбросить и начать заново -./scripts/init-manager.sh --reset -``` +- **beads** — управление задачами +- **claude** — Claude Code CLI +- **gh** — GitHub CLI (опционально) +- **jq** — JSON processing +- **gitleaks** — secret detection (опционально) diff --git a/install.sh b/install.sh index 3a7953d..3f901ef 100755 --- a/install.sh +++ b/install.sh @@ -4,41 +4,235 @@ # Устанавливает систему в целевой проект # # Использование: -# git clone git@github.com:user/claudev.git .claudev -# .claudev/install.sh +# .claudev/install.sh # Интерактивный режим +# .claudev/install.sh --auto-install # Автоустановка зависимостей # set -euo pipefail -# Определяем директории +# === Определяем директории === + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TARGET_DIR="$(dirname "$SCRIPT_DIR")" CLAUDEV_DIR_NAME="$(basename "$SCRIPT_DIR")" +AUTO_INSTALL="${1:-}" echo "=== Claudev Installer ===" echo "Claudev dir: $SCRIPT_DIR" echo "Target dir: $TARGET_DIR" echo "" -# Проверяем что запускаем из подпапки проекта +# === Проверка директории === + if [[ "$SCRIPT_DIR" == "$TARGET_DIR" ]]; then - echo "Error: claudev должен быть клонирован в подпапку проекта" + echo "Error: claudev должен быть в подпапке проекта" echo "" echo "Правильно:" echo " cd your-project" - echo " git clone .claudev" - echo " .claudev/install.sh" + echo " curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash" exit 1 fi -# Проверяем наличие core/ if [[ ! -d "$SCRIPT_DIR/core" ]]; then echo "Error: не найдена папка core/ в $SCRIPT_DIR" exit 1 fi -# Создаём .claude/ с симлинками -echo "Creating .claude/ directory..." +# === Определяем систему === + +OS="unknown" +if [[ "$OSTYPE" == "darwin"* ]]; then + OS="macos" +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + OS="linux" +fi + +# === Функции установки === + +install_homebrew() { + if ! command -v brew &>/dev/null; then + echo "Homebrew не найден, устанавливаю..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + # Добавляем brew в PATH для текущей сессии + if [[ -f "/opt/homebrew/bin/brew" ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -f "/usr/local/bin/brew" ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi + echo " ✓ Homebrew установлен" + fi +} + +install_with_brew() { + local pkg=$1 + local cmd=${2:-$1} + + if ! command -v "$cmd" &>/dev/null; then + echo " Устанавливаю $pkg через brew..." + brew install "$pkg" + echo " ✓ $pkg установлен" + fi +} + +install_with_apt() { + local pkg=$1 + local cmd=${2:-$1} + + if ! command -v "$cmd" &>/dev/null; then + echo " Устанавливаю $pkg через apt..." + sudo apt install -y "$pkg" + echo " ✓ $pkg установлен" + fi +} + +install_claude_code() { + if ! command -v claude &>/dev/null; then + echo " Устанавливаю Claude Code (официальный скрипт)..." + curl -fsSL https://claude.ai/install.sh | bash + echo " ✓ Claude Code установлен" + fi +} + +# === Проверка и установка зависимостей === + +echo "Проверяю зависимости..." +echo "" + +if [[ "$AUTO_INSTALL" == "--auto-install" ]]; then + + # === macOS === + if [[ "$OS" == "macos" ]]; then + install_homebrew + + echo "Устанавливаю зависимости (macOS)..." + install_with_brew "beads" "bd" + install_with_brew "gh" + install_with_brew "jq" + install_claude_code + + # gitleaks опционально + if ! command -v gitleaks &>/dev/null; then + echo " Устанавливаю gitleaks (опционально)..." + brew install gitleaks || echo " - gitleaks пропущен" + fi + + # === Linux === + elif [[ "$OS" == "linux" ]]; then + if command -v apt &>/dev/null; then + echo "Устанавливаю зависимости (Linux/apt)..." + sudo apt update + + install_with_apt "gh" + install_with_apt "jq" + install_claude_code + + # beads через npm на Linux (если нет brew) + if ! command -v bd &>/dev/null; then + if command -v npm &>/dev/null; then + echo " Устанавливаю beads через npm..." + npm install -g beads + echo " ✓ beads установлен" + else + echo " Warning: npm не найден, beads нужно установить вручную" + fi + fi + else + echo "Error: apt не найден. Установите зависимости вручную." + exit 1 + fi + else + echo "Error: неизвестная система ($OS)" + exit 1 + fi + +else + # === Без автоустановки — только проверка === + + missing=() + + command -v bd &>/dev/null || missing+=("beads") + command -v claude &>/dev/null || missing+=("claude-code") + command -v gh &>/dev/null || missing+=("gh") + command -v jq &>/dev/null || missing+=("jq") + + if [ ${#missing[@]} -gt 0 ]; then + echo "Не хватает: ${missing[*]}" + echo "" + echo "Установите вручную или запустите:" + echo " $SCRIPT_DIR/install.sh --auto-install" + exit 1 + fi +fi + +# === Проверяем что всё установлено === + +echo "" +echo "Проверяю установку..." + +check_cmd() { + local cmd=$1 + local name=${2:-$1} + if command -v "$cmd" &>/dev/null; then + echo " ✓ $name" + else + echo " ✗ $name НЕ УСТАНОВЛЕН" + return 1 + fi +} + +check_cmd "bd" "beads" +check_cmd "claude" "claude-code" +check_cmd "gh" "gh (GitHub CLI)" +check_cmd "jq" "jq" + +GITLEAKS_AVAILABLE=false +command -v gitleaks &>/dev/null && GITLEAKS_AVAILABLE=true +if [ "$GITLEAKS_AVAILABLE" = true ]; then + echo " ✓ gitleaks (опционально)" +else + echo " - gitleaks (опционально, не установлен)" +fi + +# === Git === + +echo "" +echo "Настраиваю git..." + +cd "$TARGET_DIR" + +if [[ ! -d ".git" ]]; then + echo " Инициализирую git репозиторий..." + git init + echo " ✓ git init" +else + echo " ✓ .git/ существует" +fi + +# Проверяем remote +if ! git remote -v | grep -q origin; then + echo " - Warning: нет git remote" + echo " Добавьте позже: git remote add origin " +fi + +# === Beads === + +echo "" +echo "Настраиваю beads..." + +if [[ ! -d ".beads" ]]; then + echo " Инициализирую beads..." + bd init + echo " ✓ bd init" +else + echo " ✓ .beads/ существует" +fi + +# === Создаём .claude/ с симлинками === + +echo "" +echo "Создаю симлинки..." + mkdir -p "$TARGET_DIR/.claude" # Симлинк на agents @@ -46,7 +240,7 @@ if [[ -L "$TARGET_DIR/.claude/agents" ]]; then rm "$TARGET_DIR/.claude/agents" fi if [[ -d "$TARGET_DIR/.claude/agents" ]]; then - echo "Warning: .claude/agents/ уже существует как папка, пропускаю" + echo " - .claude/agents/ уже папка, пропускаю" else ln -s "../$CLAUDEV_DIR_NAME/core/agents" "$TARGET_DIR/.claude/agents" echo " ✓ .claude/agents -> $CLAUDEV_DIR_NAME/core/agents" @@ -57,7 +251,7 @@ if [[ -L "$TARGET_DIR/.claude/commands" ]]; then rm "$TARGET_DIR/.claude/commands" fi if [[ -d "$TARGET_DIR/.claude/commands" ]]; then - echo "Warning: .claude/commands/ уже существует как папка, пропускаю" + echo " - .claude/commands/ уже папка, пропускаю" else ln -s "../$CLAUDEV_DIR_NAME/core/commands" "$TARGET_DIR/.claude/commands" echo " ✓ .claude/commands -> $CLAUDEV_DIR_NAME/core/commands" @@ -68,41 +262,91 @@ if [[ -L "$TARGET_DIR/scripts" ]]; then rm "$TARGET_DIR/scripts" fi if [[ -d "$TARGET_DIR/scripts" ]]; then - echo "Warning: scripts/ уже существует как папка, пропускаю" + echo " - scripts/ уже папка, пропускаю" else ln -s "$CLAUDEV_DIR_NAME/core/scripts" "$TARGET_DIR/scripts" echo " ✓ scripts -> $CLAUDEV_DIR_NAME/core/scripts" fi -# Копируем шаблоны (если не существуют) +# === Копируем config === + echo "" -echo "Copying templates..." +echo "Настраиваю конфиг..." -if [[ -f "$TARGET_DIR/SPEC.md" ]]; then - echo " - SPEC.md уже существует, пропускаю" -else - cp "$SCRIPT_DIR/templates/SPEC.template.md" "$TARGET_DIR/SPEC.md" - echo " ✓ SPEC.md создан" -fi +mkdir -p "$TARGET_DIR/.claudev" -if [[ -f "$TARGET_DIR/CLAUDE.md" ]]; then - echo " - CLAUDE.md уже существует, пропускаю" +if [[ -f "$TARGET_DIR/.claudev/config.sh" ]]; then + echo " - config.sh уже существует" else - cp "$SCRIPT_DIR/templates/CLAUDE.template.md" "$TARGET_DIR/CLAUDE.md" - echo " ✓ CLAUDE.md создан" + cp "$SCRIPT_DIR/templates/config.template.sh" "$TARGET_DIR/.claudev/config.sh" + echo " ✓ .claudev/config.sh создан" fi -# Создаём рабочие директории +# === Рабочие директории === + echo "" -echo "Creating work directories..." -mkdir -p "$TARGET_DIR/logs" "$TARGET_DIR/worktrees" +echo "Создаю рабочие директории..." +mkdir -p "$TARGET_DIR/logs/archive" +mkdir -p "$TARGET_DIR/stats" echo " ✓ logs/" -echo " ✓ worktrees/" +echo " ✓ stats/" + +# === Pre-commit hook (если gitleaks есть) === + +if [ "$GITLEAKS_AVAILABLE" = true ]; then + echo "" + echo "Настраиваю pre-commit hook..." + + HOOK_FILE="$TARGET_DIR/.git/hooks/pre-commit" + + if [[ -f "$HOOK_FILE" ]] && grep -q "gitleaks" "$HOOK_FILE"; then + echo " - gitleaks уже в pre-commit" + else + mkdir -p "$TARGET_DIR/.git/hooks" + cat >> "$HOOK_FILE" << 'EOF' +#!/bin/bash +# Gitleaks secret detection (added by claudev) +gitleaks protect --staged --verbose +EOF + chmod +x "$HOOK_FILE" + echo " ✓ pre-commit hook с gitleaks" + fi +fi + +# === .gitignore === + +echo "" +echo "Обновляю .gitignore..." + +GITIGNORE="$TARGET_DIR/.gitignore" +touch "$GITIGNORE" +add_to_gitignore() { + local pattern=$1 + if ! grep -q "^${pattern}$" "$GITIGNORE" 2>/dev/null; then + echo "$pattern" >> "$GITIGNORE" + echo " + $pattern" + fi +} + +add_to_gitignore ".env" +add_to_gitignore ".env.*" +add_to_gitignore "*.pem" +add_to_gitignore "*.key" +add_to_gitignore "credentials.*" +add_to_gitignore "secrets/" +add_to_gitignore "logs/" +add_to_gitignore ".claudev/orchestrator.lock" + +# === Финиш === + +echo "" +echo "==========================================" +echo " Claudev установлен!" +echo "==========================================" echo "" -echo "=== Installation complete ===" +echo "Запустите систему:" +echo " ./scripts/orchestrator.sh" echo "" -echo "Следующие шаги:" -echo " 1. Заполните SPEC.md спецификацией проекта" -echo " 2. Запустите систему: ./scripts/orchestrator.sh" +echo "Tech Writer спросит что вы хотите создать." echo "" diff --git a/invite.sh b/invite.sh new file mode 100755 index 0000000..0616e93 --- /dev/null +++ b/invite.sh @@ -0,0 +1,142 @@ +#!/bin/bash +# +# Claudev Invite Script +# One-liner установка виртуального отдела разработки +# +# Использование: +# curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash +# +# Или с конкретной веткой/тегом: +# curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash -s -- v0.1 +# + +set -euo pipefail + +REPO="${CLAUDEV_REPO:-https://github.com/Puremag1c/claudev.git}" +BRANCH="${1:-main}" +TARGET=".claudev" + +echo "=== Claudev Invite ===" +echo "" + +# === Определяем систему === + +OS="unknown" +if [[ "$OSTYPE" == "darwin"* ]]; then + OS="macos" +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + OS="linux" +elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "win32" ]]; then + OS="windows" +fi + +# === Windows: требуется WSL === + +if [[ "$OS" == "windows" ]]; then + echo "Windows detected." + echo "" + echo "Claudev требует WSL (Windows Subsystem for Linux)." + echo "" + echo "1. Установите WSL (откройте PowerShell как администратор):" + echo " wsl --install" + echo "" + echo "2. Перезагрузите компьютер" + echo "" + echo "3. Откройте Ubuntu из меню Пуск и запустите:" + echo " curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash" + echo "" + exit 1 +fi + +echo "Система: $OS" +echo "" + +# === Устанавливаем git если нужно === + +if ! command -v git &>/dev/null; then + echo "Git не найден, устанавливаю..." + + if [[ "$OS" == "macos" ]]; then + # macOS: через Xcode Command Line Tools + echo "Запускаю xcode-select --install..." + echo "Следуйте инструкциям в появившемся окне." + xcode-select --install 2>/dev/null || true + + # Ждём установки + echo "Ожидаю завершения установки Xcode CLI..." + until command -v git &>/dev/null; do + sleep 5 + done + echo " ✓ Git установлен" + + elif [[ "$OS" == "linux" ]]; then + # Linux: через apt + if command -v apt &>/dev/null; then + echo "Устанавливаю через apt..." + sudo apt update && sudo apt install -y git + echo " ✓ Git установлен" + else + echo "Error: apt не найден. Установите git вручную." + exit 1 + fi + else + echo "Error: неизвестная система. Установите git вручную." + exit 1 + fi +fi + +echo " ✓ Git: $(git --version)" + +# === Проверяем что не в корне системы === + +if [ "$PWD" = "/" ] || [ "$PWD" = "$HOME" ]; then + echo "" + echo "Error: запустите из директории проекта, не из / или ~" + echo "" + echo "Пример:" + echo " mkdir my-project && cd my-project" + echo " curl -fsSL https://raw.githubusercontent.com/Puremag1c/claudev/main/invite.sh | bash" + exit 1 +fi + +# === Проверяем существующую установку === + +if [ -d "$TARGET" ]; then + echo "" + echo "Claudev уже установлен в $TARGET/" + echo "" + read -p "Переустановить? (y/N) " -n 1 -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Отменено" + exit 0 + fi + rm -rf "$TARGET" +fi + +# === Клонируем === + +echo "" +echo "Клонирую claudev ($BRANCH)..." +git clone --depth 1 --branch "$BRANCH" "$REPO" "$TARGET" 2>/dev/null || \ +git clone --depth 1 "$REPO" "$TARGET" + +# Удаляем .git (не нужен, обновления через переустановку) +rm -rf "$TARGET/.git" + +# Удаляем файлы разработки — пользователю не нужны +rm -f "$TARGET/README.md" +rm -f "$TARGET/PROJECT.md" +rm -f "$TARGET/CLAUDE.md" +rm -f "$TARGET/AGENTS.md" +rm -f "$TARGET/invite.sh" +rm -rf "$TARGET/.beads" +rm -rf "$TARGET/docs" + +echo "" +echo "Запускаю установщик..." +echo "" + +# === Запускаем install.sh === + +"$TARGET/install.sh" --auto-install diff --git a/templates/CLAUDE.template.md b/templates/CLAUDE.template.md index 3c95401..7d69b86 100644 --- a/templates/CLAUDE.template.md +++ b/templates/CLAUDE.template.md @@ -1,104 +1,74 @@ # Project Instructions -Многоагентная AI-система разработки с памятью в Beads. +Claudev — многоагентная AI-система разработки. ## Архитектура ``` orchestrator.sh (bash loop) │ - └─► Manager (Claude Sonnet) + └─► Manager (Sonnet, stateless) │ - ├─► Читает состояние из Beads - ├─► Принимает решение - ├─► Выполняет действие - ├─► Сохраняет состояние в Beads + ├─► Определяет фазу + ├─► Запускает агентов │ - └─► Вызывает агентов: - ├─► Architect (Opus) - ├─► Helpers (Sonnet × 4) - ├─► Analyst (Sonnet) - ├─► Coders (по задаче) - └─► Reviewers (Sonnet) + └─► Агенты: + ├─► Tech Writer (Opus) — собирает требования + ├─► Architect (Opus) — план, задачи, dependencies + ├─► Analysts (Sonnet × 5) — аудит плана + ├─► Executors (по задаче) — реализация + └─► Senior Executor (Opus) — ревью, merge ``` ## Запуск ```bash -# 1. Инициализируй состояние менеджера (один раз) -./scripts/init-manager.sh - -# 2. Запусти orchestrator +# Запустить систему ./scripts/orchestrator.sh -# Или в фоне +# В фоне nohup ./scripts/orchestrator.sh & -tail -f logs/orchestrator.log +tail -f logs/claudev.log ``` -## Состояние менеджера +## Фазы -Хранится в Beads как задача с label `role:manager`: +| Фаза | Описание | +|------|----------| +| INIT | Нет SPEC.md → Tech Writer собирает требования | +| PLANNING | Architect создаёт план из SPEC.md | +| HELPERS | 5 Analysts аудитят план параллельно | +| PLAN_REVIEW | Architect ревьюит добавления Analysts | +| IMPLEMENTATION | Executors реализуют задачи | +| FINAL_REVIEW | Architect проверяет целостность | +| DONE | Проект завершён | -```json -{ - "phase": "IMPLEMENTATION", - "cycle": 15, - "helper_cycles": 2, - "last_action": "run-coders", - "decisions": [...] -} -``` +## Полезные команды -Посмотреть: ```bash -bd list --json | jq '.[] | select(.labels | index("role:manager"))' -``` +bd ready # Готовые к работе задачи +bd list # Все задачи +bd list --status=in_progress # Задачи в работе +bd show # Детали задачи -## Команды +./scripts/orchestrator.sh # Запустить систему +./scripts/detect-phase.sh # Определить текущую фазу +``` -```bash -./scripts/init-manager.sh # Инициализация -./scripts/init-manager.sh --reset # Сброс состояния -./scripts/init-manager.sh --phase IMPLEMENTATION # Установить фазу +## Конфигурация -./scripts/orchestrator.sh # Главный цикл -./scripts/detect-phase.sh # Определить фазу (legacy) -./scripts/run-helpers.sh # Запустить помощников -./scripts/run-coders.sh 3 # Запустить 3 кодеров +Редактируйте `.claudev/config.sh`: -./scripts/add-models.sh sonnet # Добавить модели к задачам -./scripts/set-milestones.sh ... # Проставить milestones +```bash +MAX_PARALLEL_EXECUTORS=3 # Параллельные Executors +RETRY_LIMIT=3 # Retry перед эскалацией +TASK_TIMEOUT="10m" # Таймаут на задачу ``` -## Интеграция с существующим проектом +## Логи ```bash -# 1. Скопируй систему -cp -r ai-dev-system/{.claude,scripts,CLAUDE.md} . -chmod +x scripts/*.sh - -# 2. Добавь модели к задачам -./scripts/add-models.sh sonnet - -# 3. Проставь milestones -./scripts/set-milestones.sh planning-done helpers-done plan-reviewed - -# 4. Инициализируй менеджера с нужной фазой -./scripts/init-manager.sh --phase IMPLEMENTATION --helper-cycles 2 - -# 5. Запусти -./scripts/orchestrator.sh +tail -f logs/claudev.log # Основной лог +ls logs/archive/ # Архив итераций +cat logs/executor-.log # Лог конкретного executor ``` - -## Фазы - -| Фаза | Описание | -|------|----------| -| INIT | Начало, нет плана | -| PLANNING | Архитектор создаёт план | -| HELPERS | Помощники аудитят | -| PLAN_REVIEW | Ревью + Аналитик | -| IMPLEMENTATION | Кодеры работают | -| FINAL_REVIEW | Тесты + финальное ревью | -| DONE | Завершено | diff --git a/templates/SPEC.template.md b/templates/SPEC.template.md index 2ed4390..c2041b4 100644 --- a/templates/SPEC.template.md +++ b/templates/SPEC.template.md @@ -1,12 +1,26 @@ -# [Название проекта] +# Project Specification -## Описание -Что это и зачем. +## Vision +[1-2 предложения: что это и зачем] -## Требования -- [ ] Требование 1 -- [ ] Требование 2 +## Target Audience +[Для кого продукт] -## Стек -- Backend: ... -- Database: ... +## MVP Scope +[Что минимум нужно для первого релиза] + +### Must Have +- [ ] Feature 1 +- [ ] Feature 2 + +### Nice to Have +- [ ] Feature 3 + +## User Stories +- As a [user], I want [feature] so that [benefit] + +## Technical Notes (optional) +[Предпочтения по стеку, ограничения] + +## Open Questions (for Architect) +[Что осталось неопределённым — Architect решит] diff --git a/templates/config.template.sh b/templates/config.template.sh new file mode 100644 index 0000000..95381e3 --- /dev/null +++ b/templates/config.template.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# .claudev/config.sh — конфигурация Claudev +# Скопировано из templates/config.template.sh при установке +# +# Редактируйте значения под свой проект. +# Orchestrator перечитывает этот файл каждую итерацию. + +# === Основные настройки === + +# Максимум параллельных Executor агентов +MAX_PARALLEL_EXECUTORS=3 + +# Лимит retry перед эскалацией к Architect +RETRY_LIMIT=3 + +# Пауза между итерациями orchestrator (seconds) +ITERATION_DELAY=30 + +# === Таймауты === + +# Таймаут выполнения задачи агентом +TASK_TIMEOUT="10m" + +# Таймаут ожидания ввода пользователя (Tech Writer) +USER_INPUT_TIMEOUT="30m" + +# === CI/CD === + +# Включить интеграцию с GitHub CI +CI_ENABLED=false + +# Включить автоматический релиз (CD) +CD_ENABLED=false + +# === Логирование === + +# Логировать оценку токенов (для анализа расхода) +LOG_TOKENS=false + +# === Cleanup === + +# Автоматически удалять старые логи +CLEANUP_ENABLED=false + +# Хранить логи N дней (если CLEANUP_ENABLED=true) +CLEANUP_KEEP_DAYS=30