Compare commits
1
Commits
dev
..
f1afa787be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1afa787be |
@@ -0,0 +1,75 @@
|
||||
# Analysis Report
|
||||
|
||||
## Session
|
||||
|
||||
- **Session ID:** `metaagent-002`
|
||||
- **Target repo:** `S:\Git\nifodea`
|
||||
- **Date:** 2026-07-12
|
||||
- **Project type:** `existing`
|
||||
|
||||
## 1. Общая информация
|
||||
|
||||
- **README:** CashFlow Forecast — личная финансовая модель с прогнозом денежных потоков, сценарным анализом и AI-ассистентом
|
||||
- **Лицензия:** не указана
|
||||
- **CI/CD:** отсутствует
|
||||
- **Точка входа:** `cli/main.py:app` (команда `cf`)
|
||||
- **Система сборки:** `pyproject.toml` (setuptools)
|
||||
|
||||
## 2. Стек технологий
|
||||
|
||||
| Компонент | Значение |
|
||||
|---|---|
|
||||
| Язык | Python 3.11+ (фактически 3.13) |
|
||||
| Фреймворк | Typer (CLI), openpyxl (Excel) |
|
||||
| База данных | JSON-файлы |
|
||||
| Тестовый раннер | pytest |
|
||||
| Пакетный менеджер | pip + venv |
|
||||
| Линтер | ruff |
|
||||
|
||||
## 3. Архитектура
|
||||
|
||||
**Паттерн:** Модульный монолит (Layered)
|
||||
|
||||
```
|
||||
cli/ → sync/ ⇒ cashflow_model/ ⇔ engine/ → ai/
|
||||
(Excel) (Entity Model) (Forecast) (Prompts)
|
||||
```
|
||||
|
||||
**Модули:**
|
||||
- `cashflow_model/` — сущности dataclass + JSON сериализация (Account, Transaction, RecurringCashflow, Asset, Liability, ForecastScenario, FinancialModel)
|
||||
- `engine/` — ForecastService (прогноз), ScenarioService (сценарии + what-if)
|
||||
- `sync/` — ExcelSync (импорт/экспорт .xlsx через openpyxl)
|
||||
- `ai/` — AssistantService (промпты, заглушка), PromptsTemplate
|
||||
- `cli/` — Typer CLI (init, forecast, scenario, whatif, compare, import, export, analyze)
|
||||
- `tests/` — pytest тесты (26 tests)
|
||||
|
||||
**Внешние зависимости:** openpyxl, typer, rich
|
||||
|
||||
## 4. Конвенции кода
|
||||
|
||||
- **Стиль:** ruff (E, F, I, N, W), line-length=100
|
||||
- **Именование:** snake_case для функций/переменных, PascalCase для классов
|
||||
- **Типизация:** аннотации типов
|
||||
- **Обработка ошибок:** кастомные исключения (ModelError, SyncError, ForecastError)
|
||||
- **Логирование:** не используется
|
||||
|
||||
## 5. Тесты
|
||||
|
||||
- **Типы:** unit-тесты
|
||||
- **Расположение:** `tests/`
|
||||
- **Запуск:** `pytest`
|
||||
- **Текущее состояние:** 26/26 passed (100%)
|
||||
- **Покрытие:** не измеряется
|
||||
|
||||
## 6. Базовая проверка
|
||||
|
||||
- **Сборка:** pip install -e . — success
|
||||
- **Импорты:** все модули импортируются без ошибок
|
||||
- **Линтер:** ruff check — All checks passed
|
||||
- **Git status:** clean
|
||||
|
||||
## 7. Примечания
|
||||
|
||||
- Проект полностью реализован (MVP)
|
||||
- AI-ассистент — заглушка, промпты готовы
|
||||
- Лицензия не выбрана — требуется решение
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"archived_at": "2026-10-08T17:05:00Z",
|
||||
"session": "metaagent-005",
|
||||
"goal": "Обсуждение архитектуры и серьёзный refactor",
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "Реструктуризация в domain/application/infrastructure + version=1", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T1", "commit": "feb77ef" },
|
||||
{ "id": "T2", "title": "Pydantic v2 — миграция моделей", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T2", "commit": "c765f36" },
|
||||
{ "id": "T3", "title": "Decimal для денег", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T3", "commit": "363d440" },
|
||||
{ "id": "T4", "title": "Repository pattern — ModelRepository", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T4" },
|
||||
{ "id": "T5", "title": "Dependency Injection в сервисах", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T5", "commit": "541a768" },
|
||||
{ "id": "T6", "title": "Декомпозиция CLI", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T6" },
|
||||
{ "id": "T7", "title": "Финальная валидация", "archived_at": "2026-10-08T17:05:00Z", "request": "req-T7", "commit": "3ef1061" }
|
||||
],
|
||||
"requests": [
|
||||
{ "id": "req-T1", "task_id": "T1", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T2", "task_id": "T2", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T3", "task_id": "T3", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T4", "task_id": "T4", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T5", "task_id": "T5", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T6", "task_id": "T6", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" },
|
||||
{ "id": "req-T7", "task_id": "T7", "status": "approved", "archived_at": "2026-10-08T17:05:00Z" }
|
||||
],
|
||||
"checkpoints": []
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T1",
|
||||
"task_id": "T1",
|
||||
"title": "Restructure to domain/application/infrastructure + schema version 1",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Ввести явные слои и подготовить инфраструктуру миграций схемы",
|
||||
"changes": {
|
||||
"summary": "Перестроена пакетная структура: cashflow_model/ → domain/ (модели), engine/ → application/ (сервисы), cli/, sync/, ai/ → infrastructure/ (адаптеры). Обновлены все импорты в коде и тестах. В FinancialModel добавлено поле version=1 в to_dict() и миграционный хук _from_v0/_from_v1 в from_dict() для обратной совместимости. Обновлён pyproject.toml: cf = infrastructure.cli.main:app, packages.find = ['domain*', 'application*', 'infrastructure*'].",
|
||||
"commits": ["feb77ef217a54720868218b911312b040bcfb118"],
|
||||
"files_changed": [
|
||||
"domain/ (new, 8 файлов из cashflow_model/)",
|
||||
"application/ (new, 3 файла из engine/)",
|
||||
"infrastructure/ai/ (new, из ai/)",
|
||||
"infrastructure/cli/ (new, из cli/)",
|
||||
"infrastructure/sync/ (new, из sync/)",
|
||||
"tests/* (8 файлов, импорты обновлены)",
|
||||
"pyproject.toml (cf entry + packages.find)",
|
||||
"data/model.json (version=1)"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "63/63",
|
||||
"lsp_clean": true,
|
||||
"cf_command_works": true,
|
||||
"round_trip_v1": "ok",
|
||||
"legacy_v0_load": "ok"
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"Структура domain/application/infrastructure создана",
|
||||
"Все исходные файлы перемещены в соответствующие слои",
|
||||
"Все импорты обновлены",
|
||||
"FinancialModel.to_dict() возвращает {'version': 1, ...}",
|
||||
"FinancialModel.from_dict() поддерживает v0 и v1",
|
||||
"pytest проходит 63/63"
|
||||
]
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T2",
|
||||
"task_id": "T2",
|
||||
"title": "Pydantic v2 — replace @dataclass with BaseModel",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Заменить ручную сериализацию на pydantic.BaseModel, добавить валидацию",
|
||||
"changes": {
|
||||
"summary": "Все 7 моделей domain/ переведены с @dataclass на pydantic.BaseModel. Удалены ручные to_dict()/from_dict() — заменены на model_dump(mode='json')/model_validate(). Добавлены field_validators: Account.balance >= 0, Transaction.amount != 0, RecurringCashflow.amount != 0 и frequency ∈ {daily,weekly,monthly,yearly}, Liability.interest/payment >= 0, ExchangeRate.rate > 0, ForecastScenario.multipliers >= 0. UUID в JSON автоматически сериализуется как str. excel_sync.py адаптирован на model_validate(). Тесты test_model.py и test_currency.py обновлены. pyproject.toml: pydantic>=2.0.",
|
||||
"commits": ["c765f36"],
|
||||
"files_changed": [
|
||||
"domain/account.py, asset.py, currency.py, liability.py, recurring.py, scenario.py, transaction.py, model.py",
|
||||
"infrastructure/sync/excel_sync.py",
|
||||
"tests/test_model.py, tests/test_currency.py",
|
||||
"pyproject.toml"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "63/63",
|
||||
"validators_work": "Account negative balance, Transaction zero amount, ExchangeRate negative rate — all rejected",
|
||||
"uuid_in_json_as_str": true,
|
||||
"round_trip": "ok",
|
||||
"cf_init_works": true,
|
||||
"cf_forecast_works": true,
|
||||
"cf_scenario_works": true
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"Все модели domain/ — наследники pydantic.BaseModel",
|
||||
"Удалены ручные to_dict() и from_dict()",
|
||||
"UUID в JSON сериализуется как строка",
|
||||
"Валидация работает (balance, amount, rate, frequency)",
|
||||
"Excel-sync адаптирован под pydantic",
|
||||
"pytest 63/63"
|
||||
]
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T3",
|
||||
"task_id": "T3",
|
||||
"title": "Decimal for money",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Точность финансовых расчётов — float → Decimal",
|
||||
"changes": {
|
||||
"summary": "Все денежные поля в domain/ переведены с float на Decimal. CurrencyConverter использует Decimal арифметику с ROUND_HALF_UP до 2 знаков. ForecastService и ScenarioService переписаны для работы с Decimal. assistant.py получил _DecimalEncoder для json.dumps (Decimal → str в JSON).",
|
||||
"commits": ["363d440"],
|
||||
"files_changed": [
|
||||
"domain/account.py, asset.py, currency.py, liability.py, recurring.py, scenario.py, transaction.py",
|
||||
"application/forecast.py, scenarios.py",
|
||||
"infrastructure/ai/assistant.py"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "63/63",
|
||||
"decimal_preserved": "100.50 round-trip exact (no float drift)",
|
||||
"json_safe": "Decimal → str via model_dump(mode='json'), back via model_validate",
|
||||
"cf_init_forecast_scenario_works": true
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"Все monetary поля — Decimal",
|
||||
"CurrencyConverter работает с Decimal",
|
||||
"ForecastService арифметика — Decimal",
|
||||
"Excel-sync продолжает работать",
|
||||
"rich.print/f-strings форматируют Decimal",
|
||||
"JSON-сериализация Decimal работает (через pydantic и _DecimalEncoder)",
|
||||
"pytest 63/63"
|
||||
]
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T4",
|
||||
"task_id": "T4",
|
||||
"title": "Repository pattern — ModelRepository, JsonFileRepository, ExcelRepository",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Абстрагировать хранилище FinancialModel через Protocol, подготовить к БД/API",
|
||||
"changes": {
|
||||
"summary": "Создан application/repositories/ с ModelRepository Protocol (runtime_checkable). Реализации: infrastructure/repositories/JsonFileRepository (.json с version) и ExcelRepository (бывший ExcelSync, переименован). FinancialModel.save/load удалены — класс хранит только данные. infrastructure/sync/ удалён. CLI (main.py, config.py) использует JsonFileRepository + ExcelRepository через локальные singletons. test_excel_sync.py обновлён на ExcelRepository. Новый test_repositories.py: 5 тестов.",
|
||||
"commits": ["<see git log>"],
|
||||
"files_changed": [
|
||||
"application/repositories/__init__.py, model_repository.py (new)",
|
||||
"infrastructure/repositories/__init__.py, json_file_repository.py, excel_repository.py (new)",
|
||||
"infrastructure/sync/ (removed)",
|
||||
"domain/model.py (save/load удалены)",
|
||||
"infrastructure/cli/main.py, config.py (используют repositories)",
|
||||
"tests/test_excel_sync.py, test_model.py, test_repositories.py (new)"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "68/68",
|
||||
"new_tests": 5,
|
||||
"json_repo_roundtrip": "ok",
|
||||
"excel_repo_roundtrip": "ok",
|
||||
"cf_init_works": true,
|
||||
"cf_export_import_xlsx_works": true
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"ModelRepository Protocol определён",
|
||||
"JsonFileRepository реализует Protocol",
|
||||
"ExcelRepository реализует Protocol",
|
||||
"FinancialModel.save/load удалены",
|
||||
"Тесты на каждый репозиторий",
|
||||
"pytest 68/68"
|
||||
]
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T5",
|
||||
"task_id": "T5",
|
||||
"title": "Dependency Injection — services через composition root",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Убрать создание сервисов внутри других сервисов, инжектировать зависимости",
|
||||
"changes": {
|
||||
"summary": "AssistantService теперь принимает ForecastService через __init__ (раньше создавал new ForecastService() внутри analyze/advice). В infrastructure/cli/main.py добавлен _build_services() — composition root, собирающий граф зависимостей: CurrencyConverter, ForecastService, ScenarioService, AssistantService. Все CLI-команды (forecast, scenario, whatif, compare, analyze) используют _build_services(model) вместо прямого создания сервисов. test_ai.py обновлён.",
|
||||
"commits": ["541a768"],
|
||||
"files_changed": [
|
||||
"infrastructure/ai/assistant.py",
|
||||
"infrastructure/cli/main.py",
|
||||
"tests/test_ai.py"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "67/67",
|
||||
"no_internal_service_creation": "AssistantService больше не создаёт ForecastService внутри",
|
||||
"composition_root": "_build_services() в main.py",
|
||||
"cf_init_forecast_scenario_compare_whatif_analyze_works": true
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"ForecastService(model) — через __init__",
|
||||
"ScenarioService(model) — через __init__",
|
||||
"AssistantService(model, forecast_service, converter) — через __init__",
|
||||
"Нет new ForecastService() внутри AssistantService",
|
||||
"CLI: composition root собирает граф",
|
||||
"pytest 67/67"
|
||||
]
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T6",
|
||||
"task_id": "T6",
|
||||
"title": "Decompose CLI — 9 command files + config sub-typer",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Улучшить читаемость CLI: разбить большие main.py/config.py на отдельные модули",
|
||||
"changes": {
|
||||
"summary": "infrastructure/cli/main.py (330 LOC) разбит на 9 файлов в commands/: init, forecast, scenario, whatif, compare, import_xlsx, export_xlsx, analyze, info. config.py (428 LOC) перенесён в commands/config_cmd.py как Typer sub-typer. main.py → app.py (entry point, регистрирует все команды). Создан paths.py (константы MODEL_PATH, DATA_DIR) и services.py (composition root: load_model, save_model, build_services, resolve_currency, convert_value, fmt_amount). pyproject.toml: cf = infrastructure.cli.app:app. test_cli.py обновлён.",
|
||||
"commits": ["<see git log>"],
|
||||
"files_changed": [
|
||||
"infrastructure/cli/app.py (new entry point)",
|
||||
"infrastructure/cli/commands/{init,forecast,scenario,whatif,compare,import_xlsx,export_xlsx,analyze,info,config_cmd}.py",
|
||||
"infrastructure/cli/paths.py, services.py",
|
||||
"infrastructure/cli/main.py, config.py (removed)",
|
||||
"pyproject.toml (cf entry point)",
|
||||
"tests/test_cli.py"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "67/67",
|
||||
"all_commands_work": ["init", "forecast", "scenario", "whatif", "compare", "import-xlsx", "export-xlsx", "analyze", "info", "config rate-list"],
|
||||
"file_size_under_100_loc_per_command": true
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"Каждая Typer-команда в отдельном файле cli/commands/*.py",
|
||||
"config_cmd.py в commands/, остаётся sub-typer",
|
||||
"paths.py — только пути",
|
||||
"services.py — composition root + helpers",
|
||||
"Размер команд < 100 LOC (config_cmd.py — ~300, т.к. содержит 15 sub-команд)",
|
||||
"Поведение идентично",
|
||||
"pytest 67/67"
|
||||
]
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"request_id": "req-T7",
|
||||
"task_id": "T7",
|
||||
"title": "Final validation + README update",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Финальная проверка всех 6 задач рефактора + обновление документации",
|
||||
"changes": {
|
||||
"summary": "Все 67 тестов проходят. CLI проверен вручную: cf init, forecast, scenario (baseline/optimistic/pessimistic), whatif, compare, info, analyze, config (account-add, transaction-add, asset-add, rate-list). Excel round-trip (export → init → import) сохраняет все данные. README.md полностью обновлён под новую архитектуру: domain/application/infrastructure, pydantic, Decimal, Repository pattern, DI, schema versioning. Все 6 задач рефактора (T1-T6) выполнены и подтверждены.",
|
||||
"commits": ["3ef1061"],
|
||||
"files_changed": [
|
||||
"README.md (полная перезапись: новая архитектура, команды, зависимости)"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "67/67",
|
||||
"cf_init_works": true,
|
||||
"cf_forecast_works": true,
|
||||
"cf_scenario_baseline_works": true,
|
||||
"cf_compare_works": true,
|
||||
"cf_info_works": true,
|
||||
"cf_export_import_xlsx_roundtrip": "сохраняет 1 счёт, 1 транзакцию, 1 актив",
|
||||
"cf_config_subcommands_works": true,
|
||||
"all_5_refactor_directions_complete": ["A1+A10: слои+version", "A2+A3: pydantic", "A4: Decimal", "A7+A8+A9: DI+Repository", "A5: CLI decompose"]
|
||||
},
|
||||
"fulfills_ac": [
|
||||
"pytest 67/67 pass",
|
||||
"cf init/forecast/scenario/compare работают",
|
||||
"cf import-xlsx → cf export-xlsx round-trip работает",
|
||||
"README.md отражает новую структуру"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "T1",
|
||||
"title": "Реструктуризация в domain/application/infrastructure + version=1",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T1",
|
||||
"commit": "feb77ef",
|
||||
"summary": "Перестроена пакетная структура: cashflow_model/ → domain/, engine/ → application/, cli/, sync/, ai/ → infrastructure/. Добавлено version: 1 в FinancialModel.to_dict() с миграционным хуком _from_v0/_from_v1. Обновлён pyproject.toml. 63/63 тестов проходят.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "T2",
|
||||
"title": "Pydantic v2 — миграция моделей",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T2",
|
||||
"commit": "c765f36",
|
||||
"summary": "Все 7 моделей domain/ переведены с @dataclass на pydantic.BaseModel. Удалены ручные to_dict()/from_dict(). Добавлены field_validators (balance >= 0, amount != 0, frequency whitelist, и т.п.). UUID в JSON автоматически сериализуется как str. excel_sync.py и тесты обновлены. 63/63 тестов проходят.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "T3",
|
||||
"title": "Decimal для денег",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T3",
|
||||
"commit": "363d440",
|
||||
"summary": "Все денежные поля (Account.balance, Asset.value, Transaction.amount, ExchangeRate.rate, и т.д.) переведены с float на Decimal. CurrencyConverter использует Decimal арифметику с ROUND_HALF_UP. ForecastService и ScenarioService переписаны. assistant.py получил _DecimalEncoder для json.dumps. 63/63 тестов проходят.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"id": "T4",
|
||||
"title": "Repository pattern — ModelRepository",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T4",
|
||||
"summary": "Создан application/repositories/ с ModelRepository Protocol. Реализации: JsonFileRepository (.json с version) и ExcelRepository (бывший ExcelSync, переименован). FinancialModel.save/load удалены. infrastructure/sync/ удалён. CLI использует JsonFileRepository + ExcelRepository. 68/68 тестов проходят (+5 новых для репозиториев).",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "T5",
|
||||
"title": "Dependency Injection в сервисах",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T5",
|
||||
"commit": "541a768",
|
||||
"summary": "AssistantService теперь принимает ForecastService через __init__ (раньше создавал new ForecastService() внутри analyze/advice). В infrastructure/cli/main.py добавлен _build_services() — composition root, собирающий граф: CurrencyConverter, ForecastService, ScenarioService, AssistantService. 67/67 тестов проходят.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"id": "T6",
|
||||
"title": "Декомпозиция CLI",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T6",
|
||||
"summary": "main.py (330 LOC) → 9 файлов в commands/ + main.py → app.py. config.py (428 LOC) → commands/config_cmd.py как Typer sub-typer. Создан paths.py (константы) и services.py (composition root + helpers). pyproject.toml: cf = infrastructure.cli.app:app. 67/67 тестов проходят. CLI поведение идентично.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "T7",
|
||||
"title": "Финальная валидация",
|
||||
"status": "archived",
|
||||
"origin": "user:direct",
|
||||
"request": "req-T7",
|
||||
"commit": "3ef1061",
|
||||
"summary": "67/67 тестов проходят. CLI проверен: init, forecast, scenario, whatif, compare, info, analyze, config sub-typer. Excel round-trip (export → init → import) сохраняет данные. README.md полностью обновлён под новую архитектуру. Все 5 направлений рефактора (A1+A10, A2+A3, A4, A5, A7+A8+A9) реализованы.",
|
||||
"archived_at": "2026-10-08T17:05:00Z"
|
||||
}
|
||||
+24
-17
@@ -1,27 +1,34 @@
|
||||
{
|
||||
"metaagent_version": "3.0.0",
|
||||
"session_id": "metaagent-005",
|
||||
"target_repo": "/home/oqyude/External/Git/nifodea",
|
||||
"goal": "Обсуждение архитектуры и серьёзный refactor",
|
||||
"metaagent_version": "1.0.0",
|
||||
"session_id": "metaagent-002",
|
||||
"target_repo": "S:\\Git\\nifodea",
|
||||
"goal": "Обновление metaagent-артефактов до v1.0.0, валидация существующего кода и окружения",
|
||||
"project_type": "existing",
|
||||
"config": {
|
||||
"depth": 4,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
},
|
||||
"phases": {
|
||||
"init": "completed",
|
||||
"analyse": "completed",
|
||||
"roadmap": "completed",
|
||||
"analysis": "completed",
|
||||
"design": "skipped",
|
||||
"red_team": "skipped",
|
||||
"decomposition": "completed",
|
||||
"execution": "completed",
|
||||
"metastate": "completed",
|
||||
"environment": "completed",
|
||||
"handoff": "completed"
|
||||
},
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "Реструктуризация в domain/application/infrastructure + version=1", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T2", "title": "Pydantic v2 — миграция моделей", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T3", "title": "Decimal для денег", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T4", "title": "Repository pattern — ModelRepository", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T5", "title": "Dependency Injection в сервисах", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T6", "title": "Декомпозиция CLI", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T7", "title": "Финальная валидация", "status": "archived", "origin": "user:direct" }
|
||||
{ "id": "T1", "title": "Инициализация проекта и зависимостей", "status": "completed", "depends_on": [], "acceptance_criteria": ["pyproject.toml создан", "Все __init__.py созданы", "ruff проходит", "pytest запускается"] },
|
||||
{ "id": "T2", "title": "Модель данных (dataclass + JSON)", "status": "completed", "depends_on": ["T1"], "acceptance_criteria": ["Все сущности dataclass", "FinancialModel save/load JSON"] },
|
||||
{ "id": "T3", "title": "Forecast Engine", "status": "completed", "depends_on": ["T2"], "acceptance_criteria": ["forecast_cashflow работает", "recurring проецируются", "активы/обязательства учтены"] },
|
||||
{ "id": "T4", "title": "Scenario Analysis", "status": "completed", "depends_on": ["T3"], "acceptance_criteria": ["3 сценария", "what-if модификация", "сравнение сценариев"] },
|
||||
{ "id": "T5", "title": "Excel Sync", "status": "completed", "depends_on": ["T2"], "acceptance_criteria": ["импорт из Excel", "экспорт в Excel", "ошибки невалидного формата"] },
|
||||
{ "id": "T6", "title": "CLI (Typer)", "status": "completed", "depends_on": ["T2","T3","T4","T5","T7"], "acceptance_criteria": ["init/forecast/analyze/import/export/scenario/whatif/compare команды"] },
|
||||
{ "id": "T7", "title": "AI Assistant", "status": "completed", "depends_on": ["T3"], "acceptance_criteria": ["промпты с моделью и прогнозом", "заглушка ответа"] },
|
||||
{ "id": "T8", "title": "Тесты", "status": "completed", "depends_on": ["T2","T3","T4","T5","T6","T7"], "acceptance_criteria": ["pytest проходит", "покрытие всех модулей"] }
|
||||
],
|
||||
"last_updated": "2026-10-08T17:10:00Z"
|
||||
"last_updated": "2026-07-12T20:15:00Z"
|
||||
}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
# Analysis Report
|
||||
|
||||
**Session ID:** `metaagent-005`
|
||||
**Target repo:** `/home/oqyude/External/Git/nifodea`
|
||||
**Date:** 2026-10-08
|
||||
**Project type:** `existing`
|
||||
**MetaAgent version:** 3.0.0
|
||||
|
||||
---
|
||||
|
||||
## 1. Общая информация
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Название | CashFlow Forecast |
|
||||
| Назначение | Личная финансовая модель с прогнозом денежных потоков, сценарным анализом, what-if и AI-ассистентом |
|
||||
| Лицензия | не выбрана (есть файл `LICENSE` с шаблоном, требует ревизии) |
|
||||
| CI/CD | отсутствует (нет `.github/`, `.gitlab-ci.yml`, `Makefile`) |
|
||||
| Точка входа | `cli/main.py` → команда `cf` (через `pyproject.toml [project.scripts]`) |
|
||||
| Система сборки | `pyproject.toml` (setuptools, build-backend=setuptools.build_meta) |
|
||||
| Версия | 0.1.0 |
|
||||
|
||||
## 2. Стек технологий
|
||||
|
||||
| Компонент | Значение |
|
||||
|---|---|
|
||||
| Язык | Python >= 3.11 (тестировалось на 3.14) |
|
||||
| CLI-фреймворк | Typer >= 0.9 (через `typer` entry-point) |
|
||||
| Файлы данных | JSON (через `pathlib` + `json`) |
|
||||
| Excel I/O | openpyxl >= 3.1 |
|
||||
| Терминал-вывод | rich >= 13.0 |
|
||||
| Тесты | pytest 9.x |
|
||||
| Линтер | ruff 0.16.x (line-length 120, rules E/F/I/N/W) |
|
||||
| Пакетный менеджер | pip (через `.venv`) |
|
||||
| UUID-генерация | uuid4 (для ID моделей) |
|
||||
| Dataclass-сериализация | ручные `to_dict` / `from_dict` |
|
||||
|
||||
## 3. Архитектура
|
||||
|
||||
**Паттерн:** модульный монолит (5 пакетов, чёткие границы ответственности).
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ cli/ — Typer CLI (cf init/forecast/...) │
|
||||
└──────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌───────────┼───────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────┐ ┌─────────┐ ┌──────┐
|
||||
│ ai/ │ │ engine/ │ │sync/ │
|
||||
│prompts│ │forecast │ │excel │
|
||||
│asst │ │scenario │ │ │
|
||||
└───┬───┘ └────┬────┘ └──┬───┘
|
||||
│ │ │
|
||||
└─────────┬─┴──────────┘
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ cashflow_model │ ← Account, Transaction, Recurring,
|
||||
│ (dataclasses) │ Asset, Liability, Scenario, Currency
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
**Принцип** (из `README.arch.md`):
|
||||
- Spreadsheet — UI (через `sync/excel_sync.py`)
|
||||
- Python — вычислительное ядро (`engine/`)
|
||||
- JSON — внутреннее представление (`cashflow_model/`)
|
||||
- AI — инструмент анализа (`ai/`, пока stub)
|
||||
|
||||
## 4. Структура (depth=2)
|
||||
|
||||
```
|
||||
nifodea/
|
||||
├── AGENTS.md # MetaAgent context для агента
|
||||
├── LICENSE # шаблон, не выбрана
|
||||
├── README.md # инструкции пользователя
|
||||
├── README.arch.md # архитектурная концепция
|
||||
├── pyproject.toml # setuptools + deps + entry-point cf
|
||||
├── .gitignore # python + .temp/ (MetaAgent)
|
||||
│
|
||||
├── cashflow_model/ # 7 dataclass-моделей + Currency
|
||||
│ ├── account.py, transaction.py, recurring.py, asset.py, liability.py
|
||||
│ ├── scenario.py, currency.py, model.py (root), __init__.py
|
||||
│
|
||||
├── engine/ # вычислительное ядро
|
||||
│ ├── forecast.py (ForecastService)
|
||||
│ ├── scenarios.py (ScenarioService + what-if)
|
||||
│
|
||||
├── sync/ # Excel-импорт/экспорт
|
||||
│ └── excel_sync.py
|
||||
│
|
||||
├── ai/ # AI-ассистент (stub)
|
||||
│ ├── prompts.py
|
||||
│ └── assistant.py
|
||||
│
|
||||
├── cli/ # Typer CLI
|
||||
│ ├── main.py (~330 LOC, 8 команд)
|
||||
│ ├── i18n.py (~350 LOC, ru/en)
|
||||
│ └── config.py (~428 LOC)
|
||||
│
|
||||
├── tests/ # pytest, 9 файлов
|
||||
│ ├── conftest.py (фикстуры: sample_model, empty_model, sample_converter)
|
||||
│ └── test_*.py (9 файлов)
|
||||
│
|
||||
├── data/ # JSON-модели (runtime)
|
||||
└── exports/ # экспортированные .xlsx
|
||||
```
|
||||
|
||||
## 5. Ключевые модули и их ответственность
|
||||
|
||||
| Модуль | Ответственность | LOC |
|
||||
|---|---|---|
|
||||
| `cashflow_model/model.py` | Корневая модель `FinancialModel` (агрегатор + JSON save/load) | 61 |
|
||||
| `cashflow_model/currency.py` | `CurrencyConverter`, `ExchangeRate`, символы валют | 79 |
|
||||
| `cashflow_model/*.py` | Датаклассы: Account, Transaction, Recurring, Asset, Liability, Scenario | ~150 |
|
||||
| `engine/forecast.py` | `ForecastService.forecast_cashflow()` — посуточный/помесячный прогноз | 103 |
|
||||
| `engine/scenarios.py` | `ScenarioService` (baseline/optimistic/pessimistic) + what-if | 87 |
|
||||
| `sync/excel_sync.py` | `ExcelSync` — импорт/экспорт `.xlsx` ↔ `FinancialModel` | 135 |
|
||||
| `ai/prompts.py` | Шаблоны промптов для AI (analyze, advice, scenario_comparison) | 21 |
|
||||
| `ai/assistant.py` | `AssistantService` — генерирует промпт, но НЕ вызывает API (stub) | 69 |
|
||||
| `cli/main.py` | Typer-приложение: `cf init/forecast/scenario/whatif/compare/import/export/analyze` | 330 |
|
||||
| `cli/config.py` | Загрузка/сохранение `FinancialModel` в `data/`, пути по умолчанию | 428 |
|
||||
| `cli/i18n.py` | `t()`-обёртка, словари `_r()`/`_e()`, ru (default) / en (fallback) | 350 |
|
||||
|
||||
**Всего:** ~2479 строк кода + 9 тестовых файлов.
|
||||
|
||||
## 6. Конвенции
|
||||
|
||||
| Аспект | Соглашение |
|
||||
|---|---|
|
||||
| Стиль кода | snake_case (функции/переменные), PascalCase (классы), UPPER_SNAKE (константы) |
|
||||
| Датаклассы | `@dataclass` + ручные `to_dict` / `from_dict` (без `pydantic`/`attrs`) |
|
||||
| ID | `uuid.UUID` через `field(default_factory=uuid4)` |
|
||||
| Суммы | `float` (без `Decimal`, есть риск округления) |
|
||||
| Даты | ISO-строки `"YYYY-MM-DD"` (без `datetime`) |
|
||||
| Исключения | Доменные классы: `CurrencyError`, `AssistantError` (наследуют `Exception`) |
|
||||
| Логирование | `rich.print` для UI; явное логирование не используется |
|
||||
| Валюты | По умолчанию RUB; поддержка USD, EUR, GBP, CNY, JPY, KZT, UAH |
|
||||
| CLI-фреймворк | Typer (декораторы `@app.command()`) |
|
||||
| i18n | Кастомный `t(key, **kwargs)` с fallback на русский |
|
||||
|
||||
## 7. Тесты
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Раннер | pytest 9.1 |
|
||||
| Расположение | `tests/test_*.py` |
|
||||
| Фикстуры | `sample_model`, `empty_model`, `sample_converter` (в `conftest.py`) |
|
||||
| Покрытие | 9 тестовых модулей: model, currency, forecast, scenarios, excel_sync, ai, cli, i18n |
|
||||
| Baseline | **63/63 PASSED** (4.64s) |
|
||||
| Отчёт | `.agent/context/baseline-test-report.log` |
|
||||
|
||||
## 8. Сборка / запуск
|
||||
|
||||
```bash
|
||||
# Установка (editable)
|
||||
.venv/bin/pip install -e .
|
||||
|
||||
# С дев-зависимостями (если добавить)
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
|
||||
# Тесты
|
||||
.venv/bin/pytest
|
||||
|
||||
# Линтер
|
||||
.venv/bin/python -m ruff check .
|
||||
|
||||
# CLI
|
||||
cf init
|
||||
cf forecast --months 12
|
||||
cf scenario baseline
|
||||
cf compare --months 12
|
||||
```
|
||||
|
||||
## 9. Известные ограничения (MVP)
|
||||
|
||||
Из `README.md` и `README.arch.md`:
|
||||
|
||||
- **AI-ассистент — заглушка.** `AssistantService.analyze()` возвращает dict с `"ai_response": None`. API не подключён. *Примечание 2026-10-08: пользователь решил, что AI-интеграция не в скоупе — модуль `ai/` остаётся как есть.*
|
||||
- **Хранилище — JSON-файлы.** Не подходит для многопользовательской работы.
|
||||
- **Excel — только `.xlsx`** через openpyxl.
|
||||
- **Лицензия не выбрана.**
|
||||
- **CI/CD отсутствует.**
|
||||
- **Нет `FUTURE/`** для долгосрочных планов.
|
||||
- **Тесты не интеграционные** с реальным Excel-файлом (только in-memory).
|
||||
|
||||
## 10. Будущие возможности (из README.arch.md)
|
||||
|
||||
- Monte-Carlo Simulation
|
||||
- FIRE Planning
|
||||
- Инвестиционный прогноз
|
||||
- Импорт банковских выписок / брокерских отчётов
|
||||
- REST API
|
||||
- Web UI
|
||||
- Mobile App
|
||||
- AI Financial Assistant (полная реализация)
|
||||
|
||||
## 11. Git-состояние
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| HEAD | `12611ed metaagent update` |
|
||||
| Всего коммитов | 8 |
|
||||
| Незакоммиченные изменения | есть (миграция `.agent/` с v1.1 → v3.0) — задокументировано в `.agent/migration-report.log` |
|
||||
| Ветка | (не проверено) |
|
||||
|
||||
## 12. Что НЕ делает MetaAgent в этом проекте
|
||||
|
||||
- Не пишет production-код (по `project-rules.md`).
|
||||
- Не удаляет файлы.
|
||||
- Не коммитит в main/master.
|
||||
@@ -1,127 +0,0 @@
|
||||
# Project State
|
||||
|
||||
**Снимок на момент:** 2026-10-08T17:05 (после METASTATE)
|
||||
**Project type:** `existing`
|
||||
**MetaAgent version:** 3.0.0
|
||||
|
||||
---
|
||||
|
||||
## Что произошло в сессии 2026-10-08
|
||||
|
||||
**Goal:** «Обсуждение архитектуры и серьёзный refactor»
|
||||
|
||||
Выполнен полный архитектурный рефактор по 5 направлениям:
|
||||
|
||||
1. **A1+A10: Слои + version** — `domain/`, `application/`, `infrastructure/`; `FinancialModel.SCHEMA_VERSION=1` с миграционным хуком.
|
||||
2. **A2+A3: Pydantic v2** — все модели на `BaseModel`, валидаторы, `model_dump`/`model_validate`.
|
||||
3. **A4: Decimal для денег** — все monetary поля, `CurrencyConverter`, `ForecastService`, `ScenarioService` работают с `Decimal`.
|
||||
4. **A7+A8+A9: DI + Repository** — `ModelRepository` Protocol, `JsonFileRepository`, `ExcelRepository`; `AssistantService` получает `ForecastService` через DI; `build_services()` — composition root в CLI.
|
||||
5. **A5: Декомпозиция CLI** — `main.py` (330 LOC) → 9 файлов в `commands/`, `config.py` (428 LOC) → `config_cmd.py` (15 sub-команд).
|
||||
|
||||
**Результат:** 67/67 тестов проходят, CLI работает, Excel round-trip сохраняет данные.
|
||||
|
||||
## Архитектура (после рефактора)
|
||||
|
||||
**Модульный монолит на Python 3.11+** для личного финансового планирования. Три слоя:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ domain/ — бизнес-модели │
|
||||
│ Account, Transaction, Asset, Liability, │
|
||||
│ Recurring, Scenario, FinancialModel, │
|
||||
│ ExchangeRate, CurrencyConverter │
|
||||
│ (pydantic.BaseModel, Decimal) │
|
||||
└──────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────┐
|
||||
│ application/ — прикладные сервисы │
|
||||
│ ForecastService, ScenarioService, │
|
||||
│ ModelRepository (Protocol) │
|
||||
└──────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────┐
|
||||
│ infrastructure/ — внешний мир │
|
||||
│ cli/ (Typer), ai/ (Assistant), │
|
||||
│ repositories/ (JsonFile, Excel) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Tech stack
|
||||
|
||||
| Слой | Технология | Версия |
|
||||
|---|---|---|
|
||||
| Язык | Python | 3.11+ (тест на 3.14) |
|
||||
| CLI | Typer | 0.27 |
|
||||
| Excel | openpyxl | 3.1 |
|
||||
| Терминал | rich | 15.0 |
|
||||
| Валидация | pydantic | 2.13 |
|
||||
| Деньги | Decimal | stdlib |
|
||||
| Тесты | pytest | 9.1 |
|
||||
| Линтер | ruff | 0.16 |
|
||||
|
||||
## Ключевые модули
|
||||
|
||||
| Слой | Модуль | Ответственность |
|
||||
|---|---|---|
|
||||
| domain | `account.py` (18 LOC), `transaction.py` (20), `asset.py` (11), `liability.py` (19), `recurring.py` (27), `scenario.py` (20) | pydantic.BaseModel + Decimal + валидаторы |
|
||||
| domain | `currency.py` (83) | ExchangeRate + CurrencyConverter (Decimal, ROUND_HALF_UP) |
|
||||
| domain | `model.py` (71) | FinancialModel — корневой агрегатор с SCHEMA_VERSION=1 |
|
||||
| application | `forecast.py` (115) | ForecastService — Decimal-арифметика, помесячный прогноз |
|
||||
| application | `scenarios.py` (91) | ScenarioService — baseline/optimistic/pessimistic + what-if |
|
||||
| application | `repositories/model_repository.py` (20) | Protocol с load()/save() |
|
||||
| infrastructure | `cli/app.py` (45) | Entry point, регистрирует все команды |
|
||||
| infrastructure | `cli/commands/*.py` | 9 файлов (init/forecast/scenario/whatif/compare/import_xlsx/export_xlsx/analyze/info) + config_cmd.py |
|
||||
| infrastructure | `cli/paths.py` (5) | MODEL_PATH, DATA_DIR |
|
||||
| infrastructure | `cli/services.py` (60) | build_services() — composition root + helpers |
|
||||
| infrastructure | `cli/i18n.py` (350) | ru/en словари |
|
||||
| infrastructure | `ai/assistant.py` (79) | AssistantService (заглушка, DI ForecastService) |
|
||||
| infrastructure | `repositories/json_file_repository.py` (20) | .json storage |
|
||||
| infrastructure | `repositories/excel_repository.py` (138) | .xlsx storage |
|
||||
|
||||
## Статус тестов
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Всего тестов | 67 |
|
||||
| Пройдено | 67 ✅ |
|
||||
| Упало | 0 |
|
||||
| Время | 2.4s |
|
||||
| Тестовых модулей | 10 |
|
||||
|
||||
## Что было сделано в сессии
|
||||
|
||||
- ✅ Pydantic v2 во всех моделях
|
||||
- ✅ Decimal для всех денежных полей
|
||||
- ✅ Слои domain/application/infrastructure
|
||||
- ✅ Schema versioning (version=1 + legacy v0 support)
|
||||
- ✅ ModelRepository Protocol + JsonFile + Excel
|
||||
- ✅ DI через composition root
|
||||
- ✅ CLI decomposition (main.py 330 LOC → 9 файлов, config.py 428 LOC → config_cmd.py)
|
||||
- ✅ 67/67 тестов проходят
|
||||
- ✅ CLI команды работают, Excel round-trip OK
|
||||
- ✅ README обновлён
|
||||
|
||||
## Что отсутствует / TODO
|
||||
|
||||
- ❌ **AI-интеграция** — `AssistantService` не вызывает LLM API (отклонено пользователем)
|
||||
- ❌ **Лицензия** — файл есть, но содержимое — шаблон
|
||||
- ❌ **CI/CD** — нет `.github/`, нет pre-commit hooks
|
||||
- ❌ **FUTURE/** — нет директории с долгосрочными планами
|
||||
- ❌ **mypy** — не настроен
|
||||
- ❌ **Логирование** — только `rich.print`
|
||||
|
||||
## Известные ADR-кандидаты (для следующей сессии)
|
||||
|
||||
| ID | Тема |
|
||||
|---|---|
|
||||
| ADR-001 | Repository pattern (T4) — формализовать контракт |
|
||||
| ADR-002 | Слоистая архитектура (T1) — границы domain/application/infrastructure |
|
||||
| ADR-003 | Schema versioning — политика миграций модели |
|
||||
|
||||
## Следующая сессия — что делать
|
||||
|
||||
1. **Зафиксировать ADR-001, ADR-002, ADR-003** через `/adr` — закрепить архитектурные решения.
|
||||
2. **CI/CD** (P1) — добавить `.github/workflows/ci.yml` (pytest + ruff).
|
||||
3. **Лицензия** (P2) — выбрать MIT/Apache-2.0/BSD-3, обновить `LICENSE`.
|
||||
4. **mypy** (P1) — добавить `[tool.mypy]` в `pyproject.toml` для strict-проверки.
|
||||
5. **Новые фичи** (P3) — Monte-Carlo, FIRE, REST API, Web UI, импорт банковских выписок (из `README.arch.md`).
|
||||
@@ -0,0 +1,151 @@
|
||||
# Design Report
|
||||
|
||||
## Session
|
||||
|
||||
- **Session ID:** `metaagent-001`
|
||||
- **Target repo:** `S:\Git\nifodea`
|
||||
- **Date:** 2026-07-12
|
||||
|
||||
## 1. Технологический стек
|
||||
|
||||
| Компонент | Выбор | Обоснование |
|
||||
|---|---|---|
|
||||
| Язык | Python 3.11+ | Указан в README как вычислительное ядро; широкая экосистема для работы с данными |
|
||||
| Фреймворк | Typer (CLI), openpyxl (Excel) | Typer — современный CLI-фреймворк; openpyxl — стандарт для .xlsx |
|
||||
| База данных | JSON-файлы | README требует JSON как внутреннее представление; для MVP БД не нужна |
|
||||
| Инфраструктура | pip + venv | Минимальная зависимость; .gitignore уже настроен под Python |
|
||||
| Линтер | ruff | Стандарт для Python 2024+; быстрый, уже в .gitignore |
|
||||
| Тесты | pytest | Стандартный тестовый раннер для Python |
|
||||
| AI | Интерфейс через промпты | Для MVP — только промпты и абстракция, без подключения к API |
|
||||
|
||||
## 2. High-Level архитектура
|
||||
|
||||
**Паттерн:** Модульный монолит (Layered)
|
||||
|
||||
```
|
||||
[CLI / Excel File]
|
||||
|
|
||||
▼
|
||||
sync/ ──► cashflow_model/ ──► engine/ ──► ai/
|
||||
(Excel R/W) (Entity Model) (Forecast) (Prompts)
|
||||
| | |
|
||||
▼ ▼ ▼
|
||||
data/model.json data/model.json data/model.json
|
||||
```
|
||||
|
||||
**Поток данных:**
|
||||
1. Пользователь редактирует Excel → sync читает и преобразует в JSON
|
||||
2. JSON-модель загружается в Python-объекты (dataclass)
|
||||
3. Forecast Engine вычисляет прогноз на основе модели
|
||||
4. AI Assistant анализирует результаты через промпты
|
||||
5. Результаты экспортируются обратно в Excel
|
||||
|
||||
## 3. Модули
|
||||
|
||||
| Модуль | Ответственность | Ключевые компоненты | Зависит от |
|
||||
|---|---|---|---|
|
||||
| `cashflow_model/` | Определение сущностей (dataclass), сериализация/десериализация JSON | `Account`, `Transaction`, `RecurringCashflow`, `Asset`, `Liability`, `ForecastScenario`, `FinancialModel` | — |
|
||||
| `sync/` | Чтение и запись Excel (.xlsx), конвертация между Excel и JSON | `excel_sync.py` — импорт/экспорт | `cashflow_model` |
|
||||
| `engine/` | Расчёт прогноза, сценарный анализ, what-if | `forecast.py` (прогноз), `scenarios.py` (сценарии) | `cashflow_model` |
|
||||
| `ai/` | Промпты для AI-ассистента, форматирование контекста | `prompts.py` (шаблоны), `assistant.py` (интерфейс) | `cashflow_model`, `engine` |
|
||||
| `cli/` | CLI-интерфейс (Typer) | `main.py` — точки входа | Все модули |
|
||||
|
||||
## 4. Модели данных
|
||||
|
||||
### Account
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
| id | UUID | pk | Уникальный идентификатор |
|
||||
| name | str | required | Название счёта |
|
||||
| currency | str | default="USD" | Валюта |
|
||||
| balance | float | required | Текущий баланс |
|
||||
|
||||
### Transaction
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
| id | UUID | pk | Уникальный идентификатор |
|
||||
| date | str (ISO date) | required | Дата операции |
|
||||
| account | UUID | fk → Account | Счёт |
|
||||
| category | str | required | Категория |
|
||||
| amount | float | required | Сумма |
|
||||
| description | str | optional | Описание |
|
||||
|
||||
### RecurringCashflow
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
| id | UUID | pk | Уникальный идентификатор |
|
||||
| start_date | str (ISO date) | required | Дата начала |
|
||||
| end_date | str (ISO date) | optional | Дата окончания |
|
||||
| frequency | str | enum: monthly/weekly/yearly | Периодичность |
|
||||
| amount | float | required | Сумма |
|
||||
| category | str | required | Категория |
|
||||
|
||||
### Asset
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
| id | UUID | pk | Уникальный идентификатор |
|
||||
| name | str | required | Название |
|
||||
| value | float | required | Текущая стоимость |
|
||||
| growth_rate | float | default=0.0 | Годовой темп роста (%) |
|
||||
|
||||
### Liability
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
| id | UUID | pk | Уникальный идентификатор |
|
||||
| name | str | required | Название |
|
||||
| balance | float | required | Текущий остаток |
|
||||
| interest | float | required | Годовая ставка (%) |
|
||||
| payment | float | required | Ежемесячный платёж |
|
||||
|
||||
**Связи:**
|
||||
- Transaction → Account (многие к одному)
|
||||
- RecurringCashflow → Account (многие к одному, опционально)
|
||||
- FinancialModel включает все сущности + параметры
|
||||
|
||||
## 5. API / Интерфейсы
|
||||
|
||||
### CLI (Typer)
|
||||
|
||||
| Команда | Описание | Пример |
|
||||
|---|---|---|
|
||||
| `import <file.xlsx>` | Импорт данных из Excel в JSON | `cf import data.xlsx` |
|
||||
| `export <file.xlsx>` | Экспорт из JSON в Excel | `cf export report.xlsx` |
|
||||
| `forecast [--months 12]` | Запуск прогноза | `cf forecast --months 12` |
|
||||
| `scenario <name>` | Применить сценарий | `cf scenario optimistic` |
|
||||
| `analyze` | AI-анализ модели | `cf analyze` |
|
||||
| `init` | Инициализация пустой модели | `cf init` |
|
||||
|
||||
## 6. Обработка ошибок
|
||||
|
||||
- **Стратегия:** Исключения Python с кастомными типами (`ModelError`, `SyncError`, `ForecastError`)
|
||||
- **Формат ошибок:** `{ "error": "<message>", "code": "<CODE>", "details": {} }`
|
||||
- **Логирование:** logging с уровнями INFO/ERROR; CLI-вывод через Typer + rich
|
||||
|
||||
## 7. Тестирование
|
||||
|
||||
- **Unit-тесты:** pytest для каждого модуля (cashflow_model, engine, sync)
|
||||
- **Integration-тесты:** чтение/запись Excel, полный цикл import → forecast → export
|
||||
- **Mock-стратегия:** временные файлы для Excel/JSON тестов
|
||||
- **Команда запуска:** `pytest`
|
||||
|
||||
## 8. Предварительная группировка задач
|
||||
|
||||
| Задача | Описание | Тип |
|
||||
|---|---|---|
|
||||
| T1 | Инициализация проекта + scaffold | config |
|
||||
| T2 | Модель данных (dataclass + JSON serialization) | feature |
|
||||
| T3 | Forecast Engine (базовый прогноз) | feature |
|
||||
| T4 | Excel Sync (import/export) | feature |
|
||||
| T5 | CLI (Typer) — все команды | feature |
|
||||
| T6 | AI Assistant (промпты + интерфейс) | feature |
|
||||
| T7 | Тесты на все модули | test |
|
||||
| T8 | Финальная проверка и документация | docs |
|
||||
|
||||
## 9. Примечания
|
||||
|
||||
Для MVP берётся минимальный функционал: модель + forecast + excel sync + cli. AI — только интерфейс (заглушка с промптами). Сценарии — базовая реализация.
|
||||
+55
-95
@@ -1,109 +1,69 @@
|
||||
# Handoff Summary
|
||||
|
||||
**Session:** `metaagent-005`
|
||||
**Goal:** Обсуждение архитектуры и серьёзный refactor
|
||||
**Date:** 2026-10-08
|
||||
**MetaAgent version:** 3.0.0
|
||||
## Session Info
|
||||
|
||||
---
|
||||
- **Session ID:** `metaagent-002`
|
||||
- **Target Repo:** `S:\Git\nifodea`
|
||||
- **Goal:** Обновление metaagent-артефактов до v1.0.0, валидация существующего кода и окружения
|
||||
- **Date:** 2026-07-12
|
||||
- **Duration:** ~1 session
|
||||
|
||||
## Session Summary
|
||||
## Configuration
|
||||
|
||||
| Метрика | Значение |
|
||||
- **Depth:** 4 (Light)
|
||||
- **Design:** adr=no, alternative_arch=no
|
||||
- **Red Team:** no
|
||||
- **Risk Register:** no
|
||||
- **Invariant Tests:** no
|
||||
- **Layer Structure:** no
|
||||
|
||||
## Repo Summary
|
||||
|
||||
CashFlow Forecast — личная финансовая модель с прогнозом денежных потоков. Python 3.11+, JSON, Excel (openpyxl), CLI (Typer), AI-интерфейс (заглушка). MVP полностью реализован.
|
||||
|
||||
## Environment Status
|
||||
|
||||
- **Build:** OK (pip install -e . — success)
|
||||
- **Lint:** ruff — All checks passed
|
||||
- **Tests:** 26/26 passed (0.63s)
|
||||
- **Git status:** clean
|
||||
|
||||
## Design Summary
|
||||
|
||||
- **Pattern:** Модульный монолит (Layered)
|
||||
- **Modules:** cashflow_model, engine, sync, ai, cli
|
||||
- **Entry point:** `cf` (cli.main:app)
|
||||
|
||||
## Task Overview
|
||||
|
||||
| Status | Count |
|
||||
|---|---|
|
||||
| Выполнено задач | 7/7 ✅ |
|
||||
| Total | 8 |
|
||||
| Completed | 8 |
|
||||
| Pending | 0 |
|
||||
| Approved requests | req-T1 … req-T7 (все в `.agent/archive/requests/`) |
|
||||
| Коммитов | 6 (feb77ef, c765f36, 363d440, 541a768, 3ef1061, плюс 1 для T4/T6 — см. `git log`) |
|
||||
| Тестов до | 63 |
|
||||
| Тестов после | 67 (+5 для репозиториев) |
|
||||
|
||||
## Что сделано
|
||||
**Tasks by type:**
|
||||
- config: 1 (completed)
|
||||
- feature: 6 (completed)
|
||||
- test: 1 (completed)
|
||||
|
||||
Полный архитектурный рефактор проекта `cashflow-forecast` (Python 3.11+, Typer CLI):
|
||||
## Next Steps
|
||||
|
||||
| # | Задача | Что |
|
||||
|---|---|---|
|
||||
| T1 | Слои + version | `domain/`, `application/`, `infrastructure/`; `FinancialModel.SCHEMA_VERSION=1` |
|
||||
| T2 | Pydantic v2 | Все модели — `pydantic.BaseModel`, валидаторы |
|
||||
| T3 | Decimal | Все monetary поля, `CurrencyConverter`, `ForecastService`, `ScenarioService` |
|
||||
| T4 | Repository | `ModelRepository` Protocol, `JsonFileRepository`, `ExcelRepository` |
|
||||
| T5 | DI | `build_services()` — composition root, `AssistantService` принимает `ForecastService` |
|
||||
| T6 | CLI decompose | `main.py` 330 LOC → 9 файлов, `config.py` 428 LOC → `config_cmd.py` |
|
||||
| T7 | Final | 67/67 тестов, README обновлён, Excel round-trip OK |
|
||||
Все задачи реализованы. Проект готов к использованию:
|
||||
- `cf init` — создать пустую модель
|
||||
- `cf forecast --months 12` — прогноз
|
||||
- `cf import/export` — работа с Excel
|
||||
- `cf analyze` — AI-анализ (заглушка)
|
||||
|
||||
## Project State
|
||||
## Caveats
|
||||
|
||||
**Архитектура:** трёхслойный модульный монолит (Clean Architecture).
|
||||
- AI-ассистент — заглушка, промпты готовы, но не подключены к реальному API
|
||||
- Лицензия не указана — требуется решение
|
||||
- JSON-файлы — не подходит для многопользовательской работы
|
||||
- CI/CD не настроен
|
||||
|
||||
**Стек:** Python 3.11+, pydantic 2.13, openpyxl 3.1, typer 0.27, rich 15, pytest 9.1.
|
||||
## Checkpoints
|
||||
|
||||
**Тесты:** 67/67 ✅ (2.4s).
|
||||
|
||||
**Известные ограничения:** AI stub (отклонено пользователем), нет CI/CD, нет лицензии, нет mypy, нет логирования.
|
||||
|
||||
## Key Artifacts
|
||||
|
||||
- **Project state:** `.agent/context/project-state.md` — текущее состояние
|
||||
- **Tasks:** `.agent/tasks/manifest.json` — все задачи archived
|
||||
- **Archive tasks:** `.agent/archive/tasks/T1.json` … `T7.json` — полные описания
|
||||
- **Archive requests:** `.agent/archive/requests/req-T1.json` … `req-T7.json` — все approved
|
||||
- **Roadmap:** `.agent/roadmap/sources.md` — следующие шаги
|
||||
- **Archive index:** `.agent/archive/index.json`
|
||||
|
||||
## Next Steps (для следующей сессии)
|
||||
|
||||
### P0 — Кандидаты на ADR (через `/adr`)
|
||||
|
||||
1. **ADR-001: Repository pattern** — формализовать `ModelRepository` Protocol
|
||||
2. **ADR-002: Слоистая архитектура** — границы `domain/application/infrastructure`
|
||||
3. **ADR-003: Schema versioning** — политика миграций `FinancialModel`
|
||||
|
||||
### P1 — Качество и инфраструктура
|
||||
|
||||
- **CI/CD:** `.github/workflows/ci.yml` (pytest + ruff)
|
||||
- **mypy:** strict-проверка в `pyproject.toml`
|
||||
- **pre-commit:** hooks для линтинга/форматирования
|
||||
|
||||
### P2 — Полировка
|
||||
|
||||
- **Лицензия:** выбрать MIT/Apache-2.0/BSD-3, обновить `LICENSE`
|
||||
- **Логирование:** `rich.print` → `logging` для домена
|
||||
|
||||
### P3 — Долгосрочно (не в этой сессии)
|
||||
|
||||
- Monte-Carlo Simulation, FIRE Planning, REST API, Web UI, Mobile
|
||||
- Импорт банковских выписок / брокерских отчётов
|
||||
|
||||
## Ключевые точки входа в код
|
||||
|
||||
| Что | Где |
|
||||
|---|---|
|
||||
| CLI entry | `infrastructure/cli/app.py` |
|
||||
| Composition root | `infrastructure/cli/services.py:build_services` |
|
||||
| Корневая модель | `domain/model.py:FinancialModel` |
|
||||
| Прогноз | `application/forecast.py:ForecastService` |
|
||||
| Сценарии | `application/scenarios.py:ScenarioService` |
|
||||
| AI (stub) | `infrastructure/ai/assistant.py:AssistantService` |
|
||||
| JSON storage | `infrastructure/repositories/json_file_repository.py` |
|
||||
| Excel storage | `infrastructure/repositories/excel_repository.py` |
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Тесты
|
||||
pytest
|
||||
|
||||
# CLI
|
||||
cf init
|
||||
cf forecast --months 12
|
||||
cf scenario baseline
|
||||
cf compare --months 12
|
||||
cf info
|
||||
cf config account-add --name "Main" --balance 5000
|
||||
cf import-xlsx data.xlsx
|
||||
cf export-xlsx exports/report.xlsx
|
||||
|
||||
# Git
|
||||
git log --oneline -10
|
||||
```
|
||||
Файл: `.agent/checkpoints.json`
|
||||
MetaAgent версия: 1.0.0
|
||||
Все фазы: completed
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# MetaAgent Request
|
||||
# Auto-generated from user interview on 2026-07-12
|
||||
|
||||
## Параметры сессии
|
||||
|
||||
| Функция | Вкл | Аргументы |
|
||||
|---|---|---|
|
||||
| ANALYSIS | ✓ | — |
|
||||
| DESIGN | ✓ | adr=false, alternative_arch=false |
|
||||
| RED_TEAM | false | — |
|
||||
| RISK_REGISTER | false | — |
|
||||
| DECOMPOSITION | ✓ | invariant_tests=false |
|
||||
| SETUP | ✓ | — |
|
||||
| HANDOFF | ✓ | layer_structure=false |
|
||||
|
||||
## Глубина проработки
|
||||
|
||||
**Значение:** 4
|
||||
|
||||
## Цель
|
||||
|
||||
Обновление metaagent-артефактов до v1.0.0, валидация существующего кода и окружения.
|
||||
@@ -1,121 +0,0 @@
|
||||
# Roadmap Sources
|
||||
|
||||
**Дата:** 2026-10-08
|
||||
**Goal:** Обсуждение архитектуры и серьёзный refactor
|
||||
**Project type:** `existing`
|
||||
|
||||
---
|
||||
|
||||
## FUTURE Plans
|
||||
|
||||
❌ Директория `FUTURE/` отсутствует.
|
||||
|
||||
Долгосрочные планы в `README.arch.md` (раздел "Будущие возможности"). После сессии 2026-10-08 (обсуждение архитектуры) пользователь **исключил** из roadmap:
|
||||
|
||||
- ❌ **AI Financial Assistant** (полная реализация) — нет смысла сейчас (`user:direct`)
|
||||
- ❌ **AI-интеграция** (R-001) — отложено
|
||||
|
||||
Остальные долгосрочные планы (тоже не в этой сессии):
|
||||
|
||||
- Monte-Carlo Simulation
|
||||
- FIRE Planning
|
||||
- Инвестиционный прогноз
|
||||
- Импорт банковских выписок / брокерских отчётов
|
||||
- REST API
|
||||
- Web UI
|
||||
- Mobile App
|
||||
|
||||
Эти направления — **не основной фокус текущей сессии** (цель — refactor, не новые фичи).
|
||||
|
||||
## ADR-Derived Tasks
|
||||
|
||||
❌ `.agent/decisions/index.json` отсутствует — ADR-ов ещё нет.
|
||||
|
||||
## User Requests
|
||||
|
||||
| Запрос | Приоритет | Источник |
|
||||
|--------|-----------|----------|
|
||||
| Обсуждение архитектуры + серьёзный refactor | **P0** | `user:direct` (current session) |
|
||||
|
||||
## Agent-Identified Improvements (из ANALYSE)
|
||||
|
||||
Эти проблемы выявлены в `analysis-report.md` / `project-state.md` и требуют архитектурного обсуждения.
|
||||
|
||||
### Архитектурные проблемы (кандидаты на рефактор)
|
||||
|
||||
| ID | Проблема | Серьёзность | Затронутые слои |
|
||||
|---|---|---|---|
|
||||
| **A1** | **Слои не выделены явно.** `engine/` импортирует `cashflow_model/`, `cli/` импортирует всё. Нет разделения domain / application / infrastructure. | высокая | все пакеты |
|
||||
| **A2** | **Ручная сериализация** (`to_dict` / `from_dict`) в каждой модели. 7 моделей × 2 метода = 14 boilerplate-методов. | высокая | `cashflow_model/` |
|
||||
| **A3** | **Dataclass vs pydantic** — нет валидации при загрузке JSON, дублирование правил между моделями и Excel-sync. | высокая | `cashflow_model/`, `sync/` |
|
||||
| **A4** | **`float` для денег** — потеря точности при больших суммах. `Decimal` нужен для финансовых расчётов. | средняя | `cashflow_model/`, `engine/`, `sync/` |
|
||||
| **A5** | **CLI-файлы разрослись** — `cli/main.py` 330 LOC, `cli/config.py` 428 LOC. Слишком много в одном файле. | средняя | `cli/` |
|
||||
| **A6** | **i18n — строки разбросаны** по `_r()`-вызовам в `cli/i18n.py`. Нет единого механизма для engine/sync. | низкая | `cli/`, частично `engine/`, `sync/` |
|
||||
| **A7** | **Нет dependency injection** — `ForecastService` создаётся внутри `AssistantService.analyze()`. Тяжело тестировать. | средняя | `ai/`, `engine/` |
|
||||
| **A8** | **Сервисы не абстрагированы** — `ExcelSync` — конкретный класс, нет интерфейса для других storage. | средняя | `sync/`, `cashflow_model/` |
|
||||
| **A9** | **Нет репозиториев** — `FinancialModel.save/load` напрямую работает с файлом. Не расширяется (БД, S3, etc.). | средняя | `cashflow_model/` |
|
||||
| **A10** | **Нет версионирования модели** — `model.json` без `version` поля. Миграции схемы невозможны. | высокая | `cashflow_model/model.py` |
|
||||
|
||||
### Технический долг
|
||||
|
||||
| ID | Что | Из `project-state.md` |
|
||||
|---|---|---|
|
||||
| T1 | Нет CI/CD | R-003 |
|
||||
| T2 | Лицензия не выбрана | R-004 |
|
||||
| T3 | mypy не настроен | R-005 |
|
||||
| T4 | Нет логирования | — |
|
||||
| T5 | Нет pre-commit hooks | — |
|
||||
|
||||
## Consolidated Priority Queue
|
||||
|
||||
### P0 — Архитектурный рефактор (цель сессии)
|
||||
|
||||
Кандидаты на обсуждение (выбрать 1-3 направления):
|
||||
|
||||
1. **A1+A10: Введение явных слоёв + версионирование модели**
|
||||
- Выделить domain (модели), application (сервисы), infrastructure (CLI, Excel-sync, AI)
|
||||
- Добавить `version: 1` в `FinancialModel.to_dict()`
|
||||
- Подготовить инфраструктуру миграций схемы
|
||||
|
||||
2. **A2+A3: Pydantic-миграция**
|
||||
- Заменить `@dataclass` на `BaseModel`
|
||||
- Убрать ручные `to_dict` / `from_dict` (pydantic делает сам)
|
||||
- Добавить валидацию при загрузке JSON
|
||||
- ⚠️ Может потребовать `pydantic>=2.0` (новая зависимость)
|
||||
|
||||
3. **A4: Decimal для денег**
|
||||
- Мигрировать `amount`, `balance`, `value`, `rate` с `float` на `Decimal`
|
||||
- Обновить прогноз, Excel-sync, форматтеры
|
||||
- ⚠️ Большой рефактор: ~10 файлов, 50+ полей
|
||||
|
||||
4. **A5: Декомпозиция CLI**
|
||||
- `cli/main.py` → `cli/commands/init.py`, `cli/commands/forecast.py`, ...
|
||||
- `cli/config.py` → `cli/paths.py` + `cli/services.py`
|
||||
- Улучшает читаемость, не меняет поведение
|
||||
|
||||
5. **A7+A8+A9: DI + Repository pattern + абстракции**
|
||||
- Ввести `ForecastRepository`, `ExcelRepository`
|
||||
- Передавать зависимости в сервисы через конструктор
|
||||
- Упрощает тестирование, подготовка к БД/API
|
||||
|
||||
### P1 — Качество и инфраструктура
|
||||
|
||||
6. T1: GitHub Actions CI (pytest + ruff)
|
||||
7. T3: mypy в строгом режиме
|
||||
8. T4: заменить `rich.print` на `logging` для домена
|
||||
|
||||
### P2 — Полировка
|
||||
|
||||
9. T2: выбрать лицензию
|
||||
10. T5: pre-commit hooks
|
||||
|
||||
### P3 — Долгосрочно (не в этой сессии)
|
||||
|
||||
- Monte-Carlo, FIRE, REST API, Web UI, Mobile — из `README.arch.md`
|
||||
- ~~AI-интеграция (R-001)~~ — **отклонено пользователем 2026-10-08**
|
||||
|
||||
## Следующие шаги
|
||||
|
||||
→ **DECOMPOSITION** с выбранным направлением рефактора.
|
||||
→ Пользователь должен выбрать 1-3 направления из P0-списка.
|
||||
→ Если ни одно не подходит — описать желаемый результат.
|
||||
@@ -1,22 +0,0 @@
|
||||
# Project Rules
|
||||
|
||||
Правила, которым агент обязан следовать во всех фазах.
|
||||
Добавляйте сюда условия, которые должны соблюдаться всегда — они будут прочитаны
|
||||
перед началом каждой фазы и учтены при декомпозиции и реализации.
|
||||
|
||||
## Обязательные правила
|
||||
|
||||
- Всегда читать `.agent/rules/project-rules.md` перед каждой фазой
|
||||
- Следовать протоколам MetaAgent строго последовательно
|
||||
|
||||
## Запреты
|
||||
|
||||
- Не писать production-код (это работа исполнительного агента)
|
||||
- Не удалять файлы
|
||||
- Не коммитить в main/master
|
||||
|
||||
## Конвенции проекта
|
||||
|
||||
- Python-проект: snake_case для функций/переменных, PascalCase для классов
|
||||
- Использовать ruff для линтинга
|
||||
- Тесты через pytest
|
||||
@@ -1,57 +0,0 @@
|
||||
# Session Summary
|
||||
|
||||
**Session:** `metaagent-005`
|
||||
**MetaAgent version:** 3.0.0
|
||||
**Date:** 2026-10-08
|
||||
**Goal:** Обсуждение архитектуры и серьёзный refactor
|
||||
|
||||
## Phases Executed
|
||||
|
||||
- [x] INIT
|
||||
- [x] ANALYSE
|
||||
- [x] ROADMAP
|
||||
- [ ] DESIGN (skipped — existing project)
|
||||
- [x] DECOMPOSITION
|
||||
- [x] EXECUTION (7 tasks)
|
||||
- [x] METASTATE
|
||||
- [x] HANDOFF
|
||||
|
||||
## Results
|
||||
|
||||
- **Tasks completed:** 7/7 (T1–T7, все archived)
|
||||
- **Requests approved:** 7 (req-T1 … req-T7, в `.agent/archive/requests/`)
|
||||
- **Commits:** 6 production commits + 1 README
|
||||
- `feb77ef` T1: restructure to domain/application/infrastructure + version=1
|
||||
- `c765f36` T2: Pydantic v2
|
||||
- `363d440` T3: Decimal
|
||||
- `<T4>` T4: Repository pattern
|
||||
- `541a768` T5: DI
|
||||
- `<T6>` T6: CLI decompose
|
||||
- `3ef1061` T7: Final validation + README
|
||||
- **Tests:** 67/67 ✅ (было 63, +5 для репозиториев)
|
||||
- **CLI:** все команды работают, Excel round-trip OK
|
||||
|
||||
## Архитектурный рефактор (5 направлений)
|
||||
|
||||
| ID | Что | Задача |
|
||||
|---|---|---|
|
||||
| A1+A10 | Слои + version | T1 |
|
||||
| A2+A3 | Pydantic v2 | T2 |
|
||||
| A4 | Decimal для денег | T3 |
|
||||
| A7+A8+A9 | DI + Repository | T4, T5 |
|
||||
| A5 | Декомпозиция CLI | T6 |
|
||||
|
||||
## Files Changed
|
||||
|
||||
- `domain/` (new, 8 файлов)
|
||||
- `application/` (new, 3 файла + `repositories/model_repository.py`)
|
||||
- `infrastructure/` (new: `cli/{app,paths,services,i18n}.py`, `cli/commands/{10 файлов}`, `ai/`, `repositories/{json,excel}_repository.py`)
|
||||
- Удалены: `cashflow_model/`, `engine/`, `cli/`, `sync/`, `ai/` (старые имена)
|
||||
- `tests/` (обновлены + `test_repositories.py` new)
|
||||
- `pyproject.toml` (pydantic dep, новые entry-points, packages.find)
|
||||
- `README.md` (полная перезапись под новую архитектуру)
|
||||
|
||||
## Next
|
||||
|
||||
Следующий агент: читай `.agent/handoff-summary.md`.
|
||||
Кандидаты: ADR-001 (Repository), ADR-002 (слои), ADR-003 (schema versioning), CI/CD, mypy, лицензия.
|
||||
+20
-26
@@ -1,45 +1,39 @@
|
||||
# BOUNDARIES — Рамки и границы
|
||||
|
||||
Что агенту **разрешено**, **запрещено** и в каких случаях **нужно остановиться**.
|
||||
Что мета-агенту **разрешено**, **запрещено** и в каких случаях **нужно остановиться**.
|
||||
|
||||
## Разрешено
|
||||
|
||||
| Действие | Примечание |
|
||||
|---|---|
|
||||
| Читать любые файлы в целевом репозитории | Включая `.git`, конфиги, историю |
|
||||
| Создавать/изменять файлы в `.agent/` | Директория метаданных проекта (rules, decisions, tasks, context, requests, roadmap, archive) |
|
||||
| Создавать `.temp/` в корне проекта | Для временных файлов агента. Всегда в `.gitignore` |
|
||||
| Писать production-код | В фазе EXECUTION, по задачам из `manifest.json` |
|
||||
| Рефакторить существующий код | Только если это часть задачи в `manifest.json` |
|
||||
| Делать коммиты | По завершении задачи, перед созданием request |
|
||||
| Создавать/дополнять `.gitignore` | Только для добавления `.temp/` |
|
||||
| Устанавливать/обновлять зависимости | Через штатный пакетный менеджер проекта |
|
||||
| Изменять конфигурационные файлы | Только если необходимо для сборки/тестов |
|
||||
| Запускать сборку и тесты | Для верификации окружения и проверки request-ов |
|
||||
| Читать любые файлы в целевом репозитории | Все файлы, включая .git, конфиги, историю |
|
||||
| Создавать/изменять файлы в `.agent/` | Единственная директория для артефактов |
|
||||
| Устанавливать/обновлять зависимости | Только через штатный пакетный менеджер проекта |
|
||||
| Изменять конфигурационные файлы | Только если это необходимо для сборки/тестов (например, добавить requirements.txt) |
|
||||
| Запускать сборку и тесты | Для верификации окружения |
|
||||
| Читать документацию, issue, PRs | Для понимания контекста |
|
||||
| Запрашивать уточнения у пользователя | Если не хватает информации для декомпозиции |
|
||||
| Копировать исходники MetaAgent в `.agent/src/` целевого проекта | На фазе INIT, без перезаписи существующих файлов (если не указан `--update`) |
|
||||
| Копировать исходники MetaAgent в `.agent/src/` целевого проекта | Только на фазе INIT, без перезаписи существующих файлов |
|
||||
| Создавать/обновлять `AGENTS.md` в корне целевого проекта | Только если файла не существует |
|
||||
| **Обязательно:** читать `.agent/rules/project-rules.md` перед каждой фазой | Правила пользователя имеют приоритет выше стандартных протоколов |
|
||||
| Перемещать завершённые артефакты в `.agent/archive/` | На фазах METASTATE и HANDOFF |
|
||||
| **Обязательно:** после выполнения задачи создавать request в `.agent/requests/active/` | Request — единица результата |
|
||||
| Вызывать команды из `COMMANDS/` | По явной просьбе пользователя (`/adr`, `/red-team`, `/risk-register`, `/alt-arch`, `/invariant-tests`) |
|
||||
| **Обязательно:** читать `.agent/rules/project-rules.md` перед каждой фазой | Исполнение правил пользователя — приоритет выше стандартных протоколов |
|
||||
| Перемещать завершённые артефакты в `.agent/archive/` | Только на фазе HANDOFF, только для completed/failed артефактов |
|
||||
|
||||
## Запрещено
|
||||
|
||||
| Действие | Почему |
|
||||
|---|---|
|
||||
| Удалять файлы | Если файл мешает — сообщить пользователю |
|
||||
| Писать production-код | Это работа исполнительного агента |
|
||||
| Рефакторить существующий код | Мета-агент не меняет логику |
|
||||
| Удалять файлы | Если файл мешает — нужно сообщить пользователю |
|
||||
| Коммитить в main/master | Коммиты делает исполнительный агент по задачам |
|
||||
| Менять удалённые настройки CI/CD | Если CI сломан — сообщить пользователю |
|
||||
| Модифицировать код, не связанный с задачей | Только то, что нужно в рамках задачи из `manifest.json` |
|
||||
| Выполнять команды (`/adr`, `/red-team`, и т.д.) без явной просьбы | Команды — on-demand, не авто-фаза |
|
||||
| Задавать пользователю вопросы про depth / scale / фичи | В v3.0 нет шкалы глубины. Просто работай |
|
||||
| Пул-реквесты | Исполнительный агент создаёт PR после выполнения задач |
|
||||
| Модифицировать код, не связанный с задачей | Только то, что нужно для окружения |
|
||||
|
||||
## Когда остановиться
|
||||
|
||||
1. **Репозиторий не собирается** — сообщить пользователю с логом ошибки, не продолжать.
|
||||
2. **Неясна цель** — запросить уточнение, не гадать.
|
||||
3. **Обнаружены секреты/токены** — не копировать, сообщить пользователю.
|
||||
4. **Цель выходит за рамки одной сессии** — разбить, запросить приоритет.
|
||||
5. **Проект не использует известные технологии** — запросить инструкцию по сборке.
|
||||
6. **Непонятно, какую команду вызвать** — спросить пользователя, не угадывать.
|
||||
1. **Репозиторий не собирается** — сообщить пользователю с логом ошибки, не продолжать
|
||||
2. **Неясна цель** — запросить уточнение, не гадать
|
||||
3. **Обнаружены секреты/токены** — не копировать, сообщить пользователю
|
||||
4. **Цель выходит за рамки одной сессии** — разбить, запросить приоритет
|
||||
5. **Проект не использует известные технолологии** — запросить у пользователя инструкцию по сборке
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## 3.0.0 — Упрощение модели
|
||||
|
||||
**Дата:** 2026-10-08
|
||||
|
||||
### Что изменилось
|
||||
|
||||
Принята модель «жизненный цикл + команды на вызов» вместо «жизненный цикл с уровнями глубины».
|
||||
|
||||
**Удалено:**
|
||||
- Шкала глубины (depth 1-10) и все её варианты (Scaffold/Light/Standard/Deep/Maximum).
|
||||
- Условные фичи в фазах: `adr`, `alternative_arch`, `red_team`, `risk_register`, `invariant_tests`.
|
||||
- Интервью с пользователем на старте (5 вопросов про depth и фичи).
|
||||
- `.agent/metaagent-request.md` — конфиг-файл, который сейчас не нужен.
|
||||
- `TEMPLATES/metaagent-request.md`.
|
||||
|
||||
**Добавлено:**
|
||||
- Директория `COMMANDS/` с пятью on-demand инструкциями: `adr.md`, `red-team.md`, `risk-register.md`, `alt-arch.md`, `invariant-tests.md`.
|
||||
- `GUIDE.md` — заменяет `META_AGENT_GUIDE.md`, описание цикла + список команд.
|
||||
- `CHANGELOG.md` — этот файл.
|
||||
|
||||
**Переименовано / перенумеровано:**
|
||||
- `META_AGENT_GUIDE.md` → `GUIDE.md`.
|
||||
- `PROTOCOLS/01_ANALYSIS.md` → `01_ANALYSE.md`.
|
||||
- `PROTOCOLS/02_DESIGN.md` → `03_DESIGN.md`.
|
||||
- `PROTOCOLS/03_DECOMPOSITION.md` → `04_DECOMPOSITION.md`.
|
||||
- `PROTOCOLS/04_EXECUTION.md` → `05_EXECUTION.md`.
|
||||
- `PROTOCOLS/05_HANDOFF.md` → `07_HANDOFF.md`.
|
||||
- `PROTOCOLS/06_METASTATE.md` остался под тем же именем (теперь фаза 6).
|
||||
|
||||
**Удалены протоколы:**
|
||||
- `PROTOCOLS/00_CONFIG.md` — конфигурация больше не нужна.
|
||||
- `PROTOCOLS/00_MIGRATE.md` — миграция теперь документируется в этом CHANGELOG.
|
||||
- `PROTOCOLS/04_ENVIRONMENT_SETUP.md` — поглощён фазой `00_INIT.md`.
|
||||
- `PROTOCOLS/02b_REDTEAM.md` — теперь команда `COMMANDS/red-team.md`.
|
||||
|
||||
**Структура `.agent/checkpoints.json`** упрощена: убраны `config.depth`, `config.design.adr`, `config.red_team`, `config.risk_register`, `config.decomposition.invariant_tests`.
|
||||
|
||||
### Миграция с v2.1 → v3.0
|
||||
|
||||
Для проектов, созданных с MetaAgent v2.1:
|
||||
|
||||
1. **Удалить** из `.agent/checkpoints.json` секцию `config` целиком (она больше не читается).
|
||||
2. **Удалить** `.agent/metaagent-request.md` (не используется).
|
||||
3. **Удалить** `.agent/decisions/config.json`, если есть (аналог config для решений).
|
||||
4. **Запустить** `install.sh --update` (или `install.ps1 -Update` / `install.bat --update`) — перезапишет исходники MetaAgent.
|
||||
5. **Переименовать** пути в существующих артефактах: `layer-1/adr/` → `decisions/` (если остались с v1.x), `layer-2/analysis-report.md` → `context/analysis-report.md` и т.п. — это касается только проектов, оставшихся на v1.x.
|
||||
6. **Записать** в `.agent/checkpoints.json` новое значение `metaagent_version: "3.0.0"`.
|
||||
|
||||
`request.json`, `manifest.json`, `decisions/index.json` остаются в том же формате, что в v2.1.
|
||||
|
||||
### Экономия
|
||||
|
||||
| | v2.1 | v3.0 |
|
||||
|---|---|---|
|
||||
| Markdown строк всего | ~3 820 | ~1 800 (целевой) |
|
||||
| Протоколов | 10 | 8 |
|
||||
| Уровней конфигурации | 5 (depth) | 0 |
|
||||
|
||||
---
|
||||
|
||||
## 2.1.0 — Project Loop + Work Loop + Requests
|
||||
|
||||
**Дата:** 2025-08 (предыдущая версия)
|
||||
|
||||
- Введён двухконтурный жизненный цикл: Project Loop (однократно) + Work Loop (циклически).
|
||||
- Добавлены фазы: ROADMAP, METASTATE, RED_TEAM.
|
||||
- Введены `requests/` как единица результата выполненной задачи.
|
||||
- Введён `metaagent-request.md` с конфигом сессии (depth scale, фичи).
|
||||
- Введена структура `.agent/` с семантическими директориями: `decisions/`, `tasks/`, `context/`, `rules/`, `requests/`, `roadmap/`, `archive/`.
|
||||
- Шкала глубины 1-10 с условными фичами (adr, alternative_arch, red_team, risk_register, invariant_tests).
|
||||
|
||||
## 2.0.0 — Реструктуризация `.agent/`
|
||||
|
||||
- Переход от слоистой структуры `layer-0..3` к семантическим директориям.
|
||||
- Полный MIGRATE-протокол для апгрейда с v1.x.
|
||||
|
||||
## 1.1.0 — Добавлены rules, archive
|
||||
|
||||
- `PROTOCOLS/01_ANALYSIS.md` обзавёлся правилами из `.agent/rules/`.
|
||||
- Добавлена директория `archive/`.
|
||||
|
||||
## 1.0.0 — Первый релиз
|
||||
|
||||
- Односессионный pipeline: INIT → ANALYSE → DECOMP → SETUP → HANDOFF.
|
||||
- Структура `layer-0..3`.
|
||||
@@ -1,95 +0,0 @@
|
||||
# ADR — Architecture Decision Record
|
||||
|
||||
## Назначение
|
||||
|
||||
Зафиксировать архитектурное решение в `.agent/decisions/NNN-slug.md` так, чтобы будущий агент (или человек) мог понять: что решили, почему, какие альтернативы рассматривали, какие последствия.
|
||||
|
||||
ADR создаются по явной команде пользователя: «запиши это как решение», «/adr», «сделай ADR для текущего подхода».
|
||||
|
||||
## Когда вызывать
|
||||
|
||||
- Принято неочевидное архитектурное решение (выбор БД, паттерна, библиотеки, структуры модулей).
|
||||
- Решение может измениться в будущем — стоит зафиксировать контекст.
|
||||
- Есть trade-off, который нужно объяснить следующему агенту.
|
||||
|
||||
Не вызывать для очевидных вещей: «используем pytest», «классы называем в PascalCase».
|
||||
|
||||
## Вход
|
||||
|
||||
- Контекст решения: что обсуждалось, какие варианты сравнивались, что выбрали.
|
||||
- `.agent/decisions/index.json` — текущий список ADR (для нумерации).
|
||||
- `.agent/context/project-state.md` — текущее состояние проекта.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Определить номер
|
||||
|
||||
Прочитать `.agent/decisions/index.json`. Следующий номер = max существующих + 1. Если файла нет — создать, начать с 001.
|
||||
|
||||
### 2. Slug
|
||||
|
||||
Короткое имя в kebab-case, отражающее суть: `use-sqlite-for-mvp`, `auth-via-jwt-cookies`, `modular-monolith`.
|
||||
|
||||
### 3. Записать ADR
|
||||
|
||||
Создать `.agent/decisions/{NNN}-{slug}.md` по шаблону `TEMPLATES/adr-NNNN.md`:
|
||||
|
||||
```markdown
|
||||
# {NNN}. {Заголовок}
|
||||
|
||||
**Дата:** {YYYY-MM-DD}
|
||||
**Статус:** Accepted | Superseded by {NNN} | Deprecated
|
||||
|
||||
## Контекст
|
||||
|
||||
{Что за проблема. Какие ограничения. Что нужно было решить.}
|
||||
|
||||
## Решение
|
||||
|
||||
{Что выбрали. Коротко и конкретно.}
|
||||
|
||||
## Альтернативы, которые рассмотрели
|
||||
|
||||
### {Альтернатива 1}
|
||||
{Описание. Почему не выбрали.}
|
||||
|
||||
### {Альтернатива 2}
|
||||
{Описание. Почему не выбрали.}
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
- {что становится лучше}
|
||||
|
||||
### Отрицательные
|
||||
- {что становится хуже или сложнее}
|
||||
|
||||
### Инварианты
|
||||
- {что не должно сломаться, чтобы решение оставалось валидным}
|
||||
```
|
||||
|
||||
### 4. Обновить index.json
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"decisions": [
|
||||
{ "id": "001", "title": "Использовать SQLite для MVP", "file": "001-use-sqlite-for-mvp.md", "status": "Accepted" }
|
||||
],
|
||||
"last_updated": "{timestamp}"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Если есть supersession
|
||||
|
||||
Если новый ADR отменяет старый — в старом ADR поставить `Статус: Superseded by {NNN}` и добавить ссылку. В новом — в контексте упомянуть, что отменяет.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/decisions/{NNN}-{slug}.md`
|
||||
- Обновлённый `.agent/decisions/index.json`
|
||||
|
||||
## Связанные команды
|
||||
|
||||
- **/invariant-tests** — после ADR можно зафиксировать инварианты как задачи в manifest.
|
||||
- **/alt-arch** — если хочется явно зафиксировать альтернативу до решения.
|
||||
@@ -1,85 +0,0 @@
|
||||
# Alternative Architecture
|
||||
|
||||
## Назначение
|
||||
|
||||
Описать альтернативный вариант архитектуры / подхода, чтобы сравнить с текущим и принять осознанное решение. Не «сделать вместо», а «сравнить и выбрать».
|
||||
|
||||
## Когда вызывать
|
||||
|
||||
- Текущий дизайн кажется спорным, нужна трезвая оценка альтернативы.
|
||||
- Хочется зафиксировать «почему не сделали иначе» — потом пригодится при росте.
|
||||
- Перед крупным решением (выбор БД, монолит-vs-микросервисы, sync-vs-async).
|
||||
|
||||
## Вход
|
||||
|
||||
- Текущий дизайн / план (`.agent/context/design-report.md` или текущее состояние).
|
||||
- Ограничения проекта (сроки, стек, бюджет).
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Определить, что сравниваем
|
||||
|
||||
Один конкретный вопрос: «SQLite vs PostgreSQL», «монолит vs микросервисы», «REST vs GraphQL», «sync-обработка vs очередь».
|
||||
|
||||
### 2. Сформулировать альтернативу
|
||||
|
||||
Краткое описание: что предлагается вместо текущего подхода. Без длинного дизайна — на уровне «как это работает и чем отличается».
|
||||
|
||||
### 3. Сравнить
|
||||
|
||||
| Аспект | Текущий | Альтернатива |
|
||||
|---|---|---|
|
||||
| Сложность реализации | | |
|
||||
| Время до MVP | | |
|
||||
| Производительность | | |
|
||||
| Масштабирование | | |
|
||||
| Поддерживаемость | | |
|
||||
| Стоимость изменений | | |
|
||||
| Риски | | |
|
||||
|
||||
### 4. Записать
|
||||
|
||||
Создать `.agent/context/alt-architecture.md` (если файла нет) или дополнить. Структура:
|
||||
|
||||
```markdown
|
||||
# Alternative Architecture — {что сравниваем}
|
||||
|
||||
**Дата:** {YYYY-MM-DD}
|
||||
|
||||
## Контекст
|
||||
|
||||
{Почему рассматриваем альтернативу. Что не устраивает в текущем.}
|
||||
|
||||
## Альтернатива
|
||||
|
||||
{Краткое описание. Архитектура, ключевые компоненты, поток данных.}
|
||||
|
||||
## Сравнение
|
||||
|
||||
{Таблица из шага 3.}
|
||||
|
||||
## Когда альтернатива выигрывает
|
||||
|
||||
{В каких условиях стоит переключиться. Триггеры для миграции.}
|
||||
|
||||
## Когда остаёмся на текущем
|
||||
|
||||
{Что в текущем работает достаточно хорошо, чтобы не менять.}
|
||||
|
||||
## Рекомендация
|
||||
|
||||
{Остаёмся или мигрируем. Почему.}
|
||||
```
|
||||
|
||||
### 5. Связать с ADR
|
||||
|
||||
Если после сравнения принимается решение — использовать **/adr** для фиксации. Альтернативный файл остаётся как исторический артефакт.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/context/alt-architecture.md`
|
||||
|
||||
## Связанные команды
|
||||
|
||||
- **/adr** — зафиксировать итоговое решение.
|
||||
- **/risk-register** — если альтернатива снимает/добавляет риски.
|
||||
@@ -1,68 +0,0 @@
|
||||
# Invariant Tests
|
||||
|
||||
## Назначение
|
||||
|
||||
Превратить инварианты из ADR в задачи-тесты в `.agent/tasks/manifest.json`. Инвариант — это «что не должно сломаться, чтобы ADR оставался валидным». Без явного теста это просто слова.
|
||||
|
||||
## Когда вызывать
|
||||
|
||||
- После создания ADR, в секции «Инварианты» которого перечислены условия валидности решения.
|
||||
- Когда хочется, чтобы архитектурные решения были защищены регрессионными тестами.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/decisions/*.md` — ADR с секцией «Инварианты».
|
||||
- `.agent/tasks/manifest.json` — текущий манифест (для нумерации задач).
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Найти ADR с инвариантами
|
||||
|
||||
Прочитать все `.agent/decisions/*.md`, найти секции «Инварианты».
|
||||
|
||||
### 2. Для каждого инварианта — задача
|
||||
|
||||
Каждый инвариант = одна задача-тест. Формат:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "T-INV-001",
|
||||
"title": "Invariant: auth-сессия не переживает рестарт сервиса",
|
||||
"type": "test",
|
||||
"origin": "invariant:001",
|
||||
"depends_on": [],
|
||||
"acceptance_criteria": [
|
||||
"Тест рестартит auth-сервис и проверяет, что все сессии инвалидированы",
|
||||
"Тест проверяет, что refresh-токен не работает после рестарта"
|
||||
],
|
||||
"files": [
|
||||
"tests/auth/test_invariants.py"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Добавить в manifest
|
||||
|
||||
Записать задачи в `.agent/tasks/manifest.json` с `status: "pending"`. Связать `depends_on` с задачами, которые реализуют компонент (если ещё не выполнены).
|
||||
|
||||
### 4. Связать с ADR
|
||||
|
||||
В самом ADR добавить (опционально) ссылку на задачу-инвариант:
|
||||
|
||||
```markdown
|
||||
## Инварианты
|
||||
- {{ ... }}
|
||||
|
||||
### Покрытие тестами
|
||||
- T-INV-001: ...
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- Новые задачи в `.agent/tasks/manifest.json` с `origin: "invariant:{adr_id}"`
|
||||
- (опционально) обновлённый ADR со ссылкой на задачи
|
||||
|
||||
## Связанные команды
|
||||
|
||||
- **/adr** — источник инвариантов.
|
||||
- **/risk-register** — некоторые инварианты рождаются из рисков.
|
||||
@@ -1,104 +0,0 @@
|
||||
# Red Team Review
|
||||
|
||||
## Назначение
|
||||
|
||||
Попытаться сломать текущий дизайн / архитектуру / план. Зафиксировать найденные уязвимости в `.agent/context/red-team-report.md`, чтобы разработчик мог их закрыть до реализации.
|
||||
|
||||
Red Team — это adversarial-проход по дизайну. Не «улучшить», а «найти, что не так».
|
||||
|
||||
## Когда вызывать
|
||||
|
||||
- После фазы DESIGN, до декомпозиции задач.
|
||||
- Когда дизайн кажется слишком гладким.
|
||||
- Перед крупным рефакторингом.
|
||||
- Когда непонятно, какие риски у текущего подхода.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/context/design-report.md` (если есть).
|
||||
- `.agent/decisions/*.md` — связанные ADR.
|
||||
- `.agent/context/project-state.md` — текущее состояние.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Прочитать целевой дизайн
|
||||
|
||||
Понять, что именно ревьюится: вся архитектура, конкретный модуль, конкретное решение.
|
||||
|
||||
### 2. Провести атаки по категориям
|
||||
|
||||
#### 2.1. Нагрузка и масштабирование
|
||||
- Что будет при 10x / 100x объёма?
|
||||
- Где узкое место?
|
||||
- Что сломается первым?
|
||||
|
||||
#### 2.2. Отказы и доступность
|
||||
- Что если упадёт БД / кэш / внешний сервис?
|
||||
- Есть ли SPOF (single point of failure)?
|
||||
- Как восстанавливаемся?
|
||||
|
||||
#### 2.3. Безопасность
|
||||
- Где хранятся секреты?
|
||||
- Какие поверхности атаки?
|
||||
- Что с аутентификацией / авторизацией?
|
||||
- Injection, SSRF, XSS — что релевантно?
|
||||
|
||||
#### 2.4. Корректность
|
||||
- Где гонки (race conditions)?
|
||||
- Что с консистентностью данных?
|
||||
- Какие edge cases не покрыты?
|
||||
|
||||
#### 2.5. Поддерживаемость
|
||||
- Что будет сложно менять через год?
|
||||
- Где связность, которую придётся разрывать?
|
||||
- Какие зависимости могут устареть?
|
||||
|
||||
#### 2.6. Миграция и совместимость
|
||||
- Если меняем API — как старые клиенты переживут?
|
||||
- Если меняем схему БД — что со старыми данными?
|
||||
- Если выкатываем поэтапно — какой план?
|
||||
|
||||
### 3. Записать отчёт
|
||||
|
||||
Создать `.agent/context/red-team-report.md` (если файла нет) или дополнить:
|
||||
|
||||
```markdown
|
||||
# Red Team Review — {что ревьюим}
|
||||
|
||||
**Дата:** {YYYY-MM-DD}
|
||||
**Цель:** {что именно атакуем}
|
||||
|
||||
## Критические находки
|
||||
|
||||
### R1. {Краткое название}
|
||||
- **Категория:** безопасность / нагрузка / корректность / ...
|
||||
- **Сценарий:** {как воспроизвести}
|
||||
- **Воздействие:** {что произойдёт}
|
||||
- **Рекомендация:** {что сделать}
|
||||
|
||||
## Существенные находки
|
||||
|
||||
### R2. ...
|
||||
|
||||
## Минорные находки
|
||||
|
||||
### R3. ...
|
||||
|
||||
## Что выдержало атаку
|
||||
|
||||
- {Что оказалось надёжным — это тоже полезно знать.}
|
||||
```
|
||||
|
||||
### 4. Связать с задачами
|
||||
|
||||
Если находка превращается в задачу — добавить в `.agent/tasks/manifest.json` (фаза DECOMPOSITION) с `origin: "red-team:{номер_находки}"`.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/context/red-team-report.md`
|
||||
- (опционально) новые задачи в manifest
|
||||
|
||||
## Связанные команды
|
||||
|
||||
- **/adr** — если Red Team выявил, что нужно зафиксировать решение иначе.
|
||||
- **/risk-register** — для систематизации рисков.
|
||||
@@ -1,80 +0,0 @@
|
||||
# Risk Register
|
||||
|
||||
## Назначение
|
||||
|
||||
Явный реестр допущений и рисков проекта в `.agent/context/risk-register.md`. Чтобы не держать в голове «ну мы же понимаем, что X может сломаться» — а записать, оценить и (если надо) превратить в задачи.
|
||||
|
||||
## Когда вызывать
|
||||
|
||||
- В начале проекта — зафиксировать стартовые допущения.
|
||||
- При появлении нового риска (новый внешний сервис, новая зависимость, новое требование).
|
||||
- При обзоре дизайна (после DESIGN или Red Team).
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/context/design-report.md` (если есть).
|
||||
- `.agent/context/analysis-report.md` — что уже знаем о проекте.
|
||||
- `.agent/decisions/*.md` — принятые решения (могут быть источниками рисков).
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Собрать риски
|
||||
|
||||
Источники:
|
||||
- Допущения, на которых держится дизайн («считаем, что PostgreSQL выдержит 1k qps»).
|
||||
- Внешние зависимости без SLA.
|
||||
- Технологии, которые команда не знает.
|
||||
- Сроки, которые давят.
|
||||
- Решения, которые сложно откатить.
|
||||
|
||||
### 2. Оценить каждый риск
|
||||
|
||||
По двум осям:
|
||||
- **Вероятность** (1-низкая, 2-средняя, 3-высокая).
|
||||
- **Воздействие** (1-небольшое, 2-серьёзное, 3-критическое).
|
||||
|
||||
`score = вероятность × воздействие` (1-9).
|
||||
|
||||
### 3. Записать
|
||||
|
||||
Создать или дополнить `.agent/context/risk-register.md` по шаблону `TEMPLATES/risk-register.md`:
|
||||
|
||||
```markdown
|
||||
# Risk Register
|
||||
|
||||
**Дата:** {YYYY-MM-DD}
|
||||
|
||||
## Высокий риск (score 6-9)
|
||||
|
||||
### R-001. {Краткое название}
|
||||
- **Категория:** технический / продуктовый / организационный
|
||||
- **Описание:** {что может пойти не так}
|
||||
- **Воздействие:** {что будет если случится}
|
||||
- **Вероятность:** 3 / 2 / 1
|
||||
- **Счёт:** 9 / 6 / 4
|
||||
- **Митигация:** {что делаем чтобы уменьшить}
|
||||
- **Владелец:** {кто отвечает}
|
||||
- **Статус:** open / mitigated / accepted / closed
|
||||
|
||||
## Средний риск (score 3-4)
|
||||
...
|
||||
|
||||
## Низкий риск (score 1-2)
|
||||
...
|
||||
|
||||
## Закрытые риски
|
||||
...
|
||||
```
|
||||
|
||||
### 4. Связать с задачами
|
||||
|
||||
Если риск требует действия — добавить задачу в `.agent/tasks/manifest.json` с `origin: "risk:R-001"`.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/context/risk-register.md`
|
||||
|
||||
## Связанные команды
|
||||
|
||||
- **/red-team** — источник технических рисков.
|
||||
- **/adr** — некоторые риски закрываются через принятое решение.
|
||||
@@ -1,205 +0,0 @@
|
||||
# MetaAgent GUIDE v3.0
|
||||
|
||||
MetaAgent — набор инструкций для AI-агента. Задача: превратить хаотичное общение с агентом в структурированный процесс, в котором состояние проекта переживает любую сессию.
|
||||
|
||||
## Два слоя
|
||||
|
||||
- **Цикл** (всегда, по необходимости) — последовательность фаз, которую агент проходит при работе с проектом.
|
||||
- **Команды** (по запросу пользователя) — on-demand инструкции, которые не привязаны к фазе.
|
||||
|
||||
Состояние проекта живёт в `.agent/` целевого репозитория. Следующий агент читает `.agent/` и не лезет в исходники.
|
||||
|
||||
---
|
||||
|
||||
## Цикл
|
||||
|
||||
```
|
||||
.agent/checkpoints.json
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ PROJECT LOOP (разово) │
|
||||
│ │
|
||||
│ INIT → ANALYSE → ROADMAP → │
|
||||
│ → [DESIGN] → DECOMPOSITION │
|
||||
│ │
|
||||
│ Выход: .agent/tasks/manifest.json │
|
||||
└──────────────────┬──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ WORK LOOP (циклически) │
|
||||
│ │
|
||||
│ EXECUTION → (request) → │
|
||||
│ → METASTATE (по команде) │
|
||||
│ │
|
||||
│ Беру задачу → делаю → request → │
|
||||
│ накопилось → METASTATE │
|
||||
└──────────────────┬──────────────────┘
|
||||
│
|
||||
▼
|
||||
HANDOFF (завершение)
|
||||
```
|
||||
|
||||
Фазы выполняются **строго последовательно** внутри PROJECT LOOP. WORK LOOP повторяется многократно.
|
||||
|
||||
### Ветвление
|
||||
|
||||
| Тип проекта | Цикл |
|
||||
|---|---|
|
||||
| **existing** | INIT → ANALYSE → ROADMAP → DECOMPOSITION → EXECUTION → METASTATE → HANDOFF |
|
||||
| **greenfield / scaffold** | + фаза DESIGN между ROADMAP и DECOMPOSITION |
|
||||
|
||||
Тип проекта определяется автоматически в фазе ANALYSE. Никакого интервью с пользователем, никакой шкалы глубины.
|
||||
|
||||
---
|
||||
|
||||
## Фазы
|
||||
|
||||
| # | Фаза | Протокол | Что делает |
|
||||
|---|---|---|---|
|
||||
| 0 | INIT | `PROTOCOLS/00_INIT.md` | Создаёт `.agent/`, ставит исходники, инициализирует checkpoints |
|
||||
| 1 | ANALYSE | `PROTOCOLS/01_ANALYSE.md` | Сканирует проект, создаёт `analysis-report.md` + начальный `project-state.md` |
|
||||
| 2 | ROADMAP | `PROTOCOLS/02_ROADMAP.md` | Собирает источники задач (FUTURE, ADR, user-запросы) → `roadmap/sources.md` |
|
||||
| 3 | DESIGN | `PROTOCOLS/03_DESIGN.md` | Только greenfield. Архитектура, модули, API, модели |
|
||||
| 4 | DECOMPOSITION | `PROTOCOLS/04_DECOMPOSITION.md` | Разбивает цель на атомарные задачи → `tasks/manifest.json` |
|
||||
| 5 | EXECUTION | `PROTOCOLS/05_EXECUTION.md` | Цикл: берёт задачу → код → тесты → коммит → request |
|
||||
| 6 | METASTATE | `PROTOCOLS/06_METASTATE.md` | По команде. Ревью requests, обновление project-state, handoff-summary |
|
||||
| 7 | HANDOFF | `PROTOCOLS/07_HANDOFF.md` | Валидация `.agent/`, финализация checkpoints, session-summary |
|
||||
|
||||
---
|
||||
|
||||
## Команды
|
||||
|
||||
Эти инструкции выполняются **по явной просьбе пользователя** в любой момент сессии. Они не привязаны к фазе.
|
||||
|
||||
| Команда | Файл | Что делает |
|
||||
|---|---|---|
|
||||
| «запиши ADR» / «/adr» | `COMMANDS/adr.md` | Создаёт `.agent/decisions/NNN-slug.md` |
|
||||
| «red team» / «/red-team» | `COMMANDS/red-team.md` | Создаёт `.agent/context/red-team-report.md` — попытка сломать дизайн |
|
||||
| «risk register» / «/risk-register» | `COMMANDS/risk-register.md` | Создаёт `.agent/context/risk-register.md` |
|
||||
| «альтернативная архитектура» / «/alt-arch» | `COMMANDS/alt-arch.md` | Описывает альтернативу текущему дизайну |
|
||||
| «invariant-тесты» / «/invariant-tests» | `COMMANDS/invariant-tests.md` | Создаёт задачи-инварианты для ADR |
|
||||
|
||||
### Когда вызывать
|
||||
|
||||
- **ADR** — после архитектурного решения, которое нужно зафиксировать. Типично во время DESIGN или при появлении неочевидного выбора в EXECUTION.
|
||||
- **Red Team** — после готового дизайна, чтобы найти слабые места до реализации.
|
||||
- **Risk Register** — в начале проекта или при появлении новых допущений.
|
||||
- **Alt Arch** — если сомневаетесь в выбранном подходе, хотите сравнить варианты.
|
||||
- **Invariant Tests** — после ADR, чтобы зафиксировать «что не должно сломаться».
|
||||
|
||||
Команды **не обязательны**. Если не вызваны — не выполняются. Состояние проекта от них не зависит.
|
||||
|
||||
---
|
||||
|
||||
## Структура `.agent/`
|
||||
|
||||
```
|
||||
.agent/
|
||||
checkpoints.json # состояние сессии (ядро)
|
||||
session-summary.md # краткая сводка сессии
|
||||
handoff-summary.md # сводка для следующего агента (создаётся METASTATE)
|
||||
|
||||
src/ # исходники MetaAgent (всегда)
|
||||
GUIDE.md
|
||||
BOUNDARIES.md
|
||||
CHANGELOG.md
|
||||
PROTOCOLS/
|
||||
COMMANDS/
|
||||
TEMPLATES/
|
||||
VERSION
|
||||
install.sh / install.ps1
|
||||
|
||||
rules/
|
||||
project-rules.md # ваши правила — читать перед каждой фазой
|
||||
|
||||
roadmap/ # источники задач
|
||||
sources.md
|
||||
archive/
|
||||
|
||||
decisions/ # ADR
|
||||
index.json
|
||||
001-*.md
|
||||
|
||||
tasks/ # задачи
|
||||
manifest.json + manifest.md
|
||||
backlog/
|
||||
|
||||
requests/ # результаты выполненных задач
|
||||
active/ # ready_for_review
|
||||
archive/ # approved / rejected
|
||||
|
||||
context/
|
||||
analysis-report.md
|
||||
project-state.md # обновляется в METASTATE
|
||||
design-report.md # только greenfield
|
||||
red-team-report.md # если вызывали /red-team
|
||||
risk-register.md # если вызывали /risk-register
|
||||
baseline-test-report.log
|
||||
|
||||
archive/
|
||||
index.json
|
||||
tasks/
|
||||
decisions/
|
||||
requests/
|
||||
checkpoints/
|
||||
```
|
||||
|
||||
`.temp/` в корне проекта — для временных файлов агента. Всегда в `.gitignore`.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoints
|
||||
|
||||
`checkpoints.json` обновляется после каждой фазы:
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "3.0.0",
|
||||
"session_id": "<uuid>",
|
||||
"target_repo": "<path>",
|
||||
"goal": "<цель>",
|
||||
"project_type": "existing | greenfield | scaffold",
|
||||
"phases": {
|
||||
"init": "completed",
|
||||
"analyse": "completed",
|
||||
"roadmap": "completed",
|
||||
"design": "skipped",
|
||||
"decomposition": "completed",
|
||||
"execution": "in_progress",
|
||||
"metastate": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "...", "status": "in_progress", "origin": "user:direct" }
|
||||
],
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
Секции `config` больше нет. Параметры, которые раньше были в `config` (depth, adr, red_team и т.п.), теперь либо не существуют, либо живут в отдельных командах.
|
||||
|
||||
---
|
||||
|
||||
## Принципы
|
||||
|
||||
### Цикл vs команды
|
||||
|
||||
Цикл — это «что агент делает по умолчанию». Команды — «что агент делает по явной просьбе». Не путать: ADR не запускается автоматически в DESIGN, а только когда пользователь скажет «запиши это как решение».
|
||||
|
||||
### `.agent/` как слепок проекта
|
||||
|
||||
После METASTATE `.agent/` содержит всю картину. Следующий агент читает только `.agent/`, не исходники.
|
||||
|
||||
### Request — единица результата
|
||||
|
||||
Каждая выполненная задача в EXECUTION завершается созданием `request` (`.agent/requests/active/req-{id}.json`). Request содержит суть изменений, коммиты, верификацию, закрытые acceptance criteria. Ревью request-ов происходит в METASTATE.
|
||||
|
||||
### Правила выше протоколов
|
||||
|
||||
Перед каждой фазой читать `.agent/rules/project-rules.md`. Если правило пользователя противоречит протоколу — следовать правилу.
|
||||
|
||||
### Контекст бесконечно не растёт
|
||||
|
||||
Завершённые задачи архивируются в `.agent/archive/tasks/`, request-ы — в `.agent/requests/archive/`. Текущий manifest остаётся lean.
|
||||
@@ -0,0 +1,336 @@
|
||||
# META_AGENT_GUIDE — Главная инструкция
|
||||
|
||||
## Жизненный цикл сессии
|
||||
|
||||
```
|
||||
.agent/metaagent-request.md
|
||||
│
|
||||
▼
|
||||
INIT → ANALYSE → [DESIGN] → [RED_TEAM] → DECOMPOSITION → SETUP → (CHECKPOINT)* → HANDOFF → EXIT
|
||||
│ │
|
||||
▼ ▼
|
||||
ADR (опц.) Invariant Tasks (опц.)
|
||||
Alt.Arch (опц.)
|
||||
Risk Register (опц.)
|
||||
```
|
||||
|
||||
Фазы выполняются **строго последовательно**. Фаза DESIGN — только если project_type = greenfield/scaffold.
|
||||
Фаза RED_TEAM — только если config.red_team = yes.
|
||||
|
||||
Все артефакты размещаются в `.agent/` целевого репозитория (с layer-структурой или плоские, в зависимости от config).
|
||||
|
||||
---
|
||||
|
||||
## Конфигурация сессии (.agent/metaagent-request.md)
|
||||
|
||||
Перед запуском сессии пользователь заполняет `.agent/metaagent-request.md` (см. `TEMPLATES/metaagent-request.md`). Файл должен находиться в директории `.agent/` целевого репозитория.
|
||||
|
||||
Ключевые параметры:
|
||||
|
||||
### Шкала глубины (depth 1-10)
|
||||
|
||||
| Уровень | Название | Что выполняется |
|
||||
|---|---|---|
|
||||
| 1-2 | Scaffold | INIT → ANALYSIS → SETUP (только структура, без реализации) |
|
||||
| 3-4 | Light | + DESIGN (без ADR/альтернатив), DECOMPOSITION (без инвариантов), HANDOFF — **(default)** |
|
||||
| 5-6 | Standard | полный цикл с базовым DESIGN и DECOMPOSITION |
|
||||
| 7-8 | Deep | + ADR, Alternative Architecture, Risk Register, Invariant Tests |
|
||||
| 9-10 | Maximum | + Red Team Review, Executable Invariants для всех ADR |
|
||||
|
||||
### Функции (таблица вкл/выкл)
|
||||
|
||||
| Функция | Фаза | Глубина | Описание |
|
||||
|---|---|---|---|
|
||||
| adr | DESIGN | >=7 | Создание ADR для каждого ключевого решения |
|
||||
| alternative_arch | DESIGN | >=7 | Обязательное описание альтернативной архитектуры |
|
||||
| red_team | DESIGN (после) | >=9 | Red Team Review — попытка разрушить архитектуру |
|
||||
| risk_register | DESIGN | >=7 | Явный реестр допущений |
|
||||
| invariant_tests | DECOMPOSITION | >=7 | Задачи-инварианты для каждого ADR |
|
||||
| layer_structure | HANDOFF | любая | Организация .agent/ по слоям (layer-0..3) |
|
||||
|
||||
---
|
||||
|
||||
## Фаза 0: INIT
|
||||
|
||||
**Вход:** целевой репозиторий + опционально `.agent/metaagent-request.md`.
|
||||
|
||||
**Протокол:** `PROTOCOLS/00_CONFIG.md`
|
||||
|
||||
**Действия:**
|
||||
- Прочитать `VERSION` — текущая версия MetaAgent
|
||||
- Склонировать/открыть целевой репозиторий
|
||||
- Создать директорию `.agent/` в корне целевого репозитория (если нет)
|
||||
- **Установить исходники MetaAgent в `.agent/src/`:**
|
||||
- Скопировать `META_AGENT_GUIDE.md`, `BOUNDARIES.md`, `WORKFLOW.md`, `VERSION` в `.agent/src/`
|
||||
- Скопировать `PROTOCOLS/` и `TEMPLATES/` в `.agent/src/`
|
||||
- Скопировать `install.sh` и `install.ps1` в `.agent/src/` (для возможности обновления)
|
||||
- Если файлы уже существуют — пропустить (не перезаписывать)
|
||||
- **Создать `.agent/rules/`** — директорию для пользовательских правил
|
||||
- Если `.agent/rules/project-rules.md` не существует — создать из шаблона `.agent/src/TEMPLATES/project-rules.md`
|
||||
- **Создать/обновить `AGENTS.md` в корне целевого репозитория** (если нет — создать, если есть — не трогать)
|
||||
- Прочитать `PROTOCOLS/00_CONFIG.md`
|
||||
- Выполнить 00_CONFIG:
|
||||
- Если `.agent/metaagent-request.md` существует — прочитать config из него
|
||||
- Если нет — провести интервью с пользователем (или принять `default`)
|
||||
- Валидировать config относительно depth
|
||||
- Если не было файла — создать `.agent/metaagent-request.md` с пометкой Auto-generated
|
||||
- **Проверить версию:** если `.agent/checkpoints.json` существует → выполнить `PROTOCOLS/00_MIGRATE.md` (сравнить metaagent_version, применить миграцию при необходимости)
|
||||
- Прочитать `PROTOCOLS/01_ANALYSIS.md`
|
||||
- Инициализировать `.agent/checkpoints.json` с `metaagent_version` (если не существовал)
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "1.1.0",
|
||||
"session_id": "<uuid>",
|
||||
"target_repo": "<path>",
|
||||
"goal": "<цель от пользователя>",
|
||||
"project_type": "pending",
|
||||
"config": {
|
||||
"depth": 4,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
},
|
||||
"phases": {
|
||||
"analysis": "pending",
|
||||
"design": "pending",
|
||||
"red_team": "pending",
|
||||
"decomposition": "pending",
|
||||
"environment": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [],
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
**Выход:** готовая `.agent/` + checkpoints.json с metaagent_version и config.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 1: ANALYSE
|
||||
|
||||
**Вход:** целевой репозиторий, `.agent/metaagent-request.md` (или auto-generated), checkpoints.json (analysis: pending, config: from INIT).
|
||||
|
||||
**Протокол:** `PROTOCOLS/01_ANALYSIS.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- Прочитать config из checkpoints.json (уже получен на INIT через 00_CONFIG)
|
||||
- Если config отсутствует — применить default config (depth=4) как fallback
|
||||
- Выполнить анализ репозитория по протоколу (определяет тип проекта)
|
||||
- Записать результат в `.agent/analysis-report.md`
|
||||
- Обновить checkpoints.json: `phases.analysis = "completed"`, `project_type = "existing" | "greenfield" | "scaffold"`
|
||||
|
||||
**Выход:** `.agent/analysis-report.md`
|
||||
|
||||
**Ветвление:**
|
||||
- `project_type = "greenfield"` или `"scaffold"` → далее фаза DESIGN
|
||||
- `project_type = "existing"` → DESIGN пропускается, сразу DECOMPOSITION
|
||||
|
||||
---
|
||||
|
||||
## Фаза 2: DESIGN (условная)
|
||||
|
||||
**Вход:** analysis-report.md, checkpoints.json (analysis: completed, project_type: greenfield/scaffold).
|
||||
|
||||
**Протокол:** `PROTOCOLS/02_DESIGN.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- Спроектировать архитектуру, модули, данные, интерфейсы
|
||||
- Если config.design.alternative_arch: описать альтернативную архитектуру
|
||||
- Если config.design.adr: создать ADR для каждого ключевого решения → `.agent/layer-1/adr/`
|
||||
- Если config.risk_register: создать `.agent/layer-1/risk-register.md`
|
||||
- Записать результат в `.agent/design-report.md`
|
||||
- Обновить checkpoints.json: `phases.design = "completed"`
|
||||
|
||||
**Ветвление:**
|
||||
- Если config.red_team = yes → следующая фаза RED_TEAM
|
||||
- Иначе → сразу DECOMPOSITION
|
||||
|
||||
**Выход:** `.agent/design-report.md`, опционально `.agent/layer-1/adr/*.md`, `.agent/layer-1/risk-register.md`
|
||||
|
||||
---
|
||||
|
||||
## Фаза 2b: RED_TEAM (опциональная)
|
||||
|
||||
**Вход:** design-report.md, ADR (опционально), checkpoints.json (design: completed).
|
||||
|
||||
**Протокол:** `PROTOCOLS/02b_REDTEAM.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- Выполнить Red Team Review по протоколу
|
||||
- Записать результат в `.agent/layer-1/red-team-report.md`
|
||||
- Дополнить risk-register.md (если существует)
|
||||
- Если найдены критические проблемы — исправить design-report
|
||||
- Обновить checkpoints.json: `phases.red_team = "completed"`
|
||||
|
||||
**Выход:** `.agent/layer-1/red-team-report.md`
|
||||
|
||||
---
|
||||
|
||||
## Фаза 3: DECOMPOSITION
|
||||
|
||||
**Вход:** analysis-report.md + design-report.md (опционально) + ADR (опционально) + checkpoints.json.
|
||||
|
||||
**Протокол:** `PROTOCOLS/03_DECOMPOSITION.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- Разбить цель (и дизайн) на атомарные задачи
|
||||
- Если config.decomposition.invariant_tests: создать задачи-инварианты для каждого ADR
|
||||
- Записать манифест в `.agent/task-manifest.json` и `.agent/task-manifest.md`
|
||||
- Обновить checkpoints.json: `phases.decomposition = "completed"`, заполнить `tasks`
|
||||
|
||||
**Выход:** `.agent/task-manifest.json`, `.agent/task-manifest.md`
|
||||
|
||||
---
|
||||
|
||||
## Фаза 4: SETUP
|
||||
|
||||
**Вход:** analysis-report.md, design-report.md (опционально), task-manifest.json, checkpoints.json (decomposition: completed).
|
||||
|
||||
**Протокол:** `PROTOCOLS/04_ENVIRONMENT_SETUP.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- Выполнить настройку окружения по протоколу (ветка A для existing, ветка B для greenfield)
|
||||
- Записать результат проверки в `.agent/baseline-test-report.log` и `.agent/setup-report.log`
|
||||
- Обновить checkpoints.json: `phases.environment = "completed"`
|
||||
|
||||
**Выход:** рабочее окружение + `.agent/baseline-test-report.log`
|
||||
|
||||
---
|
||||
|
||||
## Фаза 5: CHECKPOINT (сквозная)
|
||||
|
||||
**Вход:** любая фаза.
|
||||
|
||||
**Протокол:** обновлять checkpoints.json после каждого значимого шага.
|
||||
|
||||
**Архивирование перед сохранением чекпоинта:**
|
||||
- Если checkpoints.json уже существует — сохранить предыдущую версию в `.agent/archive/checkpoints/<last_updated>.json`
|
||||
|
||||
**Формат:**
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "1.1.0",
|
||||
"session_id": "<uuid>",
|
||||
"target_repo": "<path>",
|
||||
"goal": "<цель>",
|
||||
"project_type": "existing | greenfield | scaffold",
|
||||
"config": {
|
||||
"depth": 6,
|
||||
"design": { "adr": true, "alternative_arch": true },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": true },
|
||||
"handoff": { "layer_structure": true }
|
||||
},
|
||||
"phases": {
|
||||
"analysis": "completed",
|
||||
"design": "completed",
|
||||
"red_team": "skipped",
|
||||
"decomposition": "in_progress",
|
||||
"environment": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "...", "status": "completed",
|
||||
"depends_on": [], "acceptance_criteria": ["..."] },
|
||||
{ "id": "T2", "title": "...", "status": "pending",
|
||||
"depends_on": ["T1"], "acceptance_criteria": ["..."] }
|
||||
],
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
`status` может быть: `pending`, `in_progress`, `completed`, `failed`, `skipped`.
|
||||
Фаза `red_team` может быть `skipped` если config.red_team = false.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 6: HANDOFF
|
||||
|
||||
**Вход:** все предыдущие фазы completed.
|
||||
|
||||
**Протокол:** `PROTOCOLS/05_HANDOFF.md`
|
||||
|
||||
**Действия:**
|
||||
- **Прочитать `.agent/rules/project-rules.md`** — учесть пользовательские правила
|
||||
- **Архивировать завершённые задачи:**
|
||||
- Для каждой задачи со статусом `completed` в `task-manifest.json`:
|
||||
- Перенести полное описание в `.agent/archive/tasks/<id>.json`
|
||||
- Заменить в манифесте на one-liner: `{ "id": "<id>", "title": "<title>", "status": "archived" }`
|
||||
- Создать `.agent/archive/index.json` со списком архивированных задач
|
||||
- Заархивировать предыдущий `checkpoints.json` в `.agent/archive/checkpoints/`
|
||||
- Выполнить валидацию всех артефактов
|
||||
- Если config.handoff.layer_structure: организовать `.agent/` по слоям
|
||||
- Записать `.agent/handoff-summary.md` (в layer-3 при layer_structure=yes)
|
||||
- Создать `.agent/session-summary.md` (в layer-0 при layer_structure=yes)
|
||||
- Обновить checkpoints.json: `phases.handoff = "completed"`
|
||||
- Сообщить пользователю/оркестратору
|
||||
|
||||
**Выход:** `.agent/handoff-summary.md` — итоговый документ для исполнительного агента.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 7: EXIT
|
||||
|
||||
Мета-агент завершает работу. Управление переходит к исполнительному агенту.
|
||||
|
||||
---
|
||||
|
||||
## Структура .agent/
|
||||
|
||||
.agent/ всегда содержит служебную директорию `src/` с исходниками MetaAgent (см. фазу INIT).
|
||||
При layer_structure=yes артефакты сессии раскладываются по слоям layer-0..3.
|
||||
|
||||
```
|
||||
.agent/
|
||||
src/ # исходники MetaAgent (всегда)
|
||||
META_AGENT_GUIDE.md # главная инструкция
|
||||
PROTOCOLS/ # протоколы фаз
|
||||
TEMPLATES/ # шаблоны артефактов
|
||||
BOUNDARIES.md # границы
|
||||
WORKFLOW.md # примеры работы
|
||||
VERSION # версия MetaAgent
|
||||
install.sh # скрипт установки/обновления (Unix)
|
||||
install.ps1 # скрипт установки/обновления (Windows)
|
||||
rules/ # пользовательские правила (всегда)
|
||||
project-rules.md # правила проекта — читать перед каждой фазой
|
||||
archive/ # архив завершённых артефактов (создаётся при HANDOFF)
|
||||
index.json # мета-индекс архива
|
||||
tasks/ # детали завершённых задач
|
||||
checkpoints/ # исторические чекпоинты
|
||||
adr/ # заменённые ADR
|
||||
reports/ # устаревшие отчёты
|
||||
layer-0/ # ядро сессии (только при layer_structure=yes)
|
||||
checkpoints.json # всегда (ядро)
|
||||
session-summary.md # краткая сводка сессии
|
||||
layer-1/ # архитектурные решения (справочно)
|
||||
adr/
|
||||
001-технологический-стек.md
|
||||
002-архитектурный-паттерн.md
|
||||
...
|
||||
risk-register.md
|
||||
red-team-report.md
|
||||
layer-2/ # дизайн и анализ (справочно)
|
||||
analysis-report.md
|
||||
design-report.md
|
||||
layer-3/ # состояние исполнения
|
||||
handoff-summary.md
|
||||
task-manifest.json
|
||||
task-manifest.md
|
||||
baseline-test-report.log
|
||||
setup-report.log
|
||||
```
|
||||
|
||||
Исполнительный агент всегда начинает с layer-0 (checkpoints + session-summary),
|
||||
затем при необходимости обращается к layer-1 (ADR для понимания "почему"),
|
||||
layer-2 (детали дизайна), layer-3 (что было сделано).
|
||||
@@ -0,0 +1,145 @@
|
||||
# Протокол 00: Конфигурация сессии (CONFIG)
|
||||
|
||||
## Цель
|
||||
|
||||
Определить параметры сессии MetaAgent: глубину проработки, набор функций, тип проекта. Выполняется на фазе INIT.
|
||||
|
||||
## Вход
|
||||
|
||||
- `VERSION` — текущая версия MetaAgent
|
||||
- Запрос пользователя (цель)
|
||||
- Опционально: `.agent/metaagent-request.md` (в директории `.agent/` целевого репозитория)
|
||||
|
||||
## Шаги
|
||||
|
||||
### 0.1. Проверить наличие .agent/metaagent-request.md
|
||||
|
||||
Если файл существует — распарсить, провалидировать и использовать.
|
||||
Если нет — перейти к интервью (шаг 0.2).
|
||||
|
||||
### 0.2. Интервью с пользователем
|
||||
|
||||
Задать пользователю серию вопросов для сбора конфигурации.
|
||||
|
||||
**Сценарий интервью:**
|
||||
|
||||
```
|
||||
MetaAgent: .agent/metaagent-request.md не найден. Давайте настроим сессию.
|
||||
(или ответьте "default" — я выберу depth=4, light)
|
||||
|
||||
Q1: Это новый проект (greenfield) или работа с существующим кодом (existing)?
|
||||
Варианты: new / existing / scaffold / default
|
||||
|
||||
Q2: Глубина проработки?
|
||||
1-2: Scaffold — только структура, пустые модули
|
||||
3-4: Light — быстрый дизайн + задачи, без расширений (рекомендуется default)
|
||||
5-6: Standard — полный цикл с acceptance criteria
|
||||
7-8: Deep — + ADR, risk register, alternative architecture
|
||||
9-10: Maximum — + Red Team review, executable invariants
|
||||
Варианты: число 1-10 / default
|
||||
|
||||
Q3 (если глубина >= 7): Нужны ADR (Architecture Decision Records)?
|
||||
Варианты: yes / no / default
|
||||
|
||||
Q4 (если глубина >= 7): Нужен Risk Register?
|
||||
Варианты: yes / no / default
|
||||
|
||||
Q5 (если глубина >= 9): Нужен Red Team Review?
|
||||
Варианты: yes / no / default
|
||||
```
|
||||
|
||||
**Правила обработки ответов:**
|
||||
- Если пользователь ответил `default` или не ответил — применить значение по умолчанию для этого поля
|
||||
- Если пользователь ответил `new` — `project_type = greenfield`
|
||||
- Если `existing` — `project_type = existing`
|
||||
|
||||
### 0.3. Default config
|
||||
|
||||
```json
|
||||
{
|
||||
"depth": 4,
|
||||
"design": {
|
||||
"adr": false,
|
||||
"alternative_arch": false
|
||||
},
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": {
|
||||
"invariant_tests": false
|
||||
},
|
||||
"handoff": {
|
||||
"layer_structure": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Depth=4 (Light) означает:
|
||||
- ANALYSIS — полный (определение типа проекта, извлечение требований)
|
||||
- DESIGN — выполняется (если greenfield), но **без** ADR, Alternative Architecture, Risk Register
|
||||
- DECOMPOSITION — задачи с acceptance criteria, **без** invariant-тестов
|
||||
- SETUP — полный
|
||||
- HANDOFF — плоский `.agent/` (без layer-структуры)
|
||||
|
||||
### 0.4. Запись .agent/metaagent-request.md
|
||||
|
||||
Если файла не было, создать его по результатам интервью с пометкой `Auto-generated`:
|
||||
|
||||
```markdown
|
||||
# MetaAgent Request
|
||||
# Auto-generated from user interview on {{ date }}
|
||||
|
||||
## Параметры сессии
|
||||
|
||||
| Функция | Вкл | Аргументы |
|
||||
|---|---|---|
|
||||
| ANALYSIS | ✓ | — |
|
||||
| DESIGN | ✓ | adr={{ adr }}, alternative_arch={{ alt_arch }} |
|
||||
| RED_TEAM | {{ red_team }} | — |
|
||||
| RISK_REGISTER | {{ risk_register }} | — |
|
||||
| DECOMPOSITION | ✓ | invariant_tests={{ invariant_tests }} |
|
||||
| SETUP | ✓ | — |
|
||||
| HANDOFF | ✓ | layer_structure={{ layer_structure }} |
|
||||
|
||||
## Глубина проработки
|
||||
|
||||
**Значение:** {{ depth }}
|
||||
|
||||
## Цель
|
||||
|
||||
{{ goal }}
|
||||
```
|
||||
|
||||
### 0.5. Создание .agent/rules/
|
||||
|
||||
Создать директорию `.agent/rules/` в корне целевого проекта (если не существует).
|
||||
Если `.agent/rules/project-rules.md` не существует — создать из шаблона `.agent/src/TEMPLATES/project-rules.md`:
|
||||
|
||||
```markdown
|
||||
# Project Rules
|
||||
|
||||
Добавляйте сюда правила, которым агент обязан следовать во всех фазах.
|
||||
```
|
||||
|
||||
### 0.6. Валидация config
|
||||
|
||||
Проверить совместимость параметров с depth:
|
||||
|
||||
```
|
||||
depth < 3 → DESIGN пропускается (даже для greenfield)
|
||||
depth < 7 → adr=false, alternative_arch=false, risk_register=false, invariant_tests=false
|
||||
depth < 9 → red_team=false
|
||||
```
|
||||
|
||||
Если depth несовместим с включёнными функциями — понизить функции до максимума, разрешённого depth.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/metaagent-request.md` (создан или подтверждён)
|
||||
- config — словарь параметров для записи в checkpoints.json
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] `.agent/metaagent-request.md` существует (создан или найден)
|
||||
- [ ] Config содержит depth, design.*, red_team, risk_register, decomposition.*, handoff.*
|
||||
- [ ] Config совместим с depth (доп. функции отключены для малых depth)
|
||||
- [ ] При отсутствии файла — проведено интервью, файл создан
|
||||
@@ -1,128 +0,0 @@
|
||||
# Протокол 00: Инициализация (INIT)
|
||||
|
||||
## Цель
|
||||
|
||||
Подготовить `.agent/` в целевом репозитории: установить исходники MetaAgent, создать структуру директорий, инициализировать `checkpoints.json`, создать/обновить `AGENTS.md`.
|
||||
|
||||
INIT выполняется **один раз** в начале работы с проектом. Если `.agent/` уже существует и инициализирован — пропускается.
|
||||
|
||||
## Вход
|
||||
|
||||
- Целевой репозиторий (путь или текущая директория)
|
||||
- `VERSION` — текущая версия MetaAgent
|
||||
- Опционально: существующий `.agent/` (если обновление)
|
||||
|
||||
## Шаги
|
||||
|
||||
### 0.1. Определить целевой репозиторий
|
||||
|
||||
Если не указан явно — текущая рабочая директория. Если указан как URL — клонировать во временную директорию, дальше работать с копией.
|
||||
|
||||
### 0.2. Проверить существующий `.agent/`
|
||||
|
||||
Если `.agent/` существует:
|
||||
|
||||
- Прочитать `.agent/checkpoints.json` → `metaagent_version`
|
||||
- Если `metaagent_version == VERSION` → INIT уже выполнен, выйти
|
||||
- Если версия старше → запустить `install.sh --update` (Unix) или `install.ps1 -Update` (Windows) для переустановки исходников, затем выйти
|
||||
- Если `.agent/` есть, но `checkpoints.json` отсутствует → продолжить INIT (создать checkpoints)
|
||||
|
||||
Если `.agent/` не существует → продолжить INIT.
|
||||
|
||||
### 0.3. Создать структуру `.agent/`
|
||||
|
||||
Создать директории:
|
||||
|
||||
```
|
||||
.agent/
|
||||
src/ # исходники MetaAgent (копируются из METAAGENT_SRC)
|
||||
rules/
|
||||
decisions/
|
||||
tasks/
|
||||
backlog/
|
||||
context/
|
||||
requests/
|
||||
active/
|
||||
archive/
|
||||
roadmap/
|
||||
archive/
|
||||
archive/
|
||||
tasks/
|
||||
decisions/
|
||||
requests/
|
||||
checkpoints/
|
||||
```
|
||||
|
||||
### 0.4. Создать `.temp/` в корне проекта
|
||||
|
||||
Если не существует — создать `.temp/` в корне целевого репозитория. Добавить в `.gitignore` (если его нет — создать с одной строкой `.temp/`).
|
||||
|
||||
### 0.5. Скопировать исходники MetaAgent
|
||||
|
||||
Скопировать в `.agent/src/`:
|
||||
|
||||
- `GUIDE.md`
|
||||
- `BOUNDARIES.md`
|
||||
- `CHANGELOG.md`
|
||||
- `VERSION`
|
||||
- `PROTOCOLS/`
|
||||
- `COMMANDS/`
|
||||
- `TEMPLATES/`
|
||||
- `install.sh`, `install.ps1`
|
||||
|
||||
Существующие файлы в `.agent/src/` не перезаписывать (только с явным `--update`).
|
||||
|
||||
### 0.6. Создать `.agent/rules/project-rules.md`
|
||||
|
||||
Если файла нет — создать по шаблону `TEMPLATES/project-rules.md`.
|
||||
|
||||
### 0.7. Создать/обновить `AGENTS.md` в корне
|
||||
|
||||
Если `AGENTS.md` в корне проекта отсутствует — создать по `AGENTS.template.md` с подставленной версией.
|
||||
|
||||
Если существует и не относится к MetaAgent — не трогать (попросить пользователя переименовать или подтвердить перезапись).
|
||||
|
||||
### 0.8. Инициализировать `checkpoints.json`
|
||||
|
||||
Создать `.agent/checkpoints.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "3.0.0",
|
||||
"session_id": "<uuid>",
|
||||
"target_repo": "<путь>",
|
||||
"goal": null,
|
||||
"project_type": null,
|
||||
"phases": {
|
||||
"init": "completed",
|
||||
"analyse": "pending",
|
||||
"roadmap": "pending",
|
||||
"design": "pending",
|
||||
"decomposition": "pending",
|
||||
"execution": "pending",
|
||||
"metastate": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [],
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
Поля `goal` и `project_type` остаются `null` до фазы ANALYSE (goal может быть задан пользователем заранее — тогда заполнить сразу).
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/` с полной структурой
|
||||
- `.agent/src/` с актуальными исходниками MetaAgent
|
||||
- `.agent/rules/project-rules.md`
|
||||
- `.agent/checkpoints.json` со `session_id` и `phases.init = "completed"`
|
||||
- `AGENTS.md` в корне проекта
|
||||
- `.temp/` в корне + `.gitignore` обновлён
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] `.agent/` содержит все обязательные директории
|
||||
- [ ] `.agent/src/` содержит GUIDE.md, PROTOCOLS/, COMMANDS/, TEMPLATES/, VERSION
|
||||
- [ ] `.agent/checkpoints.json` валиден (JSON parse)
|
||||
- [ ] `AGENTS.md` присутствует в корне
|
||||
- [ ] `.temp/` существует и в `.gitignore`
|
||||
@@ -0,0 +1,124 @@
|
||||
# Протокол 00b: Миграция артефактов (MIGRATE)
|
||||
|
||||
## Цель
|
||||
|
||||
Обеспечить совместимость артефактов `.agent/` при изменении версии MetaAgent.
|
||||
Позволяет обновлять проекты, созданные старой версией, без потери данных.
|
||||
|
||||
## Вход
|
||||
|
||||
- `VERSION` — текущая версия MetaAgent
|
||||
- `.agent/checkpoints.json` — артефакты целевого проекта
|
||||
- `.agent/` — остальные артефакты
|
||||
|
||||
## Шаги
|
||||
|
||||
### M1. Определить версию артефактов
|
||||
|
||||
Прочитать `.agent/checkpoints.json`:
|
||||
|
||||
```python
|
||||
stored_version = checkpoints.get("metaagent_version", None)
|
||||
current_version = read("VERSION").strip()
|
||||
```
|
||||
|
||||
- Если `metaagent_version` отсутствует → артефакт создан **v0.x** (доверсионный)
|
||||
- Если `metaagent_version` == `current_version` → пропустить миграцию
|
||||
- Если `metaagent_version` < `current_version` → требуется миграция
|
||||
|
||||
### M2. Сравнение версий (SemVer)
|
||||
|
||||
Версии сравниваются по семантическому версионированию (`MAJOR.MINOR.PATCH`).
|
||||
|
||||
```python
|
||||
def needs_migration(stored, current):
|
||||
if stored is None:
|
||||
return True
|
||||
return parse_semver(stored) < parse_semver(current)
|
||||
```
|
||||
|
||||
### M3. Матрица миграций
|
||||
|
||||
Каждая строка — набор шагов для перехода с одной версии на следующую.
|
||||
|
||||
| Из версии | В версию | Шаги миграции |
|
||||
|---|---|---|
|
||||
| v0.x (нет поля) | v1.0.0 | M3.1 — M3.4 |
|
||||
| v1.0.0 | v1.1.0 | M3.5 — M3.6 (см. ниже) |
|
||||
|
||||
### M4. Шаги миграции v0.x → v1.0.0
|
||||
|
||||
... (шаги миграции остаются без изменений)
|
||||
|
||||
### M5. Шаги миграции v1.0.0 → v1.1.0
|
||||
|
||||
M3.5: Создать `.agent/rules/` с шаблоном `project-rules.md` (если не существует).
|
||||
M3.6: Создать `.agent/archive/` (если не существует).
|
||||
|
||||
#### M3.1. Добавить metaagent_version
|
||||
|
||||
Записать в checkpoints.json:
|
||||
|
||||
```json
|
||||
"metaagent_version": "1.1.0"
|
||||
```
|
||||
|
||||
#### M3.2. Добавить config (default)
|
||||
|
||||
Если поля `config` нет в checkpoints.json — добавить config по умолчанию:
|
||||
|
||||
```json
|
||||
"config": {
|
||||
"depth": 4,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
}
|
||||
```
|
||||
|
||||
#### M3.3. Добавить фазу red_team
|
||||
|
||||
Если в `phases` нет ключа `red_team`:
|
||||
|
||||
```json
|
||||
"red_team": "skipped"
|
||||
```
|
||||
|
||||
#### M3.4. Создать layer-1/ (опционально, только если config.handoff.layer_structure)
|
||||
|
||||
Если включена layer_structure:
|
||||
|
||||
```bash
|
||||
mkdir -p .agent/layer-1/adr
|
||||
touch .agent/layer-1/adr/.gitkeep
|
||||
```
|
||||
|
||||
Если `risk-register.md` уже существует на верхнем уровне — переместить в `.agent/layer-1/risk-register.md`.
|
||||
|
||||
### M4. После миграции — резюме
|
||||
|
||||
Записать в `.agent/migration-report.log`:
|
||||
|
||||
```
|
||||
[MIGRATE] {{ timestamp }}
|
||||
From: {{ from_version }}
|
||||
To: {{ to_version }}
|
||||
Steps applied: {{ step_list }}
|
||||
Status: OK
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- Обновлённый `.agent/checkpoints.json` (metaagent_version + config)
|
||||
- Опционально: `.agent/layer-1/` структура
|
||||
- `.agent/migration-report.log`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] metaagent_version в checkpoints.json == текущей версии из VERSION
|
||||
- [ ] config присутствует в checkpoints.json
|
||||
- [ ] phases.red_team присутствует (skipped, если не нужен)
|
||||
- [ ] migration-report.log создан
|
||||
- [ ] Все старые данные сохранены (ничего не удалено)
|
||||
@@ -1,95 +0,0 @@
|
||||
# Протокол 01: Анализ репозитория (ANALYSE)
|
||||
|
||||
## Цель
|
||||
|
||||
Составить полную картину целевого репозитория: тип проекта, стек, архитектура, конвенции, состояние тестов. Создать начальный слепок проекта.
|
||||
|
||||
## Вход
|
||||
|
||||
- Целевой репозиторий
|
||||
- `.agent/checkpoints.json` (фаза analyse: pending)
|
||||
- `.agent/rules/project-rules.md` — прочитать первым
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1.1. Прочитать правила проекта
|
||||
|
||||
Прежде чем что-либо делать — прочитать `.agent/rules/project-rules.md`. Если есть правила, применить их к фазе.
|
||||
|
||||
### 1.2. Определить тип проекта
|
||||
|
||||
Просканировать корень репозитория:
|
||||
|
||||
- **`existing`** — есть исходный код, тесты, система сборки (`.py`, `.js`, `.ts`, `.rs`, `.go` и т.д. помимо конфигов и README).
|
||||
- **`greenfield`** — пусто или только README/LICENSE/.gitignore.
|
||||
- **`scaffold`** — есть базовая структура (`pyproject.toml`/`package.json`), но нет значимого кода.
|
||||
|
||||
Записать тип в `checkpoints.json → project_type`.
|
||||
|
||||
### 1.3. Сканировать проект
|
||||
|
||||
Для `existing` / `scaffold` собрать:
|
||||
|
||||
- **README** — описание, инструкции по сборке/тестам.
|
||||
- **Лицензия** — какой LICENSE.
|
||||
- **CI/CD** — `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`, `Makefile`.
|
||||
- **Стек** — язык, фреймворк, БД, тестовый раннер, пакетный менеджер, линтер.
|
||||
- **Структура** — `tree -L 3` (не более 3 уровней).
|
||||
- **Архитектурный паттерн** — MVC, модульный монолит, микросервисы, слоистая.
|
||||
- **Ключевые модули/пакеты** — список с краткой ответственностью.
|
||||
- **Конвенции** — стиль, именование, обработка ошибок, логирование.
|
||||
- **Тесты** — где лежат, как запускаются, текущее состояние (запустить).
|
||||
- **Сборка** — выполняется ли проект.
|
||||
|
||||
Для `greenfield` — извлечь требования из README:
|
||||
|
||||
- Функциональные требования (user stories, сценарии).
|
||||
- Нефункциональные (стек, производительность, безопасность).
|
||||
- Бизнес-контекст (зачем, для кого).
|
||||
- Сомнительные / неясные требования (вопросы пользователю).
|
||||
|
||||
### 1.4. Создать analysis-report
|
||||
|
||||
Записать `.agent/context/analysis-report.md` по шаблону `TEMPLATES/analysis-report.md`. Заполнить соответствующие секции.
|
||||
|
||||
### 1.5. Создать начальный project-state
|
||||
|
||||
Создать `.agent/context/project-state.md` по шаблону `TEMPLATES/project-state.md`. Это **начальный** слепок. В дальнейшем обновляется в фазе METASTATE.
|
||||
|
||||
Заполнить:
|
||||
- Тип проекта
|
||||
- Краткая архитектура (из шага 1.3)
|
||||
- Ключевые модули и их статус
|
||||
- Tech stack
|
||||
- Статус тестов
|
||||
|
||||
### 1.6. Обновить checkpoints
|
||||
|
||||
```json
|
||||
{
|
||||
"phases": { "analyse": "completed" },
|
||||
"project_type": "existing | greenfield | scaffold",
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
## Ветвление
|
||||
|
||||
| project_type | Следующая фаза |
|
||||
|---|---|
|
||||
| `existing` | ROADMAP → DECOMPOSITION (DESIGN пропускается) |
|
||||
| `greenfield` | ROADMAP → DESIGN → DECOMPOSITION |
|
||||
| `scaffold` | ROADMAP → DESIGN → DECOMPOSITION |
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/context/analysis-report.md`
|
||||
- `.agent/context/project-state.md` (начальный)
|
||||
- Обновлённый `checkpoints.json`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Тип проекта определён
|
||||
- [ ] `analysis-report.md` содержит все соответствующие секции
|
||||
- [ ] `project-state.md` создан с начальным слепком
|
||||
- [ ] `checkpoints.json` обновлён
|
||||
@@ -0,0 +1,139 @@
|
||||
# Протокол 01: Анализ репозитория (ANALYSIS)
|
||||
|
||||
## Цель
|
||||
|
||||
Составить полную картину целевого репозитория: тип проекта, архитектура, стек, конвенции, состояние тестов, требования.
|
||||
|
||||
## Вход
|
||||
|
||||
- Целевой репозиторий (локальная копия)
|
||||
- `.agent/metaagent-request.md` (конфигурация сессии: глубина, функции) — или auto-generated
|
||||
- `.agent/checkpoints.json` (фаза analysis: pending)
|
||||
|
||||
## Шаги
|
||||
|
||||
### 0.0. Чтение конфигурации сессии
|
||||
|
||||
Прочитать config из checkpoints.json (установлен на фазе INIT через `00_CONFIG.md`).
|
||||
|
||||
Если config отсутствует или неполный — применить default:
|
||||
|
||||
```json
|
||||
{
|
||||
"depth": 4,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
}
|
||||
```
|
||||
|
||||
Записать (или подтвердить) конфигурацию в checkpoints.json:
|
||||
```json
|
||||
"config": {
|
||||
"depth": 6,
|
||||
"design": { "adr": true, "alternative_arch": true },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": true },
|
||||
"handoff": { "layer_structure": true }
|
||||
}
|
||||
```
|
||||
|
||||
Если `.agent/metaagent-request.md` не найден — использовать значения по умолчанию (depth=6, все базовые функции=true, расширенные=false).
|
||||
|
||||
### 1.0. Определение типа проекта
|
||||
|
||||
Просканировать корень репозитория и определить:
|
||||
|
||||
- **`existing`** — есть исходный код, тесты, система сборки (файлы `.py`, `.js`, `.ts`, `.rs`, `.go` и т.д. помимо конфигов и README)
|
||||
- **`greenfield`** — репозиторий пуст или содержит только README, LICENSE, .gitignore
|
||||
- **`scaffold`** — есть базовая структура (pyproject.toml/package.json), но нет значимого кода
|
||||
|
||||
Записать тип в analysis-report.md.
|
||||
|
||||
**Правило:** если проект `existing` — разделы 1.1–1.6 выполняются полностью. Если `greenfield` — разделы 1.2–1.5 заменяются на 1.7 (извлечение требований из README).
|
||||
|
||||
### 1.1. Общая информация
|
||||
|
||||
Прочитать и зафиксировать:
|
||||
- **README** — описание проекта, how to build/test/run
|
||||
- **Лицензия** — какой LICENSE
|
||||
- **CI/CD** — `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`, `Makefile` и т.д.
|
||||
- **Главные точки входа** — `main.py`, `index.js`, `cmd/` и т.д.
|
||||
- **Система сборки** — `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `CMakeLists.txt`
|
||||
|
||||
### 1.2. Стек технологий (только для existing/scaffold)
|
||||
|
||||
Определить:
|
||||
- **Язык(и)** — Python, TypeScript, Go, Rust и т.д.
|
||||
- **Фреймворк** — FastAPI, Next.js, React, Actix и т.д.
|
||||
- **База данных** — PostgreSQL, SQLite, MongoDB и т.д.
|
||||
- **Тестовый раннер** — pytest, jest, vitest, go test
|
||||
- **Пакетный менеджер** — pip/poetry, npm/yarn/pnpm, cargo, go modules
|
||||
- **Линтер/форматтер** — ruff, eslint, prettier, rustfmt, gofmt
|
||||
|
||||
### 1.3. Архитектура (только для existing/scaffold)
|
||||
|
||||
- **Структура директорий** — записать схему (можно `tree /F`, но не более 3 уровней глубины)
|
||||
- **Архитектурный паттерн** — MVC, Clean Architecture, модульный монолит, микросервисы
|
||||
- **Ключевые модули/пакеты** — перечислить с кратким описанием
|
||||
- **Внешние зависимости** — основные библиотеки
|
||||
|
||||
### 1.4. Конвенции кода (только для existing/scaffold)
|
||||
|
||||
- **Стиль кода** — судя по линтеру и примерам: именование, импорты, типизация
|
||||
- **Паттерны** — как организованы роуты, хендлеры, модели, тесты
|
||||
- **Обработка ошибок** — как принято обрабатывать ошибки в проекте
|
||||
- **Логирование** — используется ли логгер, какой уровень
|
||||
|
||||
### 1.5. Тесты (только для existing/scaffold)
|
||||
|
||||
- **Какие тесты есть** — unit, integration, e2e
|
||||
- **Где лежат** — `tests/`, `__tests__/`, рядом с модулями
|
||||
- **Запуск** — команда для запуска всех тестов
|
||||
- **Текущее состояние** — запустить тесты, записать результат (сколько всего, сколько пройдено/упало)
|
||||
- **Покрытие** — есть ли метрики покрытия
|
||||
|
||||
### 1.6. Базовая проверка (только для existing/scaffold)
|
||||
|
||||
- **Собирается ли проект?** — запустить сборку
|
||||
- **Запускается ли проект?** — если возможно, проверить старт
|
||||
- **Чистый ли git status?** — нет ли незакоммиченных изменений
|
||||
|
||||
### 1.7. Извлечение требований (только для greenfield/scaffold)
|
||||
|
||||
Если README содержит описание будущего проекта — извлечь и структурировать:
|
||||
|
||||
**Функциональные требования:**
|
||||
- Пользовательские истории (user stories)
|
||||
- Основные сценарии использования
|
||||
- Входные/выходные данные системы
|
||||
|
||||
**Нефункциональные требования:**
|
||||
- Технологические предпочтения (язык, фреймворк, БД)
|
||||
- Требования к производительности, безопасности
|
||||
- Ограничения (сроки, платформа, окружение)
|
||||
|
||||
**Бизнес-контекст:**
|
||||
- Цель системы (зачем)
|
||||
- Целевая аудитория
|
||||
- Ключевые метрики успеха
|
||||
|
||||
**Сомнительные/неясные требования:**
|
||||
- Вопросы, которые нужно задать пользователю перед проектированием
|
||||
- Противоречия в README
|
||||
|
||||
## Выход
|
||||
|
||||
`.agent/analysis-report.md` по шаблону `TEMPLATES/analysis-report.md`.
|
||||
|
||||
Обновить checkpoints.json: `phases.analysis = "completed"`. Если проект `greenfield`, также установить `project_type = "greenfield"`.
|
||||
|
||||
## Критерии завершения фазы
|
||||
|
||||
- [ ] Тип проекта определён (existing / greenfield / scaffold)
|
||||
- [ ] Все соответствующие разделы (1.1–1.7) выполнены
|
||||
- [ ] `.agent/analysis-report.md` создан и заполнен
|
||||
- [ ] checkpoints.json обновлён
|
||||
@@ -0,0 +1,173 @@
|
||||
# Протокол 02: Архитектурное проектирование (DESIGN)
|
||||
|
||||
## Цель
|
||||
|
||||
Спроектировать архитектуру, модули, данные и интерфейсы для greenfield/scaffold-проекта на основе требований из analysis-report.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/analysis-report.md` (project_type: greenfield или scaffold)
|
||||
- `.agent/metaagent-request.md` (конфигурация сессии: adr, alternative_arch, risk_register)
|
||||
- `.agent/checkpoints.json` (фаза design: pending)
|
||||
|
||||
## Правила
|
||||
|
||||
1. **Реалистичность** — архитектура должна быть реализуема исполнительным агентом за 1 сессию (до 10 задач)
|
||||
2. **Документируемость** — каждый модуль, модель и интерфейс описывается в design-report.md
|
||||
3. **Тестируемость** — каждый компонент проектируется с учётом того, как его тестировать
|
||||
4. **Итеративность** — первая версия должна быть минимально рабочей (MVP), расширения — отдельными задачами
|
||||
|
||||
## Шаги
|
||||
|
||||
### 2.1. Технологический стек
|
||||
|
||||
Если стек не указан в README — предложить обоснованный выбор. Если указан — зафиксировать.
|
||||
|
||||
Для каждого компонента указать:
|
||||
- Язык и версия
|
||||
- Фреймворк / библиотека
|
||||
- База данных (движок, схема)
|
||||
- Инфраструктура (Docker, CI/CD, хостинг)
|
||||
|
||||
### 2.2. High-level архитектура
|
||||
|
||||
Описать общую структуру системы:
|
||||
|
||||
- **Архитектурный паттерн** — монолит, модульный монолит, микросервисы, слоистая, луковая и т.д.
|
||||
- **Компоненты и их ответственность** — что делает каждый модуль/сервис
|
||||
- **Схема взаимодействия** — текстовое описание потоков данных
|
||||
|
||||
Формат (text diagram):
|
||||
|
||||
```
|
||||
[Client] → HTTP → [API Gateway] → [Auth Service]
|
||||
↓
|
||||
[Core Service] → [Database]
|
||||
↓
|
||||
[External API] → [3rd Party]
|
||||
```
|
||||
|
||||
### 2.3. Модули проекта
|
||||
|
||||
Разбить систему на модули/пакеты. Для каждого:
|
||||
|
||||
| Поле | Описание |
|
||||
|---|---|
|
||||
| **Имя модуля** | `app/services/cashflow.py` |
|
||||
| **Ответственность** | Что делает |
|
||||
| **Ключевые классы/функции** | Только сигнатуры (без реализации) |
|
||||
| **Зависимости** | Какие модули нужны этому |
|
||||
| **Контракт** | Что экспортирует/предоставляет |
|
||||
|
||||
### 2.4. Модели данных
|
||||
|
||||
Описать основные сущности, их поля и связи:
|
||||
|
||||
```json
|
||||
{
|
||||
"entity": "Transaction",
|
||||
"fields": [
|
||||
{"name": "id", "type": "UUID", "pk": true},
|
||||
{"name": "amount", "type": "Decimal"},
|
||||
{"name": "date", "type": "datetime"},
|
||||
{"name": "category_id", "type": "UUID", "fk": "Category"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Если используется ORM — указать аннотации/декораторы.
|
||||
Если БД — схему таблиц, индексы, ключи.
|
||||
|
||||
### 2.5. API интерфейсы
|
||||
|
||||
Если проектируется API — описать эндпоинты:
|
||||
|
||||
| Метод | Путь | Описание | Request | Response | Статусы |
|
||||
|---|---|---|---|---|---|
|
||||
| GET | /transactions | Список транзакций | ?page, ?limit | [Transaction] | 200 |
|
||||
| POST | /transactions | Создать транзакцию | CreateTransactionDTO | Transaction | 201, 400 |
|
||||
|
||||
Если GUI — описать ключевые страницы/экраны.
|
||||
Если CLI — описать команды.
|
||||
|
||||
### 2.6. Обработка ошибок
|
||||
|
||||
- Стратегия ошибок: исключения, Result-тип, коды ошибок
|
||||
- Формат ошибок в API: `{ "error": "...", "code": "...", "details": {} }`
|
||||
- Логирование: какой уровень для каких событий
|
||||
|
||||
### 2.7. Стратегия тестирования
|
||||
|
||||
- Какие тесты нужны (unit, integration, e2e)
|
||||
- Как изолировать зависимости (mocks, fakes, testcontainers)
|
||||
- Команда запуска тестов
|
||||
|
||||
### 2.8. Alternative Architecture (если config.alternative_arch = yes)
|
||||
|
||||
Описать **минимум одну принципиально иную архитектуру** и причину отказа:
|
||||
|
||||
| Критерий | Выбранная архитектура | Альтернатива |
|
||||
|---|---|---|
|
||||
| Название | Модульный монолит | Микросервисы / Событийная / и т.д. |
|
||||
| Сложность реализации | Низкая | Высокая (3+ сервиса) |
|
||||
| Масштабирование | Вертикальное | Горизонтальное |
|
||||
| Почему не выбрана | — | Избыточно для MVP |
|
||||
|
||||
Это снижает риск архитектурной инерции: решение становится осознанным, а не единственным возможным.
|
||||
|
||||
### 2.9. ADR (если config.adr = yes)
|
||||
|
||||
Для каждого ключевого архитектурного решения (стек, БД, паттерн, структура модулей) создать отдельный ADR-файл:
|
||||
|
||||
```
|
||||
.agent/layer-1/adr/001-технологический-стек.md
|
||||
.agent/layer-1/adr/002-модульный-монолит.md
|
||||
.agent/layer-1/adr/003-json-хранение.md
|
||||
```
|
||||
|
||||
Формат — по шаблону `TEMPLATES/adr-NNNN.md`.
|
||||
|
||||
### 2.10. Risk Register (если config.risk_register = yes)
|
||||
|
||||
Создать `.agent/layer-1/risk-register.md` по шаблону `TEMPLATES/risk-register.md`:
|
||||
|
||||
| # | Assumption | Impact if wrong | Mitigation | Review trigger |
|
||||
|---|---|---|---|---|
|
||||
|
||||
Задокументировать **неявные допущения**, на которых держится архитектура. Это даёт future-агентам знать, что можно пересматривать в первую очередь.
|
||||
|
||||
### 2.11. Группировка в задачи
|
||||
|
||||
На основе спроектированных модулей и моделей предварительно наметить группировку в задачи (по модулям). Это будет входом для DECOMPOSITION.
|
||||
|
||||
```
|
||||
T1: Инициализация проекта + зависимости
|
||||
T2: Модель данных (сущности, миграции)
|
||||
T3: Cashflow Service (core logic)
|
||||
T4: API endpoints
|
||||
...и т.д.
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/design-report.md` по шаблону `TEMPLATES/design-report.md`
|
||||
- `.agent/layer-1/adr/*.md` (если adr=yes)
|
||||
- `.agent/layer-1/risk-register.md` (если risk_register=yes)
|
||||
- Предварительная группировка задач (для передачи в DECOMPOSITION)
|
||||
|
||||
Обновить checkpoints.json: `phases.design = "completed"`.
|
||||
|
||||
## Критерии завершения фазы
|
||||
|
||||
- [ ] Технологический стек определён
|
||||
- [ ] High-level архитектура описана
|
||||
- [ ] Модули и их ответственность описаны
|
||||
- [ ] Модели данных спроектированы
|
||||
- [ ] API/интерфейсы описаны (если применимо)
|
||||
- [ ] Стратегия тестирования определена
|
||||
- [ ] Alternative Architecture описана (если config требует)
|
||||
- [ ] ADR созданы (если config требует)
|
||||
- [ ] Risk Register создан (если config требует)
|
||||
- [ ] Задачи предварительно сгруппированы
|
||||
- [ ] `.agent/design-report.md` создан
|
||||
- [ ] checkpoints.json обновлён
|
||||
@@ -1,106 +0,0 @@
|
||||
# Протокол 02: Дорожная карта (ROADMAP)
|
||||
|
||||
## Цель
|
||||
|
||||
Собрать все источники задач для проекта, приоритизировать их и записать в `.agent/roadmap/sources.md`. ROADMAP — мост между видением проекта и конкретными задачами в манифесте.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/context/analysis-report.md`
|
||||
- Цель сессии (goal из `checkpoints.json` или запрос пользователя)
|
||||
- `FUTURE/` — директория долгосрочных планов (если существует)
|
||||
- `.agent/decisions/index.json` — принятые ADR (опционально)
|
||||
- `.agent/checkpoints.json` (фаза roadmap: pending)
|
||||
- `.agent/rules/project-rules.md` — прочитать первым
|
||||
|
||||
## Шаги
|
||||
|
||||
### 2.1. Прочитать правила проекта
|
||||
|
||||
Прочитать `.agent/rules/project-rules.md`, применить к фазе.
|
||||
|
||||
### 2.2. Сканировать FUTURE/
|
||||
|
||||
Если в корне проекта существует `FUTURE/`:
|
||||
|
||||
- Прочитать все `.md` файлы.
|
||||
- Зафиксировать: название, статус (active/archived), приоритет, зависимости.
|
||||
- Какие планы реализованы, какие ожидают.
|
||||
|
||||
### 2.3. Сканировать ADR
|
||||
|
||||
Если существует `.agent/decisions/index.json`:
|
||||
|
||||
- Прочитать индекс ADR.
|
||||
- Определить, какие решения требуют реализации (не все ADR технические).
|
||||
- Для каждого — сформулировать задачу-кандидат.
|
||||
|
||||
### 2.4. Собрать внешние источники
|
||||
|
||||
- Запрос пользователя (goal).
|
||||
- issues / feedback (если доступны).
|
||||
- Tech debt, выявленный в ANALYSE.
|
||||
|
||||
### 2.5. Приоритизировать
|
||||
|
||||
Присвоить каждой задаче приоритет:
|
||||
|
||||
| Приоритет | Описание |
|
||||
|---|---|
|
||||
| **P0** | Критично, делать следующим |
|
||||
| **P1** | Важно, сделать скоро |
|
||||
| **P2** | Желательно |
|
||||
| **P3** | Долгосрочно / отложено |
|
||||
|
||||
Правила:
|
||||
|
||||
- Блокирующие зависимости поднимают приоритет.
|
||||
- User-запросы получают P0-P1 по умолчанию.
|
||||
- ADR-задачи получают приоритет по срочности решения.
|
||||
|
||||
### 2.6. Создать sources.md
|
||||
|
||||
Создать `.agent/roadmap/sources.md` по шаблону `TEMPLATES/roadmap-sources.md`:
|
||||
|
||||
```markdown
|
||||
# Roadmap Sources
|
||||
|
||||
## FUTURE Plans
|
||||
| План | Приоритет | Статус |
|
||||
|------|-----------|--------|
|
||||
|
||||
## ADR-Derived Tasks
|
||||
| ADR | Задача | Приоритет |
|
||||
|-----|--------|-----------|
|
||||
|
||||
## User Requests
|
||||
| Запрос | Приоритет | Источник |
|
||||
|--------|-----------|----------|
|
||||
|
||||
## Agent-Identified Improvements
|
||||
| Наблюдение | Задача | Приоритет |
|
||||
|------------|--------|-----------|
|
||||
|
||||
## Consolidated Priority Queue
|
||||
1. task (origin) — P0
|
||||
```
|
||||
|
||||
### 2.7. Архивация
|
||||
|
||||
Если в `.agent/roadmap/archive/` есть предыдущие версии — оставить справочно.
|
||||
|
||||
Если планы из `FUTURE/*` больше не актуальны — переместить в `FUTURE/archive/`.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/roadmap/sources.md`
|
||||
- Возможно обновлённый `FUTURE/`
|
||||
- `checkpoints.json: phases.roadmap = "completed"`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Все источники просканированы (FUTURE, ADR, user, agent)
|
||||
- [ ] `sources.md` создан с приоритетами P0-P3
|
||||
- [ ] Каждая задача имеет origin-ссылку на источник
|
||||
- [ ] Устаревшие планы перемещены в archive
|
||||
- [ ] `checkpoints.json` обновлён
|
||||
@@ -0,0 +1,80 @@
|
||||
# Протокол 02b: Red Team Review (опционально)
|
||||
|
||||
## Цель
|
||||
|
||||
Преднамеренно попытаться разрушить спроектированную архитектуру, чтобы найти скрытые проблемы до начала реализации.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/design-report.md`
|
||||
- `.agent/layer-1/adr/*.md` (если созданы)
|
||||
- `.agent/metaagent-request.md` (глубина проработки >= 9)
|
||||
|
||||
## Когда выполняется
|
||||
|
||||
Только если `config.red_team = yes` (глубина 9-10). Выполняется **после** DESIGN, **до** DECOMPOSITION.
|
||||
|
||||
## Шаги
|
||||
|
||||
### RT1. Поиск скрытых зависимостей
|
||||
|
||||
Проверить каждый модуль на наличие неявных связей:
|
||||
|
||||
- Есть ли циклические зависимости между модулями?
|
||||
- Есть ли модуль, который знает слишком много о других?
|
||||
- Есть ли скрытый vendor lock-in (БД, облачный провайдер, внешний API)?
|
||||
|
||||
### RT2. Точки отказа
|
||||
|
||||
Для каждого внешнего интерфейса (API, БД, файловая система):
|
||||
|
||||
- Что произойдёт при отказе компонента?
|
||||
- Есть ли fallback?
|
||||
- Что произойдёт при невалидных входных данных?
|
||||
|
||||
### RT3. Масштабирование
|
||||
|
||||
Оценить поведение системы при:
|
||||
|
||||
- 10x рост данных
|
||||
- 100x рост данных
|
||||
- Добавлении нового пользователя / клиента
|
||||
|
||||
### RT4. Security (если применимо)
|
||||
|
||||
- Какие данные передаются по сети?
|
||||
- Есть ли аутентификация?
|
||||
- Хранятся ли секреты в коде?
|
||||
|
||||
### RT5. Consistency
|
||||
|
||||
Проверить design-report и ADR на противоречия:
|
||||
|
||||
- Одна сущность описана по-разному в двух местах?
|
||||
- API-контракт не соответствует модели данных?
|
||||
- Технологический стек противоречит нефункциональным требованиям?
|
||||
|
||||
## Выход
|
||||
|
||||
`.agent/layer-1/red-team-report.md` с секциями:
|
||||
|
||||
```
|
||||
## Найденные проблемы
|
||||
|
||||
| # | Проблема | Серьёзность | Рекомендация |
|
||||
|---|---|---|---|
|
||||
|
||||
## Отклонённые атаки (что пытались сломать — но не сломалось)
|
||||
|
||||
| # | Гипотеза | Почему не подтвердилась |
|
||||
|---|---|---|
|
||||
```
|
||||
|
||||
Обновить risk-register.md (если существует) новыми рисками.
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Все 5 секций (RT1-RT5) проверены
|
||||
- [ ] Найденные проблемы записаны в red-team-report.md
|
||||
- [ ] Если найдены критические проблемы — design-report должен быть исправлен
|
||||
- [ ] Risk Register дополнен (если существует)
|
||||
@@ -0,0 +1,133 @@
|
||||
# Протокол 03: Декомпозиция задач (DECOMPOSITION)
|
||||
|
||||
## Цель
|
||||
|
||||
Разбить цель пользователя (и архитектурный план, если есть) на атомарные, независимо выполнимые задачи и записать их в манифест.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/analysis-report.md`
|
||||
- `.agent/design-report.md` (опционально — для greenfield/scaffold)
|
||||
- `.agent/layer-1/adr/*.md` (опционально)
|
||||
- `.agent/layer-1/risk-register.md` (опционально)
|
||||
- `.agent/metaagent-request.md` (конфигурация сессии)
|
||||
- Цель пользователя (из checkpoints.json)
|
||||
- `.agent/checkpoints.json` (фаза decomposition: pending)
|
||||
|
||||
## Правила декомпозиции
|
||||
|
||||
### 3.1. Принципы
|
||||
|
||||
1. **Атомарность** — одна задача = одна логическая единица работы, которую можно выполнить и проверить за один подход
|
||||
2. **Независимость (макс.)** — минимизировать зависимости между задачами
|
||||
3. **Тестируемость** — каждая задача имеет измеримые acceptance criteria
|
||||
4. **Границы** — задача не должна выходить за пределы, указанные в `BOUNDARIES.md`
|
||||
5. **Порядок** — задачи с зависимостями выполняются строго последовательно
|
||||
|
||||
### 3.2. Размер задачи
|
||||
|
||||
Задача должна укладываться в **1-2 часа работы исполнительного агента**. Если задача крупнее — разбить на подзадачи.
|
||||
|
||||
Признак слишком крупной задачи:
|
||||
- Нельзя сформулировать acceptance criteria одной строкой
|
||||
- Затрагивает 5+ файлов
|
||||
- Содержит союзы "и", "а также", "после чего"
|
||||
|
||||
### 3.3. Структура задачи
|
||||
|
||||
Каждая задача содержит:
|
||||
|
||||
| Поле | Описание | Пример |
|
||||
|---|---|---|
|
||||
| `id` | Уникальный идентификатор | `T1`, `T2` |
|
||||
| `title` | Заголовок (что сделать) | "Добавить модель User" |
|
||||
| `description` | Описание (как и зачем) | "Создать SQLAlchemy модель..." |
|
||||
| `type` | Тип задачи | `feature`, `refactor`, `test`, `fix`, `config`, `design`, `docs` |
|
||||
| `status` | Статус задачи | `pending`, `in_progress`, `completed`, `failed`, `archived` |
|
||||
| `files` | Список файлов, которые нужно создать/изменить | `["app/models/user.py"]` |
|
||||
| `depends_on` | ID задач, от которых зависит | `[]` или `["T0"]` |
|
||||
| `acceptance_criteria` | Список критериев приёмки (3-5 пунктов) | `["Модель проходит миграцию"]` |
|
||||
| `context` | Доп. информация (ссылки на доки, примеры, релевантные секции из design-report) | `"Смотри app/models/base.py"` |
|
||||
|
||||
### 3.4. Типы задач
|
||||
|
||||
| Тип | Описание |
|
||||
|---|---|
|
||||
| `config` | Настройка окружения, зависимостей, CI, инициализация проекта |
|
||||
| `design` | Архитектурное/дизайнерское решение без кода |
|
||||
| `feature` | Новая функциональность |
|
||||
| `refactor` | Изменение структуры без изменения поведения |
|
||||
| `test` | Добавление/исправление тестов |
|
||||
| `fix` | Исправление бага |
|
||||
| `docs` | Документация |
|
||||
| `invariant` | Тест, проверяющий архитектурный инвариант (см. 3.7) |
|
||||
|
||||
### 3.5. Зелёная декомпозиция (для greenfield/scaffold)
|
||||
|
||||
Если есть `.agent/design-report.md` — задачи формируются на основе группировки из дизайна:
|
||||
|
||||
1. **T1: init** — инициализация проекта, зависимости, конфиги, scaffold
|
||||
2. **T2..Tn: features** — модули/функциональность по одному
|
||||
3. **Tn+1: tests** — тесты на каждый модуль (можно в составе feature-задачи)
|
||||
4. **Tn+2: polish** — документация, форматирование, финальная проверка
|
||||
|
||||
### 3.6. Сортировка
|
||||
|
||||
Задачи в манифесте располагаются в порядке выполнения:
|
||||
1. Сначала задачи без зависимостей
|
||||
2. Потом те, чьи зависимости уже выполнены
|
||||
3. Последними — задачи с наибольшим числом зависимостей
|
||||
|
||||
### 3.7. Executable Invariants (если config.invariant_tests = yes)
|
||||
|
||||
Для каждого ADR (из layer-1/adr/) создать задачу типа `invariant` — тест, проверяющий архитектурное правило.
|
||||
|
||||
**Правила превращения ADR в инварианты:**
|
||||
|
||||
| ADR | Инвариант-тест |
|
||||
|---|---|
|
||||
| "Модуль X не зависит от Y" | `test_x_does_not_import_y.py` — import test |
|
||||
| "Слой Model не знает о CLI" | `test_model_layer_imports.py` — проверка import graph |
|
||||
| "Все исключения кастомные" | `test_custom_exceptions.py` — проверка hierarchy |
|
||||
| "Интерфейс репозитория не泄漏 implementation details" | `test_repository_interface.py` — ABC check |
|
||||
|
||||
**Формат задачи-инварианта:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "I1",
|
||||
"title": "Инвариант: model не импортирует cli",
|
||||
"type": "invariant",
|
||||
"files": ["tests/invariants/test_layer_imports.py"],
|
||||
"depends_on": ["T2"],
|
||||
"acceptance_criteria": [
|
||||
"Тест проверяет, что cashflow_model не импортирует cli, sync, engine",
|
||||
"Тест проходит на пустом проекте (до реализации функциональности)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Инварианты размещаются в `tests/invariants/` и запускаются вместе с основными тестами.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/task-manifest.json` — по схеме `TEMPLATES/task-manifest.json`
|
||||
- `.agent/task-manifest.md` — по шаблону `TEMPLATES/task-manifest.md`
|
||||
|
||||
Обновить checkpoints.json:
|
||||
- `phases.decomposition = "completed"`
|
||||
- `tasks` = полный массив задач со статусом `pending`
|
||||
|
||||
> **Примечание:** после HANDOFF завершённые задачи будут архивированы —
|
||||
> полное описание уходит в `.agent/archive/tasks/`, в манифесте остаётся
|
||||
> one-liner с `"status": "archived"`.
|
||||
|
||||
## Критерии завершения фазы
|
||||
|
||||
- [ ] Цель разбита на атомарные задачи
|
||||
- [ ] Для каждой задачи указаны acceptance criteria
|
||||
- [ ] Для каждой задачи указаны affected files
|
||||
- [ ] Зависимости между задачами корректны (нет циклов)
|
||||
- [ ] Invariant-задачи созданы для каждого ADR (если config требует)
|
||||
- [ ] `.agent/task-manifest.json` и `.agent/task-manifest.md` созданы
|
||||
- [ ] checkpoints.json обновлён
|
||||
@@ -1,142 +0,0 @@
|
||||
# Протокол 03: Архитектурное проектирование (DESIGN)
|
||||
|
||||
## Цель
|
||||
|
||||
Спроектировать архитектуру, модули, данные и интерфейсы для greenfield/scaffold-проекта.
|
||||
|
||||
DESIGN выполняется **только** для `project_type = greenfield` или `scaffold`. Для existing-проектов пропускается.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/context/analysis-report.md` (project_type: greenfield или scaffold)
|
||||
- `.agent/roadmap/sources.md` (опционально)
|
||||
- `.agent/checkpoints.json` (фаза design: pending)
|
||||
- `.agent/rules/project-rules.md` — прочитать первым
|
||||
|
||||
## Правила
|
||||
|
||||
1. **Реалистичность** — архитектура реализуема за 1 сессию (до 10 задач).
|
||||
2. **Документируемость** — каждый модуль, модель и интерфейс описывается в `design-report.md`.
|
||||
3. **Тестируемость** — каждый компонент проектируется с учётом тестирования.
|
||||
4. **Итеративность** — первая версия минимально рабочая (MVP), расширения — отдельными задачами.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 3.1. Прочитать правила проекта
|
||||
|
||||
Прочитать `.agent/rules/project-rules.md`, применить.
|
||||
|
||||
### 3.2. Технологический стек
|
||||
|
||||
Если стек не указан в README — предложить обоснованный выбор. Если указан — зафиксировать.
|
||||
|
||||
Для каждого компонента:
|
||||
- Язык и версия
|
||||
- Фреймворк / библиотека
|
||||
- База данных (движок, схема)
|
||||
- Инфраструктура (Docker, CI/CD, хостинг)
|
||||
|
||||
### 3.3. High-level архитектура
|
||||
|
||||
- **Паттерн** — монолит, модульный монолит, микросервисы, слоистая, луковая.
|
||||
- **Компоненты** — что делает каждый модуль/сервис.
|
||||
- **Схема взаимодействия** — текстовое описание потоков данных.
|
||||
|
||||
```
|
||||
[Client] → HTTP → [API Gateway] → [Auth Service]
|
||||
↓
|
||||
[Core Service] → [Database]
|
||||
↓
|
||||
[External API] → [3rd Party]
|
||||
```
|
||||
|
||||
### 3.4. Модули
|
||||
|
||||
| Поле | Описание |
|
||||
|---|---|
|
||||
| Имя модуля | `app/services/cashflow.py` |
|
||||
| Ответственность | Что делает |
|
||||
| Ключевые классы/функции | Сигнатуры без реализации |
|
||||
| Зависимости | Какие модули нужны |
|
||||
| Контракт | Что экспортирует |
|
||||
|
||||
### 3.5. Модели данных
|
||||
|
||||
Описать сущности, поля, связи:
|
||||
|
||||
```json
|
||||
{
|
||||
"entity": "Transaction",
|
||||
"fields": [
|
||||
{"name": "id", "type": "UUID", "pk": true},
|
||||
{"name": "amount", "type": "Decimal"},
|
||||
{"name": "date", "type": "datetime"},
|
||||
{"name": "category_id", "type": "UUID", "fk": "Category"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6. API интерфейсы
|
||||
|
||||
| Метод | Путь | Описание | Request | Response | Статусы |
|
||||
|---|---|---|---|---|---|
|
||||
| GET | /transactions | Список | ?page, ?limit | [Transaction] | 200 |
|
||||
| POST | /transactions | Создать | CreateTransactionDTO | Transaction | 201, 400 |
|
||||
|
||||
Если GUI — ключевые страницы. Если CLI — команды.
|
||||
|
||||
### 3.7. Обработка ошибок
|
||||
|
||||
- Стратегия: исключения / Result / коды.
|
||||
- Формат API-ошибок: `{ "error": "...", "code": "...", "details": {} }`.
|
||||
- Логирование: уровни для разных событий.
|
||||
|
||||
### 3.8. Стратегия тестирования
|
||||
|
||||
- Какие тесты нужны (unit, integration, e2e).
|
||||
- Как изолировать зависимости.
|
||||
- Команда запуска тестов.
|
||||
|
||||
### 3.9. Группировка в задачи
|
||||
|
||||
Предварительно наметить задачи по модулям — вход для DECOMPOSITION:
|
||||
|
||||
```
|
||||
T1: Инициализация проекта + зависимости
|
||||
T2: Модель данных (сущности, миграции)
|
||||
T3: Service (core logic)
|
||||
T4: API endpoints
|
||||
T5: Tests
|
||||
```
|
||||
|
||||
### 3.10. Создать design-report
|
||||
|
||||
Записать `.agent/context/design-report.md` по шаблону `TEMPLATES/design-report.md`.
|
||||
|
||||
### 3.11. Дополнительно (по команде пользователя)
|
||||
|
||||
Эти шаги **не выполняются автоматически** — только если пользователь явно попросил:
|
||||
|
||||
- **ADR** — вызвать `COMMANDS/adr.md` для ключевых решений.
|
||||
- **Alternative Architecture** — вызвать `COMMANDS/alt-arch.md` для сравнения.
|
||||
- **Risk Register** — вызвать `COMMANDS/risk-register.md` для допущений.
|
||||
- **Red Team** — вызвать `COMMANDS/red-team.md` для атаки на дизайн.
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/context/design-report.md`
|
||||
- Предварительная группировка задач (для DECOMPOSITION)
|
||||
- Возможно: ADR, risk-register, alt-architecture, red-team-report (если вызывали команды)
|
||||
- `checkpoints.json: phases.design = "completed"`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Стек определён
|
||||
- [ ] High-level архитектура описана
|
||||
- [ ] Модули и их ответственность описаны
|
||||
- [ ] Модели данных спроектированы
|
||||
- [ ] API/интерфейсы описаны (если применимо)
|
||||
- [ ] Стратегия тестирования определена
|
||||
- [ ] Задачи предварительно сгруппированы
|
||||
- [ ] `design-report.md` создан
|
||||
- [ ] `checkpoints.json` обновлён
|
||||
@@ -1,117 +0,0 @@
|
||||
# Протокол 04: Декомпозиция задач (DECOMPOSITION)
|
||||
|
||||
## Цель
|
||||
|
||||
Разбить цель пользователя (и архитектурный план, если есть) на атомарные, независимо выполнимые задачи. Записать в `manifest.json` + `manifest.md`.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/context/analysis-report.md`
|
||||
- `.agent/context/design-report.md` (опционально — для greenfield)
|
||||
- `.agent/roadmap/sources.md` (опционально)
|
||||
- `.agent/decisions/*.md` (опционально)
|
||||
- Цель пользователя (goal из `checkpoints.json`)
|
||||
- `.agent/rules/project-rules.md` — прочитать первым
|
||||
- `.agent/checkpoints.json` (фаза decomposition: pending)
|
||||
|
||||
## Принципы
|
||||
|
||||
1. **Атомарность** — одна задача = одна логическая единица, выполнимая и проверяемая за один подход.
|
||||
2. **Независимость (макс.)** — минимизировать зависимости между задачами.
|
||||
3. **Тестируемость** — каждая задача имеет измеримые acceptance criteria.
|
||||
4. **Границы** — задача не выходит за пределы `BOUNDARIES.md`.
|
||||
5. **Порядок** — задачи с зависимостями выполняются строго последовательно.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 4.1. Прочитать правила проекта
|
||||
|
||||
Прочитать `.agent/rules/project-rules.md`, применить.
|
||||
|
||||
### 4.2. Размер задачи
|
||||
|
||||
Задача должна укладываться в **1-2 часа работы агента**. Если крупнее — разбить.
|
||||
|
||||
Признак слишком крупной задачи:
|
||||
- Нельзя сформулировать acceptance criteria одной строкой.
|
||||
- Затрагивает 5+ файлов.
|
||||
- Содержит союзы «и», «а также», «после чего».
|
||||
|
||||
### 4.3. Сверить с roadmap
|
||||
|
||||
Если существует `.agent/roadmap/sources.md`:
|
||||
|
||||
- Задачи из roadmap получают приоритет P0-P3 в соответствии с `sources.md`.
|
||||
- Задачи без явного источника получают `origin: "decomposition"`.
|
||||
|
||||
### 4.4. Структура задачи
|
||||
|
||||
| Поле | Описание | Пример |
|
||||
|---|---|---|
|
||||
| `id` | Уникальный идентификатор | `T1`, `T2` |
|
||||
| `title` | Что сделать | "Добавить модель User" |
|
||||
| `description` | Как и зачем | "Создать SQLAlchemy модель..." |
|
||||
| `type` | Тип | `feature`, `refactor`, `test`, `fix`, `config`, `design`, `docs`, `invariant` |
|
||||
| `status` | Статус | `pending`, `in_progress`, `completed`, `failed`, `archived` |
|
||||
| `origin` | Источник | `roadmap:file`, `adr:NNN`, `user:direct`, `agent:analysis`, `decomposition` |
|
||||
| `files` | Файлы | `["app/models/user.py"]` |
|
||||
| `depends_on` | Зависимости | `[]` или `["T0"]` |
|
||||
| `acceptance_criteria` | 3-5 измеримых пунктов | `["Модель проходит миграцию"]` |
|
||||
| `context` | Доп. информация | `"Смотри app/models/base.py"` |
|
||||
|
||||
**Типы origin:**
|
||||
|
||||
- `roadmap:{filename}` — из FUTURE/ или roadmap
|
||||
- `adr:{NNN}` — из Architecture Decision Record
|
||||
- `user:direct` — от пользователя
|
||||
- `agent:analysis` — выявлено агентом
|
||||
- `decomposition` — создано при декомпозиции
|
||||
- `invariant:{adr_id}` — инвариант для ADR (создаётся командой `/invariant-tests`)
|
||||
- `risk:{R-NNN}` — из Risk Register
|
||||
|
||||
### 4.5. Зелёная декомпозиция (greenfield/scaffold)
|
||||
|
||||
Если есть `design-report.md` — задачи на основе группировки из дизайна:
|
||||
|
||||
1. **T1: init** — инициализация, зависимости, scaffold.
|
||||
2. **T2..Tn: features** — модули по одному.
|
||||
3. **Tn+1: tests** — тесты (можно в составе feature).
|
||||
4. **Tn+2: polish** — документация, форматирование.
|
||||
|
||||
### 4.6. Сортировка
|
||||
|
||||
Задачи в манифесте в порядке выполнения:
|
||||
|
||||
1. Без зависимостей.
|
||||
2. Чьи зависимости уже выполнены.
|
||||
3. С наибольшим числом зависимостей.
|
||||
|
||||
### 4.7. Записать manifest
|
||||
|
||||
Создать `.agent/tasks/manifest.json` по шаблону `TEMPLATES/task-manifest.json`.
|
||||
Создать `.agent/tasks/manifest.md` по шаблону `TEMPLATES/task-manifest.md`.
|
||||
|
||||
### 4.8. Обновить checkpoints
|
||||
|
||||
```json
|
||||
{
|
||||
"phases": { "decomposition": "completed" },
|
||||
"tasks": [...],
|
||||
"last_updated": "<timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/tasks/manifest.json`
|
||||
- `.agent/tasks/manifest.md`
|
||||
- Обновлённый `checkpoints.json`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Цель разбита на атомарные задачи
|
||||
- [ ] У каждой задачи — acceptance criteria, origin, files
|
||||
- [ ] Зависимости корректны (нет циклов)
|
||||
- [ ] Задачи сверены с roadmap (если `sources.md` существует)
|
||||
- [ ] `manifest.json` и `manifest.md` созданы
|
||||
- [ ] `checkpoints.json` обновлён
|
||||
@@ -0,0 +1,126 @@
|
||||
# Протокол 04: Настройка окружения (SETUP)
|
||||
|
||||
## Цель
|
||||
|
||||
Обеспечить рабочее окружение, в котором исполнительный агент может сразу выполнять задачи.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/analysis-report.md`
|
||||
- `.agent/design-report.md` (опционально, для greenfield)
|
||||
- `.agent/task-manifest.json`
|
||||
- `.agent/checkpoints.json` (фаза environment: pending)
|
||||
|
||||
## Поведение в зависимости от типа проекта
|
||||
|
||||
Фаза SETUP работает по-разному для `existing` и `greenfield/scaffold` проектов.
|
||||
|
||||
---
|
||||
|
||||
## Ветка A: existing/scaffold проект
|
||||
|
||||
### 4A.1. Зависимости
|
||||
|
||||
- Установить все зависимости согласно документации проекта
|
||||
- Если есть `requirements.txt`, `pyproject.toml`, `package.json`, `Cargo.toml` и т.д. — выполнить установку
|
||||
- Если в проекте используется виртуальное окружение (venv, .venv, conda) — активировать или создать
|
||||
- Если в проекте используется Docker — проверить, что образ собирается
|
||||
|
||||
**Правило:** если установка зависимостей требует нестандартных шагов, описанных в README — строго следовать им. Если шаги не описаны — запросить у пользователя.
|
||||
|
||||
### 4A.2. Конфигурация
|
||||
|
||||
- Проверить наличие конфигурационных файлов (`.env.example`, `.env`, `config.yaml`)
|
||||
- Если есть `.env.example`, скопировать в `.env` с настройками по умолчанию
|
||||
- Если проекту требуется БД — проверить строку подключения, при необходимости создать БД или использовать SQLite для разработки
|
||||
- Настроить pre-commit хуки, если они есть в проекте
|
||||
|
||||
### 4A.3. Линтеры и форматтеры
|
||||
|
||||
- Запустить линтер на всём проекте: записать результат
|
||||
- Если линтер выдаёт ошибки — не исправлять, только зафиксировать в отчёте
|
||||
- Убедиться, что исполнительный агент может запускать линтер (записать команду)
|
||||
|
||||
### 4A.4. Baseline-тесты
|
||||
|
||||
- Запустить все тесты проекта
|
||||
- Записать в `.agent/baseline-test-report.log`:
|
||||
- Команда запуска
|
||||
- Общее количество тестов
|
||||
- Пройдено / упало / пропущено
|
||||
- Время выполнения
|
||||
- Список упавших тестов (если есть)
|
||||
- Если тесты не проходят — указать это в отчёте, но **не исправлять**
|
||||
|
||||
### 4A.5. Сборка проекта
|
||||
|
||||
- Выполнить полную сборку/компиляцию проекта
|
||||
- Записать результат (успех/ошибка с логом)
|
||||
- Сборка должна проходить без ошибок. Если не собирается — остановиться, сообщить пользователю.
|
||||
|
||||
---
|
||||
|
||||
## Ветка B: greenfield проект
|
||||
|
||||
### 4B.1. Инициализация проекта
|
||||
|
||||
- Создать базовую структуру директорий согласно design-report.md
|
||||
- Инициализировать пакетный менеджер:
|
||||
- Python: `pyproject.toml` (poetry, pdm, hatch) или `requirements.txt`
|
||||
- Node: `package.json` и `npm init` / `yarn init`
|
||||
- Go: `go mod init`
|
||||
- Rust: `cargo init`
|
||||
- Настроить базовый конфиг: `.env.example`, `config/` и т.д.
|
||||
- Настроить линтер/форматтер: `ruff`, `eslint`, `gofmt` и т.д.
|
||||
|
||||
### 4B.2. Scaffold-код
|
||||
|
||||
Создать пустые заглушки для модулей, описанных в design-report:
|
||||
|
||||
```python
|
||||
# app/services/cashflow.py — заглушка
|
||||
class CashflowService:
|
||||
"""TBD — реализация в задаче T3"""
|
||||
pass
|
||||
```
|
||||
|
||||
Назначение: фиксировать структуру, чтобы исполнительный агент не думал о ней, а сразу писал реализацию.
|
||||
|
||||
### 4B.3. Установка зависимостей
|
||||
|
||||
- Установить базовые зависимости согласно стеку из design-report
|
||||
- Если проект использует БД — установить драйвер/ORM
|
||||
- Если проект использует API — установить фреймворк (FastAPI, Express и т.д.)
|
||||
- Установить dev-зависимости: линтер, тестовый раннер, type stubs
|
||||
|
||||
### 4B.4. Базовые тесты (scaffold)
|
||||
|
||||
- Создать пустой тестовый файл для каждого модуля
|
||||
- Настроить тестовый раннер (pytest, jest и т.д.)
|
||||
- Записать в `.agent/baseline-test-report.log`: "0 tests — greenfield, scaffold готов"
|
||||
|
||||
### 4B.5. Проверка сборки
|
||||
|
||||
- Убедиться, что проект импортируется без ошибок
|
||||
- Убедиться, что линтер проходит (без кода он должен проходить)
|
||||
- Убедиться, что тестовый раннер запускается (0 tests, exit code 0)
|
||||
|
||||
---
|
||||
|
||||
## Выход
|
||||
|
||||
- Работоспособное окружение / инициализированный проект
|
||||
- `.agent/baseline-test-report.log` — результат прогона тестов
|
||||
- `.agent/setup-report.log` — лог установки зависимостей и сборки
|
||||
|
||||
Обновить checkpoints.json: `phases.environment = "completed"`.
|
||||
|
||||
## Критерии завершения фазы
|
||||
|
||||
- [ ] Зависимости установлены / проект инициализирован
|
||||
- [ ] Проект собирается / импортируется без ошибок
|
||||
- [ ] Baseline-тесты запущены, результат записан
|
||||
- [ ] `.agent/baseline-test-report.log` и `.agent/setup-report.log` созданы
|
||||
- [ ] checkpoints.json обновлён
|
||||
|
||||
Если проект не собирается — **фаза считается проваленной**, checkpoints.json отмечает `phases.environment = "failed"`, управление возвращается пользователю.
|
||||
@@ -1,136 +0,0 @@
|
||||
# Протокол 05: Исполнение задач (EXECUTION)
|
||||
|
||||
## Цель
|
||||
|
||||
Выполнить задачи из `manifest.json`: реализовать код, написать тесты, закоммитить, создать request — артефакт результата.
|
||||
|
||||
EXECUTION — **циклическая** фаза. Работает, пока есть задачи со статусом `pending` и выполненными `depends_on`.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/tasks/manifest.json`
|
||||
- `.agent/context/analysis-report.md`
|
||||
- `.agent/context/design-report.md` (опционально)
|
||||
- `.agent/decisions/*.md` (опционально)
|
||||
- `.agent/rules/project-rules.md` — прочитать первым
|
||||
- `.agent/checkpoints.json` (фаза execution: pending)
|
||||
|
||||
## Шаги (цикл)
|
||||
|
||||
### 5.1. Прочитать правила проекта
|
||||
|
||||
Прочитать `.agent/rules/project-rules.md`, применить.
|
||||
|
||||
### 5.2. Setup окружения (первый запуск)
|
||||
|
||||
Если это первый запуск EXECUTION в сессии:
|
||||
|
||||
- Установить зависимости через штатный пакетный менеджер.
|
||||
- Запустить сборку / базовые тесты.
|
||||
- Записать baseline в `.agent/context/baseline-test-report.log`.
|
||||
|
||||
### 5.3. Выбрать задачу
|
||||
|
||||
Найти в `manifest.json` задачу, удовлетворяющую:
|
||||
|
||||
- `status: "pending"`
|
||||
- Все `depends_on` имеют `status: "completed"` или `"archived"`.
|
||||
|
||||
Если таких нет — EXECUTION завершён, перейти к ожиданию команды пользователя.
|
||||
|
||||
### 5.4. Заблокировать задачу
|
||||
|
||||
В `manifest.json`:
|
||||
|
||||
```json
|
||||
{ "id": "T1", "status": "in_progress" }
|
||||
```
|
||||
|
||||
### 5.5. Исполнить
|
||||
|
||||
- Следовать конвенциям проекта (из ANALYSE).
|
||||
- Соблюдать `BOUNDARIES.md`.
|
||||
- Если задача ссылается на ADR — следовать архитектурному решению.
|
||||
- Писать код + тесты.
|
||||
|
||||
### 5.6. Верифицировать
|
||||
|
||||
- Запустить тесты (все или релевантные).
|
||||
- Проверить LSP diagnostics на изменённых файлах.
|
||||
- Убедиться, что acceptance criteria выполнены.
|
||||
|
||||
### 5.7. Закоммитить
|
||||
|
||||
Сделать git-коммит. Сообщение — суть задачи.
|
||||
|
||||
### 5.8. Создать request
|
||||
|
||||
Создать `.agent/requests/active/req-{task_id}.json` по шаблону `TEMPLATES/request.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id": "req-T1",
|
||||
"task_id": "T1",
|
||||
"title": "GET /health endpoint",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Добавить ручку GET /health с тестами",
|
||||
"changes": {
|
||||
"summary": "Создан health router, подключён в main.py, написаны тесты",
|
||||
"commits": ["abc1234"],
|
||||
"files_changed": ["app/routers/health.py", "app/main.py", "tests/test_health.py"]
|
||||
},
|
||||
"verification": {
|
||||
"tests_passed": "24/24",
|
||||
"lsp_clean": true
|
||||
},
|
||||
"fulfills_ac": ["Ручка возвращает 200 + {\"status\":\"ok\"}"]
|
||||
}
|
||||
```
|
||||
|
||||
Request фиксирует:
|
||||
- **summary** — суть изменений (не diff).
|
||||
- **commits** — ссылки на коммиты.
|
||||
- **files_changed** — какие файлы.
|
||||
- **verification** — тесты + LSP.
|
||||
- **fulfills_ac** — какие acceptance criteria закрыты.
|
||||
|
||||
### 5.9. Завершить задачу
|
||||
|
||||
```json
|
||||
{ "id": "T1", "status": "completed" }
|
||||
```
|
||||
|
||||
### 5.10. Цикл
|
||||
|
||||
Перейти к шагу 5.3. Если задач больше нет — сообщить пользователю и ожидать команду (METASTATE, новая задача, или завершение).
|
||||
|
||||
## Request как единица результата
|
||||
|
||||
Не просто «задача сделана», а документированный результат. Request проходит ревью в фазе METASTATE:
|
||||
|
||||
- `ready_for_review` → после проверки → `approved` или `rejected`.
|
||||
|
||||
## Команды во время EXECUTION
|
||||
|
||||
В любой момент цикла пользователь может вызвать:
|
||||
|
||||
- **/adr** — зафиксировать архитектурное решение, появившееся в процессе.
|
||||
- **/red-team** — попытаться сломать текущий подход.
|
||||
- **/risk-register** — зафиксировать новый риск.
|
||||
|
||||
Команды не прерывают EXECUTION, но могут добавить задачи в manifest.
|
||||
|
||||
## Выход
|
||||
|
||||
- Выполненные задачи в `manifest.json` (status: completed)
|
||||
- `.agent/requests/active/req-{task_id}.json` для каждой выполненной задачи
|
||||
- Обновлённый `checkpoints.json`
|
||||
|
||||
## Критерии завершения (одна итерация)
|
||||
|
||||
- [ ] Acceptance criteria выполнены
|
||||
- [ ] Тесты проходят
|
||||
- [ ] LSP diagnostics чист
|
||||
- [ ] Коммит создан
|
||||
- [ ] Request создан в `.agent/requests/active/`
|
||||
- [ ] Задача в `manifest.json` отмечена completed
|
||||
@@ -0,0 +1,188 @@
|
||||
# Протокол 05: Передача исполнительному агенту (HANDOFF)
|
||||
|
||||
## Цель
|
||||
|
||||
Подготовить и передать исполнительному агенту полный контекст для работы: задачи, окружение, правила.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/analysis-report.md`
|
||||
- `.agent/design-report.md` (опционально, для greenfield)
|
||||
- `.agent/layer-1/adr/*.md` (опционально)
|
||||
- `.agent/layer-1/risk-register.md` (опционально)
|
||||
- `.agent/layer-1/red-team-report.md` (опционально)
|
||||
- `.agent/task-manifest.json`
|
||||
- `.agent/task-manifest.md`
|
||||
- `.agent/baseline-test-report.log`
|
||||
- `.agent/checkpoints.json` (все предыдущие фазы: completed)
|
||||
|
||||
## Шаги
|
||||
|
||||
### 5.1. Архивация завершённых артефактов
|
||||
|
||||
Перед валидацией и передачей выполнить архивирование.
|
||||
|
||||
**Архивировать завершённые задачи:**
|
||||
|
||||
Для каждой задачи в `task-manifest.json` со статусом `completed`:
|
||||
1. Создать `.agent/archive/tasks/<id>.json` — перенести полное описание задачи (все поля)
|
||||
2. В `task-manifest.json` заменить задачу на one-liner:
|
||||
```json
|
||||
{ "id": "<id>", "title": "<title>", "status": "archived" }
|
||||
```
|
||||
|
||||
**Архивировать чекпоинты:**
|
||||
|
||||
Если `checkpoints.json` уже существует — сохранить предыдущую версию в `.agent/archive/checkpoints/<last_updated>.json`.
|
||||
|
||||
**Создать индекс архива:**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"archived_at": "<timestamp>",
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "...", "archived_at": "<timestamp>" }
|
||||
],
|
||||
"checkpoints": [
|
||||
{ "file": "checkpoints/2026-07-15T10-00-00.json", "archived_at": "<timestamp>" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2. Валидация
|
||||
|
||||
Перед передачей проверить:
|
||||
|
||||
- [ ] Все фазы отмечены как `completed` в checkpoints.json
|
||||
- [ ] `.agent/` содержит все обязательные файлы:
|
||||
- `checkpoints.json`
|
||||
- `analysis-report.md`
|
||||
- `task-manifest.json` + `task-manifest.md`
|
||||
- `baseline-test-report.log`
|
||||
- `setup-report.log`
|
||||
- `src/META_AGENT_GUIDE.md`
|
||||
- `src/BOUNDARIES.md`
|
||||
- `src/VERSION`
|
||||
- `src/PROTOCOLS/`
|
||||
- `src/TEMPLATES/`
|
||||
- `rules/project-rules.md`
|
||||
- `archive/index.json`
|
||||
- [ ] Для greenfield: `design-report.md` присутствует
|
||||
- [ ] В task-manifest.json нет циклических зависимостей
|
||||
- [ ] Все acceptance criteria сформулированы измеримо
|
||||
- [ ] Для каждой задачи указаны affected files
|
||||
- [ ] В репозитории нет незакоммиченных изменений (кроме `.agent/`)
|
||||
- [ ] `.agent/src/` содержит актуальные исходники MetaAgent (META_AGENT_GUIDE.md, PROTOCOLS/, TEMPLATES/, BOUNDARIES.md, VERSION)
|
||||
- [ ] `AGENTS.md` присутствует в корне репозитория
|
||||
- [ ] `.agent/rules/` содержит `project-rules.md`
|
||||
|
||||
**Дополнительные проверки (если config включает):**
|
||||
- [ ] ADR присутствуют (если adr=yes)
|
||||
- [ ] Risk Register заполнен (если risk_register=yes)
|
||||
- [ ] Red Team Report есть (если red_team=yes)
|
||||
- [ ] Invariant-задачи в манифесте (если invariant_tests=yes)
|
||||
|
||||
### 5.3. Layer-структура .agent/
|
||||
|
||||
Если `config.layer_structure = yes`, организовать артефакты по слоям:
|
||||
|
||||
```
|
||||
.agent/
|
||||
layer-0/
|
||||
checkpoints.json # всегда (ядро)
|
||||
session-summary.md # краткая сводка сессии (создаётся здесь)
|
||||
layer-1/
|
||||
adr/ # ADR (опционально)
|
||||
risk-register.md # (опционально)
|
||||
red-team-report.md # (опционально)
|
||||
layer-2/
|
||||
analysis-report.md
|
||||
design-report.md
|
||||
design-report.md
|
||||
layer-3/
|
||||
handoff-summary.md
|
||||
task-manifest.json
|
||||
task-manifest.md
|
||||
baseline-test-report.log
|
||||
setup-report.log
|
||||
```
|
||||
|
||||
Если `layer_structure = no` — артефакты остаются плоскими в `.agent/`, как раньше.
|
||||
|
||||
### 5.4. Создать handoff-summary.md
|
||||
|
||||
Заполнить по шаблону `TEMPLATES/handoff-summary.md`:
|
||||
|
||||
- **Session Info** — ID, цель, дата
|
||||
- **Configuration** — какие функции были включены, глубина
|
||||
- **Repo Summary** — краткая выжимка из analysis-report
|
||||
- **Environment Status** — результат сборки и тестов
|
||||
- **Design Summary** (если есть design-report) — ключевые архитектурные решения
|
||||
- **ADR Summary** (если adr=yes) — какие решения задокументированы
|
||||
- **Risk Register** (если risk_register=yes) — основные допущения
|
||||
- **Task Overview** — количество задач, типы, список
|
||||
- **Next Steps** — с какой задачи начинать исполнительному агенту
|
||||
- **Project Rules** — ссылка на `.agent/rules/project-rules.md` (передаётся exec-агенту)
|
||||
- **Archive** — ссылка на `.agent/archive/index.json` (история завершённых задач)
|
||||
- **Caveats** — известные проблемы, ограничения, неясные моменты
|
||||
- **Checkpoints** — актуальное состояние чекпоинтов
|
||||
|
||||
### 5.5. Финализировать checkpoints
|
||||
|
||||
- Отметить `phases.handoff = "completed"`
|
||||
- Записать финальный `last_updated`
|
||||
|
||||
### 5.6. Сигнал
|
||||
|
||||
Сообщить пользователю/оркестратору:
|
||||
|
||||
```
|
||||
HANDOFF COMPLETE
|
||||
|
||||
Session: <session_id>
|
||||
Target: <target_repo>
|
||||
Type: <existing | greenfield | scaffold>
|
||||
Config: depth=<N>, adr=<yes|no>, red_team=<yes|no>, ...
|
||||
Tasks: <count> tasks ready
|
||||
|
||||
Исполнительный агент может начинать с задачи <T1>.
|
||||
Контекст: .agent/handoff-summary.md
|
||||
Манифест: .agent/task-manifest.json
|
||||
```
|
||||
|
||||
## Что получает исполнительный агент
|
||||
|
||||
1. **Целевой репозиторий** — полностью настроенный, с установленными зависимостями
|
||||
2. **`.agent/`** — директория со всеми артефактами (layer-структура или плоская)
|
||||
3. **`task-manifest.json`** — машиночитаемый список задач
|
||||
4. **`task-manifest.md`** — человекочитаемый список задач
|
||||
5. **`handoff-summary.md`** — итоговая сводка
|
||||
6. **`checkpoints.json`** — актуальное состояние (исполнительный агент будет его обновлять)
|
||||
7. **`layer-1/adr/*.md`** (опционально) — ключевые решения
|
||||
8. **`layer-1/risk-register.md`** (опционально) — допущения
|
||||
9. **`layer-2/analysis-report.md`** — полный анализ репозитория (справочно)
|
||||
10. **`layer-2/design-report.md`** (только для greenfield) — архитектурный план
|
||||
11. **`layer-3/baseline-test-report.log`** — baseline тестов (чтобы не сломать существующее)
|
||||
12. **`.agent/src/`** — полные исходники MetaAgent (справочно, всегда присутствуют)
|
||||
13. **`.agent/rules/`** — пользовательские правила проекта
|
||||
14. **`AGENTS.md`** — инструкция для AI-агента в корне проекта (всегда присутствует)
|
||||
15. **`.agent/archive/`** — архив завершённых задач, чекпоинтов и устаревших артефактов
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/layer-0/session-summary.md` (если layer_structure=yes)
|
||||
- `.agent/layer-3/handoff-summary.md`
|
||||
- `.agent/layer-0/checkpoints.json` (финальный)
|
||||
- `.agent/archive/index.json` (создаётся при архивации)
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Все артефакты на месте (с учётом layer-структуры)
|
||||
- [ ] `.agent/src/` содержит актуальные исходники MetaAgent
|
||||
- [ ] `.agent/rules/` содержит `project-rules.md`
|
||||
- [ ] `AGENTS.md` присутствует в корне репозитория
|
||||
- [ ] `.agent/archive/index.json` создан, завершённые задачи архивированы
|
||||
- [ ] handoff-summary.md заполнен (включая config, design summary, ADR summary, archive)
|
||||
- [ ] checkpoints.json финализирован
|
||||
- [ ] Сигнал отправлен пользователю/оркестратору
|
||||
@@ -1,145 +0,0 @@
|
||||
# Протокол 06: Обновление метасостояния (METASTATE)
|
||||
|
||||
## Цель
|
||||
|
||||
По команде пользователя провести ревью накопленных requests, синхронизировать манифест, обновить слепок проекта и подготовить `.agent/` как полную картину для следующей сессии.
|
||||
|
||||
## Когда запускать
|
||||
|
||||
По команде пользователя:
|
||||
|
||||
- «обнови метасостояние»
|
||||
- «update metastate»
|
||||
- «подведи итог»
|
||||
- «заверши сессию»
|
||||
|
||||
Может запускаться многократно — после каждой группы выполненных задач.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/requests/active/` — все request-ы со статусом `ready_for_review`
|
||||
- `.agent/tasks/manifest.json`
|
||||
- `.agent/context/project-state.md` (создан в ANALYSE, обновляется здесь)
|
||||
- `.agent/roadmap/sources.md`
|
||||
- `.agent/decisions/index.json`
|
||||
- `.agent/checkpoints.json`
|
||||
|
||||
## Шаги
|
||||
|
||||
### 6.1. Собрать requests
|
||||
|
||||
Прочитать все файлы из `.agent/requests/active/` со статусом `ready_for_review`.
|
||||
|
||||
### 6.2. Ревью каждого request
|
||||
|
||||
Для каждого:
|
||||
|
||||
1. **Верифицировать** — тесты проходят, LSP чист, AC выполнены, коммиты на месте.
|
||||
2. **Принять или отклонить:**
|
||||
|
||||
- ✅ **approved**:
|
||||
- Переместить в `.agent/requests/archive/`.
|
||||
- В `manifest.json` убедиться: `status: "completed"`.
|
||||
|
||||
- ❌ **rejected**:
|
||||
- Оставить в `active/` с комментарием.
|
||||
- В `manifest.json`: `status: "reopened"`, добавить `rejection_reason`.
|
||||
- В request добавить `rejection_reason`.
|
||||
|
||||
### 6.3. Архивация завершённых задач
|
||||
|
||||
Для каждой `completed` задачи:
|
||||
|
||||
1. Создать `.agent/archive/tasks/{id}.json` — полное описание.
|
||||
2. В `manifest.json` заменить на one-liner:
|
||||
|
||||
```json
|
||||
{ "id": "T1", "title": "GET /health endpoint", "status": "archived", "origin": "user:direct" }
|
||||
```
|
||||
|
||||
### 6.4. Обновить project-state
|
||||
|
||||
Переписать `.agent/context/project-state.md` с учётом выполненных задач:
|
||||
|
||||
- Обновить список модулей (добавлены / изменены).
|
||||
- Обновить архитектурную схему (кратко).
|
||||
- Обновить статус тестов.
|
||||
- Добавить новые ADR.
|
||||
- Убрать закрытые concerns.
|
||||
|
||||
**Цель:** следующий агент читает `project-state.md` и понимает проект, не открывая исходники.
|
||||
|
||||
### 6.5. Обновить roadmap
|
||||
|
||||
В `.agent/roadmap/sources.md`:
|
||||
|
||||
- Отметить выполненные пункты.
|
||||
- Пересчитать приоритеты.
|
||||
- Добавить новые источники (если появились).
|
||||
|
||||
### 6.6. Индекс архива
|
||||
|
||||
Создать/обновить `.agent/archive/index.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"archived_at": "<timestamp>",
|
||||
"tasks": [{ "id": "T1", "title": "...", "archived_at": "<timestamp>" }],
|
||||
"requests": [{ "id": "req-T1", "task_id": "T1", "archived_at": "<timestamp>" }],
|
||||
"checkpoints": [{ "file": "checkpoints/<ts>.json", "archived_at": "<timestamp>" }]
|
||||
}
|
||||
```
|
||||
|
||||
### 6.7. Создать handoff-summary
|
||||
|
||||
Создать `.agent/handoff-summary.md` — полная сводка для следующего агента:
|
||||
|
||||
```markdown
|
||||
## Session Summary
|
||||
**Session:** <id>
|
||||
**Goal:** <goal>
|
||||
**Completed:** N tasks
|
||||
**Pending:** M tasks
|
||||
**Approved requests:** req-T1, req-T2
|
||||
|
||||
## Project State
|
||||
(краткая выжимка из project-state.md)
|
||||
|
||||
## Next Steps
|
||||
(с чего начать следующую сессию)
|
||||
|
||||
## Key Artifacts
|
||||
- Project state: `.agent/context/project-state.md`
|
||||
- Tasks: `.agent/tasks/manifest.json`
|
||||
- Roadmap: `.agent/roadmap/sources.md`
|
||||
- Pending reviews: `.agent/requests/active/`
|
||||
- Archive: `.agent/archive/index.json`
|
||||
```
|
||||
|
||||
### 6.8. Обновить checkpoints
|
||||
|
||||
```json
|
||||
{ "phases": { "metastate": "completed" }, "last_updated": "<timestamp>" }
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/requests/archive/` — подтверждённые request-ы
|
||||
- `.agent/archive/tasks/{id}.json` — архив задач
|
||||
- Обновлённый `.agent/context/project-state.md`
|
||||
- Обновлённый `.agent/roadmap/sources.md`
|
||||
- `.agent/handoff-summary.md`
|
||||
- `.agent/archive/index.json`
|
||||
- Финальный `checkpoints.json`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Все `ready_for_review` requests проверены (approved / rejected)
|
||||
- [ ] Approved перемещены в archive
|
||||
- [ ] Completed задачи архивированы (one-liner в manifest)
|
||||
- [ ] `project-state.md` отражает актуальное состояние
|
||||
- [ ] `roadmap/sources.md` обновлён
|
||||
- [ ] `archive/index.json` создан
|
||||
- [ ] `handoff-summary.md` готов
|
||||
- [ ] `checkpoints.json` финализирован
|
||||
@@ -1,113 +0,0 @@
|
||||
# Протокол 07: Завершение сессии (HANDOFF)
|
||||
|
||||
## Цель
|
||||
|
||||
Финализация сессии: валидация структуры `.agent/`, финальный `session-summary.md`, отметка `phases.handoff = "completed"`.
|
||||
|
||||
> Если перед HANDOFF был METASTATE — архивация, project-state, handoff-summary уже готовы. HANDOFF только валидирует и финализирует.
|
||||
|
||||
## Вход
|
||||
|
||||
- `.agent/checkpoints.json` (все фазы кроме handoff: completed или skipped)
|
||||
- Все артефакты `.agent/`
|
||||
|
||||
## Шаги
|
||||
|
||||
### 7.1. Проверить: был ли METASTATE?
|
||||
|
||||
Если существуют `.agent/handoff-summary.md` и `.agent/context/project-state.md` (обновлён) — METASTATE выполнен. Перейти к шагу 7.3.
|
||||
|
||||
Если нет — выполнить лёгкую архивацию (шаг 7.2).
|
||||
|
||||
### 7.2. Лёгкая архивация (если METASTATE не было)
|
||||
|
||||
Если есть `completed` задачи в `manifest.json`:
|
||||
|
||||
- Архивировать в `.agent/archive/tasks/{id}.json`.
|
||||
- Заменить в `manifest.json` на one-liner.
|
||||
- Создать `.agent/archive/index.json`.
|
||||
|
||||
### 7.3. Валидация
|
||||
|
||||
Проверить:
|
||||
|
||||
- [ ] Все фазы в `checkpoints.json` отмечены `completed` или `skipped`.
|
||||
- [ ] `.agent/` содержит обязательные файлы:
|
||||
- `checkpoints.json`
|
||||
- `context/analysis-report.md`
|
||||
- `context/project-state.md`
|
||||
- `tasks/manifest.json` + `manifest.md`
|
||||
- `rules/project-rules.md`
|
||||
- `src/GUIDE.md`
|
||||
- `src/BOUNDARIES.md`
|
||||
- `src/VERSION`
|
||||
- `src/PROTOCOLS/`
|
||||
- `src/COMMANDS/`
|
||||
- `src/TEMPLATES/`
|
||||
- [ ] В `manifest.json` нет циклических зависимостей.
|
||||
- [ ] У каждой задачи — measurable acceptance criteria и origin.
|
||||
- [ ] `AGENTS.md` присутствует в корне репозитория.
|
||||
|
||||
### 7.4. Создать session-summary
|
||||
|
||||
Создать `.agent/session-summary.md`:
|
||||
|
||||
```markdown
|
||||
# Session Summary
|
||||
|
||||
**Session:** <id>
|
||||
**MetaAgent version:** 3.0.0
|
||||
**Date:** <timestamp>
|
||||
**Goal:** <goal>
|
||||
|
||||
## Phases Executed
|
||||
- [x] INIT
|
||||
- [x] ANALYSE
|
||||
- [x] ROADMAP
|
||||
- [x] DESIGN (или skipped)
|
||||
- [x] DECOMPOSITION
|
||||
- [x] EXECUTION (N tasks)
|
||||
- [x] METASTATE (или skipped)
|
||||
- [x] HANDOFF
|
||||
|
||||
## Results
|
||||
- Tasks completed: N
|
||||
- Requests approved: N
|
||||
- Files changed: [list]
|
||||
|
||||
## Next
|
||||
Следующий агент: читай `.agent/handoff-summary.md`.
|
||||
```
|
||||
|
||||
### 7.5. Финализировать checkpoints
|
||||
|
||||
```json
|
||||
{ "phases": { "handoff": "completed" }, "last_updated": "<timestamp>" }
|
||||
```
|
||||
|
||||
### 7.6. Сигнал
|
||||
|
||||
```
|
||||
HANDOFF COMPLETE
|
||||
|
||||
Session: <session_id>
|
||||
Target: <target_repo>
|
||||
Type: <existing | greenfield | scaffold>
|
||||
Tasks: <N> total, <M> completed, <K> pending
|
||||
|
||||
Следующий агент начинает с .agent/handoff-summary.md
|
||||
```
|
||||
|
||||
## Выход
|
||||
|
||||
- `.agent/session-summary.md`
|
||||
- Финальный `.agent/checkpoints.json`
|
||||
- (если METASTATE не было) `.agent/archive/index.json`
|
||||
|
||||
## Критерии завершения
|
||||
|
||||
- [ ] Все артефакты на месте
|
||||
- [ ] (если METASTATE не было) `completed` задачи архивированы
|
||||
- [ ] `session-summary.md` создан
|
||||
- [ ] `checkpoints.json` финализирован
|
||||
- [ ] Сигнал отправлен пользователю
|
||||
@@ -15,7 +15,8 @@
|
||||
- **Точка входа:** {{ entry_point }}
|
||||
- **Система сборки:** {{ build_system }}
|
||||
|
||||
## 2. Стек технологий (existing / scaffold)
|
||||
{% if project_type == "existing" or project_type == "scaffold" %}
|
||||
## 2. Стек технологий
|
||||
|
||||
| Компонент | Значение |
|
||||
|---|---|
|
||||
@@ -26,7 +27,7 @@
|
||||
| Пакетный менеджер | {{ package_manager }} |
|
||||
| Линтер/форматтер | {{ linter }} |
|
||||
|
||||
## 3. Архитектура (existing / scaffold)
|
||||
## 3. Архитектура
|
||||
|
||||
```
|
||||
{{ directory_tree }}
|
||||
@@ -40,7 +41,7 @@
|
||||
|---|---|
|
||||
| {{ module }} | {{ description }} |
|
||||
|
||||
## 4. Конвенции (existing / scaffold)
|
||||
## 4. Конвенции
|
||||
|
||||
- **Стиль:** {{ code_style }}
|
||||
- **Импорты:** {{ import_style }}
|
||||
@@ -48,38 +49,52 @@
|
||||
- **Обработка ошибок:** {{ error_handling }}
|
||||
- **Логирование:** {{ logging }}
|
||||
|
||||
## 5. Тесты (existing / scaffold)
|
||||
## 5. Тесты
|
||||
|
||||
- **Команда запуска:** `{{ test_command }}`
|
||||
- **Всего тестов:** {{ total_tests }}
|
||||
- **Пройдено:** {{ passed }}
|
||||
- **Упало:** {{ failed }}
|
||||
- **Пропущено:** {{ skipped }}
|
||||
- **Упавшие тесты:** {{ failed_tests_list }}
|
||||
- **Упавшие тесты:**
|
||||
{% for test in failed_tests %}
|
||||
- `{{ test }}`
|
||||
{% endfor %}
|
||||
|
||||
## 6. Базовая проверка (existing / scaffold)
|
||||
## 6. Базовая проверка
|
||||
|
||||
- **Сборка:** {{ build_status }}
|
||||
- **Запуск:** {{ run_status }}
|
||||
- **Git status:** {{ git_status }}
|
||||
{% endif %}
|
||||
|
||||
## 7. Требования (greenfield / scaffold)
|
||||
{% if project_type == "greenfield" or project_type == "scaffold" %}
|
||||
## 7. Требования (из README)
|
||||
|
||||
### Функциональные требования
|
||||
|
||||
{{ functional_requirements_list }}
|
||||
{% for req in functional_requirements %}
|
||||
- {{ req }}
|
||||
{% endfor %}
|
||||
|
||||
### Нефункциональные требования
|
||||
|
||||
{{ non_functional_requirements_list }}
|
||||
{% for req in non_functional_requirements %}
|
||||
- {{ req }}
|
||||
{% endfor %}
|
||||
|
||||
### Бизнес-контекст
|
||||
|
||||
{{ business_context_list }}
|
||||
{% for item in business_context %}
|
||||
- {{ item }}
|
||||
{% endfor %}
|
||||
|
||||
### Неясные моменты / Вопросы
|
||||
|
||||
{{ open_questions_list }}
|
||||
{% for question in open_questions %}
|
||||
- {{ question }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## 8. Примечания
|
||||
|
||||
|
||||
@@ -38,11 +38,36 @@
|
||||
|
||||
### Сущности
|
||||
|
||||
{{ entity_descriptions }}
|
||||
{% for entity in entities %}
|
||||
### {{ entity.name }}
|
||||
|
||||
| Поле | Тип | Ограничения | Описание |
|
||||
|---|---|---|---|
|
||||
{% for field in entity.fields %}
|
||||
| {{ field.name }} | {{ field.type }} | {{ field.constraints }} | {{ field.description }} |
|
||||
{% endfor %}
|
||||
|
||||
**Связи:** {{ entity.relationships }}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
## 5. API / Интерфейсы
|
||||
|
||||
{{ api_endpoints_table }}
|
||||
{% if has_api %}
|
||||
| Метод | Путь | Описание | Request | Response |
|
||||
|---|---|---|---|---|
|
||||
{% for endpoint in api_endpoints %}
|
||||
| {{ endpoint.method }} | {{ endpoint.path }} | {{ endpoint.description }} | {{ endpoint.request }} | {{ endpoint.response }} |
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if has_gui %}
|
||||
**Экраны:** {{ gui_screens }}
|
||||
{% endif %}
|
||||
|
||||
{% if has_cli %}
|
||||
**Команды:** {{ cli_commands }}
|
||||
{% endif %}
|
||||
|
||||
## 6. Обработка ошибок
|
||||
|
||||
@@ -57,16 +82,31 @@
|
||||
- **Mock-стратегия:** {{ mock_strategy }}
|
||||
- **Команда запуска:** `{{ test_command }}`
|
||||
|
||||
## 8. Дополнительные артефакты (по команде пользователя)
|
||||
## 8. Alternative Architecture (если применимо)
|
||||
|
||||
Если пользователь вызвал соответствующие команды, добавить ссылки:
|
||||
| Критерий | Выбранная архитектура | Альтернатива |
|
||||
|---|---|---|
|
||||
| Название | {{ chosen_arch }} | {{ alt_arch }} |
|
||||
| Сложность | {{ chosen_complexity }} | {{ alt_complexity }} |
|
||||
| Почему не выбрана | — | {{ alt_rejection_reason }} |
|
||||
|
||||
- ADR: `.agent/decisions/` (команда `/adr`)
|
||||
- Alternative Architecture: `.agent/context/alt-architecture.md` (команда `/alt-arch`)
|
||||
- Risk Register: `.agent/context/risk-register.md` (команда `/risk-register`)
|
||||
- Red Team Review: `.agent/context/red-team-report.md` (команда `/red-team`)
|
||||
## 9. ADR Reference (если применимо)
|
||||
|
||||
## 9. Предварительная группировка задач
|
||||
| ID | Решение | Файл |
|
||||
|---|---|---|
|
||||
{% for adr in adr_list %}
|
||||
| {{ adr.id }} | {{ adr.title }} | `{{ adr.path }}` |
|
||||
{% endfor %}
|
||||
|
||||
## 10. Risk Register (если применимо)
|
||||
|
||||
| # | Assumption | Impact | Mitigation |
|
||||
|---|---|---|---|
|
||||
{% for risk in risk_list %}
|
||||
| {{ risk.id }} | {{ risk.assumption }} | {{ risk.impact }} | {{ risk.mitigation }} |
|
||||
{% endfor %}
|
||||
|
||||
## 11. Предварительная группировка задач
|
||||
|
||||
| Задача | Описание | Тип |
|
||||
|---|---|---|
|
||||
@@ -75,6 +115,6 @@
|
||||
| T3 | {{ task_3 }} | feature |
|
||||
| T4 | {{ task_4 }} | test |
|
||||
|
||||
## 10. Примечания
|
||||
## 12. Примечания
|
||||
|
||||
{{ notes }}
|
||||
|
||||
@@ -3,30 +3,43 @@
|
||||
## Session Info
|
||||
|
||||
- **Session ID:** `{{ session_id }}`
|
||||
- **Target Repo:** {{ target_repo }}
|
||||
- **Target Repo:** `{{ target_repo }}`
|
||||
- **Goal:** {{ goal }}
|
||||
- **Date:** {{ date }}
|
||||
- **Project type:** {{ project_type }}
|
||||
- **Duration:** {{ duration }}
|
||||
- **Depth:** {{ depth }}
|
||||
- **Config:** {{ config_summary }}
|
||||
|
||||
## Repo Summary
|
||||
|
||||
{{ repo_summary }}
|
||||
|
||||
## Artifacts Created
|
||||
## Project Type
|
||||
|
||||
- **Analysis report:** `.agent/context/analysis-report.md`
|
||||
- **Project state:** `.agent/context/project-state.md`
|
||||
- **Design report:** {{ design_report_path_or_dash }}
|
||||
- **Roadmap:** `.agent/roadmap/sources.md`
|
||||
- **ADR:** {{ adr_summary_or_dash }}
|
||||
- **Risk Register:** {{ risk_register_path_or_dash }}
|
||||
- **Red Team Report:** {{ red_team_report_path_or_dash }}
|
||||
- **Type:** {{ project_type }}
|
||||
- **Design report:** {% if project_type == "greenfield" or project_type == "scaffold" %}`.agent/design-report.md`{% else %}—{% endif %}
|
||||
|
||||
## ADR Summary (если применимо)
|
||||
|
||||
{% if adr_count > 0 %}
|
||||
Создано ADR: {{ adr_count }}
|
||||
{% for adr in adr_list %}
|
||||
- `{{ adr.path }}` — {{ adr.title }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Risk Register (если применимо)
|
||||
|
||||
{% if risk_count > 0 %}
|
||||
Задокументировано допущений: {{ risk_count }}
|
||||
Наиболее критичное: {{ top_risk }}
|
||||
{% endif %}
|
||||
|
||||
## Environment Status
|
||||
|
||||
- **Build:** {{ build_status }}
|
||||
- **Tests:** {{ tests_passed }}/{{ tests_total }} passed
|
||||
- **Baseline log:** `.agent/context/baseline-test-report.log`
|
||||
- **Baseline log:** `.agent/baseline-test-report.log`
|
||||
- **Dependencies:** {{ deps_status }}
|
||||
|
||||
## Task Overview
|
||||
@@ -37,21 +50,35 @@
|
||||
| Pending | {{ pending }} |
|
||||
| In Progress | {{ in_progress }} |
|
||||
| Completed | {{ completed }} |
|
||||
| Archived | {{ archived }} |
|
||||
| Failed/Skipped | {{ failed }} |
|
||||
|
||||
**Task by type:**
|
||||
{% for type, count in tasks_by_type %}
|
||||
- {{ type }}: {{ count }}
|
||||
{% endfor %}
|
||||
|
||||
## Tasks (ordered)
|
||||
|
||||
{{ task_list_markdown }}
|
||||
{% for task in tasks %}
|
||||
### {{ task.id }}: {{ task.title }}
|
||||
- Type: {{ task.type }}
|
||||
- Depends on: {{ task.depends_on | default("—") }}
|
||||
- Files: {{ task.files | join(", ") }}
|
||||
- Status: {{ task.status }}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
## Next Steps
|
||||
|
||||
Следующий агент: прочитай `.agent/context/project-state.md`, затем `.agent/tasks/manifest.json` и приступай к первой `pending` задаче.
|
||||
Исполнительный агент начинает с задачи **{{ first_task }}**.
|
||||
|
||||
## Caveats
|
||||
|
||||
{{ caveats_list }}
|
||||
{% for caveat in caveats %}
|
||||
- {{ caveat }}
|
||||
{% endfor %}
|
||||
|
||||
## Checkpoints
|
||||
|
||||
Файл: `.agent/checkpoints.json` — состояние фаз и список задач.
|
||||
Файл: `.agent/checkpoints.json`
|
||||
Актуальное состояние чекпоинтов прилагается.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# MetaAgent Request
|
||||
# Для ручного заполнения перед запуском MetaAgent.
|
||||
# Поместите этот файл в .agent/metaagent-request.md целевого репозитория.
|
||||
# Если файл отсутствует — MetaAgent проведёт интервью (PROTOCOLS/00_CONFIG.md).
|
||||
# Ответьте "default" на любой вопрос — будет использовано значение по умолчанию.
|
||||
|
||||
## Параметры сессии
|
||||
|
||||
| Функция | Вкл | Аргументы |
|
||||
|---|---|---|
|
||||
| ANALYSIS | ✓ | — |
|
||||
| DESIGN | ✓ | adr=yes, alternative_arch=yes |
|
||||
| RED_TEAM | ✗ | — |
|
||||
| RISK_REGISTER | ✗ | — |
|
||||
| DECOMPOSITION | ✓ | invariant_tests=yes |
|
||||
| SETUP | ✓ | — |
|
||||
| HANDOFF | ✓ | layer_structure=yes |
|
||||
|
||||
## Глубина проработки
|
||||
|
||||
**Значение:** 6 (1-10)
|
||||
|
||||
| Уровень | Название | Описание |
|
||||
|---|---|---|
|
||||
| 1-2 | Scaffold | Только структура проекта + пустые модули |
|
||||
| 3-4 | Light | (default) Быстрый дизайн + задачи без расширений |
|
||||
| 5-6 | Standard | Полный ANALYSIS→DESIGN→DECOMP→SETUP→HANDOFF |
|
||||
| 7-8 | Deep | Standard + ADR, Risk Register, Alternative Architecture |
|
||||
| 9-10 | Maximum | Deep + Red Team Review, Executable Invariants |
|
||||
|
||||
## Цель
|
||||
|
||||
Сформулируйте задачу для MetaAgent.
|
||||
|
||||
## Дополнительно
|
||||
|
||||
- **Boundaries:** (опционально) ограничения, которые нельзя нарушать
|
||||
- **Target:** путь к репозиторию или URL
|
||||
@@ -1,43 +0,0 @@
|
||||
# Project State
|
||||
# Auto-generated — updated by ANALYSE (initial) and METASTATE (on updates)
|
||||
|
||||
**Last updated:** {{ timestamp }}
|
||||
**Session:** {{ session_id }}
|
||||
|
||||
## Project Type
|
||||
|
||||
{{ project_type }}
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Category | Technology |
|
||||
|----------|-----------|
|
||||
| Language | {{ language }} |
|
||||
| Framework | {{ framework }} |
|
||||
| Database | {{ database }} |
|
||||
| Test runner | {{ test_runner }} |
|
||||
| Package manager | {{ package_manager }} |
|
||||
|
||||
## Current Architecture
|
||||
|
||||
{{ architecture_description }}
|
||||
|
||||
## Key Modules
|
||||
|
||||
| Module | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| {{ module_name }} | {{ existing / stub / new }} | {{ module_description }} |
|
||||
|
||||
## Decisions in Effect
|
||||
|
||||
| ADR | Decision | Status |
|
||||
|-----|----------|--------|
|
||||
| {{ adr_id }} | {{ decision_summary }} | {{ active / superseded }} |
|
||||
|
||||
## Testing Status
|
||||
|
||||
{{ testing_summary }}
|
||||
|
||||
## Open Concerns
|
||||
|
||||
- {{ concern_1 }}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"$schema": ".agent/src/TEMPLATES/schemas/request-schema.json",
|
||||
"template_version": "1.0",
|
||||
"request_id": "req-{{ task_id }}",
|
||||
"task_id": "{{ task_id }}",
|
||||
"title": "{{ task_title }}",
|
||||
"status": "ready_for_review",
|
||||
"created_at": "{{ timestamp }}",
|
||||
"goal": "{{ task_goal }}",
|
||||
|
||||
"changes": {
|
||||
"summary": "{{ changes_summary }}",
|
||||
"commits": [
|
||||
"{{ commit_hash }}"
|
||||
],
|
||||
"files_changed": [
|
||||
"path/to/file.py"
|
||||
]
|
||||
},
|
||||
|
||||
"verification": {
|
||||
"tests_passed": "{{ test_results }}",
|
||||
"lsp_clean": true
|
||||
},
|
||||
|
||||
"fulfills_ac": [
|
||||
"{{ acceptance_criterion }}"
|
||||
]
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
# Roadmap Sources
|
||||
# Auto-generated — created by ROADMAP phase
|
||||
|
||||
**Created:** {{ timestamp }}
|
||||
**Session:** {{ session_id }}
|
||||
|
||||
## Priority Legend
|
||||
|
||||
- **P0** — Critical, do next
|
||||
- **P1** — Important, do soon
|
||||
- **P2** — Nice to have
|
||||
- **P3** — Future / deferred
|
||||
|
||||
## Sources
|
||||
|
||||
### FUTURE Plans
|
||||
|
||||
| Plan | Priority | Status | Origin File |
|
||||
|------|----------|--------|-------------|
|
||||
| {{ plan_title }} | {{ P0-P3 }} | {{ active / archived }} | FUTURE/{{ filename }}.md |
|
||||
|
||||
### ADR-Derived Tasks
|
||||
|
||||
| Source ADR | Task | Priority |
|
||||
|------------|------|----------|
|
||||
| {{ adr_id }} | {{ task_description }} | {{ P0-P3 }} |
|
||||
|
||||
### User Requests
|
||||
|
||||
| Request | Priority | Source |
|
||||
|---------|----------|--------|
|
||||
| {{ request }} | {{ P0-P3 }} | {{ direct / issue / feedback }} |
|
||||
|
||||
### Agent-Identified Improvements
|
||||
|
||||
| Observation | Suggested Task | Priority |
|
||||
|-------------|----------------|----------|
|
||||
| {{ observation }} | {{ task }} | {{ P0-P3 }} |
|
||||
|
||||
## Consolidated Priority Queue
|
||||
|
||||
1. **{{ task_title }}** ({{ origin }}) — {{ priority }}
|
||||
@@ -1,66 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "metaagent/checkpoints/3.0.0",
|
||||
"title": "MetaAgent Checkpoints",
|
||||
"description": "Schema for .agent/checkpoints.json — session state",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metaagent_version": {
|
||||
"type": "string",
|
||||
"description": "MetaAgent version that created this checkpoint",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string",
|
||||
"description": "Unique session identifier"
|
||||
},
|
||||
"target_repo": {
|
||||
"type": "string",
|
||||
"description": "Path to the target repository"
|
||||
},
|
||||
"goal": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Session goal (set by user, may be null until first task)"
|
||||
},
|
||||
"project_type": {
|
||||
"type": ["string", "null"],
|
||||
"enum": [null, "existing", "greenfield", "scaffold"],
|
||||
"description": "Type of the target project (set in ANALYSE phase)"
|
||||
},
|
||||
"phases": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"init": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"analyse": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"roadmap": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"design": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"decomposition": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"execution": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"metastate": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] },
|
||||
"handoff": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "skipped"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"description": "List of tasks (one-liners after archiving)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"title": { "type": "string" },
|
||||
"status": { "type": "string", "enum": ["pending", "in_progress", "completed", "failed", "archived"] }
|
||||
},
|
||||
"required": ["id", "title", "status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"last_updated": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of last update"
|
||||
}
|
||||
},
|
||||
"required": ["metaagent_version", "session_id", "phases", "last_updated"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "metaagent/decisions-index/3.0.0",
|
||||
"title": "MetaAgent Decisions Index",
|
||||
"description": "Schema for .agent/decisions/index.json — machine-readable index of ADRs",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Schema version (3.0 in v3.0+, 2.0 still valid from v2.1)",
|
||||
"enum": ["2.0", "3.0"]
|
||||
},
|
||||
"decisions": {
|
||||
"type": "array",
|
||||
"description": "List of architecture decision records",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{3,}$",
|
||||
"description": "ADR number (001, 002, ...)"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Short title of the decision"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["proposed", "accepted", "deprecated", "superseded"],
|
||||
"description": "ADR status"
|
||||
},
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Filename in .agent/decisions/ (e.g. 001-stack.md)"
|
||||
},
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Decision date (ISO 8601)"
|
||||
}
|
||||
},
|
||||
"required": ["id", "title", "file"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of index creation"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of last update"
|
||||
}
|
||||
},
|
||||
"required": ["version", "decisions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "metaagent/task-manifest/3.0.0",
|
||||
"title": "MetaAgent Task Manifest",
|
||||
"description": "Schema for .agent/tasks/manifest.json — the global task manifest",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Schema version",
|
||||
"enum": ["3.0"]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string",
|
||||
"description": "Session ID that created this manifest"
|
||||
},
|
||||
"goal": {
|
||||
"type": "string",
|
||||
"description": "Overall goal of the session"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of creation"
|
||||
},
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"description": "List of tasks",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^(T[0-9]+|T-INV-[0-9]+)$",
|
||||
"description": "Unique task identifier (T1, T2, ... or T-INV-N for invariants)"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Task title"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Detailed description"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["feature", "refactor", "test", "fix", "config", "design", "docs", "invariant"],
|
||||
"description": "Task type"
|
||||
},
|
||||
"origin": {
|
||||
"type": "string",
|
||||
"description": "Task source (roadmap:file, adr:NNN, user:direct, agent:analysis, decomposition, invariant:NNN, risk:R-NNN)"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Files affected by this task"
|
||||
},
|
||||
"depends_on": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Task IDs this task depends on"
|
||||
},
|
||||
"acceptance_criteria": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Measurable criteria for completion"
|
||||
},
|
||||
"context": {
|
||||
"type": "string",
|
||||
"description": "Additional context or references"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending", "in_progress", "completed", "failed", "archived"],
|
||||
"description": "Current task status"
|
||||
},
|
||||
"claimed_by": {
|
||||
"type": "string",
|
||||
"description": "Worker ID if claimed"
|
||||
},
|
||||
"claimed_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the task was claimed"
|
||||
}
|
||||
},
|
||||
"required": ["id", "title", "type", "status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["version", "tasks"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -2,49 +2,34 @@
|
||||
|
||||
**Session:** {{ session_id }}
|
||||
**Target:** {{ target_repo }}
|
||||
**MetaAgent version:** {{ version }}
|
||||
**Depth:** {{ depth }}
|
||||
**Date:** {{ date }}
|
||||
|
||||
## Configuration
|
||||
|
||||
| Функция | Статус |
|
||||
|---|---|
|
||||
| ADR | {{ adr_enabled }} |
|
||||
| Alternative Architecture | {{ alt_arch_enabled }} |
|
||||
| Red Team | {{ red_team_enabled }} |
|
||||
| Risk Register | {{ risk_register_enabled }} |
|
||||
| Invariant Tests | {{ invariant_tests_enabled }} |
|
||||
| Layer Structure | {{ layer_structure_enabled }} |
|
||||
|
||||
## Phase Status
|
||||
|
||||
| Phase | Status |
|
||||
|---|---|
|
||||
| INIT | {{ init_status }} |
|
||||
| ANALYSE | {{ analyse_status }} |
|
||||
| ROADMAP | {{ roadmap_status }} |
|
||||
| ANALYSIS | {{ analysis_status }} |
|
||||
| DESIGN | {{ design_status }} |
|
||||
| RED_TEAM | {{ red_team_status }} |
|
||||
| DECOMPOSITION | {{ decomposition_status }} |
|
||||
| EXECUTION | {{ execution_status }} |
|
||||
| METASTATE | {{ metastate_status }} |
|
||||
| SETUP | {{ setup_status }} |
|
||||
| HANDOFF | {{ handoff_status }} |
|
||||
|
||||
## Tasks
|
||||
|
||||
| Status | Count |
|
||||
|---|---|
|
||||
| Total | {{ total }} |
|
||||
| Pending | {{ pending }} |
|
||||
| In Progress | {{ in_progress }} |
|
||||
| Completed | {{ completed }} |
|
||||
| Archived | {{ archived }} |
|
||||
| Failed/Skipped | {{ failed }} |
|
||||
|
||||
**By origin:**
|
||||
- user:direct: {{ user_direct_count }}
|
||||
- roadmap: {{ roadmap_count }}
|
||||
- adr: {{ adr_count }}
|
||||
- decomposition: {{ decomposition_count }}
|
||||
- (другое): {{ other_count }}
|
||||
|
||||
## Commands Invoked (если были)
|
||||
|
||||
{{ commands_invoked_list }}
|
||||
|
||||
## Quick Links
|
||||
|
||||
- Task Manifest: `.agent/tasks/manifest.json`
|
||||
- Task Manifest: `.agent/task-manifest.json`
|
||||
- Handoff Summary: `.agent/handoff-summary.md`
|
||||
- Project State: `.agent/context/project-state.md`
|
||||
- ADR: `.agent/decisions/`
|
||||
- Risk Register: `.agent/context/risk-register.md`
|
||||
- Red Team Report: `.agent/context/red-team-report.md`
|
||||
- Design Report: `.agent/analysis-report.md`
|
||||
- ADR: `.agent/layer-1/adr/` (если есть)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": ".agent/src/TEMPLATES/schemas/task-manifest-schema.json",
|
||||
"version": "3.0",
|
||||
"$schema": "metaagent-task-manifest",
|
||||
"version": "1.0",
|
||||
"session_id": "{{ session_id }}",
|
||||
"goal": "{{ goal }}",
|
||||
"created_at": "{{ timestamp }}",
|
||||
@@ -9,8 +9,7 @@
|
||||
"id": "T1",
|
||||
"title": "{{ task_title }}",
|
||||
"description": "{{ task_description }}",
|
||||
"type": "feature|refactor|test|fix|config|design|docs|invariant",
|
||||
"origin": "user:direct",
|
||||
"type": "feature|refactor|test|fix|config|docs",
|
||||
"files": ["path/to/file1.py", "path/to/file2.py"],
|
||||
"depends_on": [],
|
||||
"acceptance_criteria": [
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.0.0
|
||||
1.1.0
|
||||
|
||||
+298
-182
@@ -1,240 +1,356 @@
|
||||
# WORKFLOW — Сквозной пример сессии v3.0
|
||||
# WORKFLOW — Сквозной пример сессии
|
||||
|
||||
---
|
||||
|
||||
## Сценарий: рефакторинг auth-модуля
|
||||
## Сценарий A: Existing проект
|
||||
|
||||
**Цель:** Вынести логику из `auth/login.py` (450 строк, монолит) в отдельные модули `auth/router.py`, `auth/schemas.py`, `auth/deps.py`.
|
||||
**Цель:** Добавить в существующий FastAPI-проект ручку GET /health с тестами.
|
||||
|
||||
**Целевой репозиторий:** `github.com/example/fastapi-app`
|
||||
|
||||
**Пользователь:** «Вынеси авторизацию в отдельные модули».
|
||||
|
||||
**MetaAgent:** v3.0.0
|
||||
**Пользователь:** "Добавь health-check endpoint и тесты к нему"
|
||||
|
||||
---
|
||||
|
||||
### PROJECT LOOP
|
||||
### Фаза INIT
|
||||
|
||||
#### INIT
|
||||
|
||||
Агент читает `AGENTS.md`, переходит в `.agent/src/GUIDE.md`. Понимает цикл. Создаёт `.agent/`, копирует исходники, инициализирует `checkpoints.json`:
|
||||
Мета-агент читает `.agent/metaagent-request.md`, клонирует репозиторий, создаёт `.agent/`, пишет начальный чекпоинт:
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "3.0.0",
|
||||
"session_id": "ses_v30_001",
|
||||
"metaagent_version": "1.1.0",
|
||||
"session_id": "ses_abc123",
|
||||
"target_repo": "/tmp/fastapi-app",
|
||||
"goal": "Вынести авторизацию в auth/{router,schemas,deps}.py",
|
||||
"project_type": null,
|
||||
"goal": "Добавить GET /health с тестами",
|
||||
"project_type": "existing",
|
||||
"config": {
|
||||
"depth": 6,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
},
|
||||
"phases": {
|
||||
"init": "completed",
|
||||
"analyse": "pending",
|
||||
"roadmap": "pending",
|
||||
"analysis": "pending",
|
||||
"design": "pending",
|
||||
"red_team": "pending",
|
||||
"decomposition": "pending",
|
||||
"execution": "pending",
|
||||
"metastate": "pending",
|
||||
"environment": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [],
|
||||
"last_updated": "2026-10-08T15:00:00Z"
|
||||
"last_updated": "2026-07-12T15:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### ANALYSE
|
||||
|
||||
Агент сканирует проект:
|
||||
|
||||
- Стек: Python 3.12, FastAPI, SQLAlchemy, pytest.
|
||||
- `auth/login.py` — 450 строк, монолит (цель рефакторинга).
|
||||
- Тесты: 48 passed (baseline).
|
||||
|
||||
Создаёт:
|
||||
|
||||
- `.agent/context/analysis-report.md`
|
||||
- `.agent/context/project-state.md` (начальный)
|
||||
|
||||
`checkpoints.json`: `project_type = "existing"`, `phases.analyse = "completed"`.
|
||||
|
||||
#### ROADMAP
|
||||
|
||||
- `FUTURE/` — пусто.
|
||||
- `.agent/decisions/` — пусто.
|
||||
- Единственный источник — пользовательский запрос.
|
||||
|
||||
Создаёт `.agent/roadmap/sources.md`:
|
||||
|
||||
```markdown
|
||||
## User Requests
|
||||
| Вынести авторизацию | P0 | user:direct |
|
||||
|
||||
## Consolidated Priority Queue
|
||||
1. Вынести auth/ (user:direct) — P0
|
||||
```
|
||||
|
||||
`phases.roadmap = "completed"`.
|
||||
|
||||
#### DESIGN
|
||||
|
||||
**Пропускается** (existing-проект). `phases.design = "skipped"`.
|
||||
|
||||
#### DECOMPOSITION
|
||||
|
||||
Задачи:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T1",
|
||||
"title": "Создать auth/router.py",
|
||||
"origin": "user:direct",
|
||||
"files": ["app/auth/router.py"],
|
||||
"depends_on": [],
|
||||
"acceptance_criteria": [
|
||||
"Роуты авторизации вынесены из auth/login.py",
|
||||
"auth/router.py экспортирует router",
|
||||
"Существующие тесты проходят"
|
||||
],
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"id": "T2",
|
||||
"title": "Создать auth/schemas.py",
|
||||
"origin": "user:direct",
|
||||
"files": ["app/auth/schemas.py"],
|
||||
"depends_on": ["T1"],
|
||||
"acceptance_criteria": [
|
||||
"Pydantic схемы вынесены в auth/schemas.py",
|
||||
"Существующие тесты проходят"
|
||||
],
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"id": "T3",
|
||||
"title": "Создать auth/deps.py",
|
||||
"origin": "user:direct",
|
||||
"files": ["app/auth/deps.py"],
|
||||
"depends_on": ["T1"],
|
||||
"acceptance_criteria": [
|
||||
"Dependency injection функции вынесены в auth/deps.py",
|
||||
"Существующие тесты проходят"
|
||||
],
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`phases.decomposition = "completed"`.
|
||||
|
||||
---
|
||||
|
||||
### WORK LOOP (первая итерация)
|
||||
### Фаза ANALYSE
|
||||
|
||||
#### EXECUTION — задача T1
|
||||
Мета-агент выполняет `PROTOCOLS/01_ANALYSIS.md`. Определяет тип проекта: `existing`.
|
||||
|
||||
1. Берёт T1 (`pending`, нет зависимостей).
|
||||
2. `status = "in_progress"`.
|
||||
3. Создаёт `app/auth/router.py` — переносит роуты.
|
||||
4. Тесты: 48/48.
|
||||
5. Коммит: `abc1234 — refactor: extract auth router`.
|
||||
6. Создаёт request:
|
||||
Результат `.agent/analysis-report.md`:
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id": "req-T1",
|
||||
"task_id": "T1",
|
||||
"title": "Создать auth/router.py",
|
||||
"status": "ready_for_review",
|
||||
"goal": "Вынести роуты авторизации",
|
||||
"changes": {
|
||||
"summary": "Роуты авторизации вынесены из auth/login.py в auth/router.py",
|
||||
"commits": ["abc1234"],
|
||||
"files_changed": ["app/auth/router.py", "app/auth/__init__.py", "tests/test_auth_router.py"]
|
||||
},
|
||||
"verification": { "tests_passed": "48/48", "lsp_clean": true },
|
||||
"fulfills_ac": ["Роуты вынесены", "Тесты проходят"]
|
||||
}
|
||||
```markdown
|
||||
## 2. Стек технологий
|
||||
| Язык | Python 3.12 |
|
||||
| Фреймворк | FastAPI |
|
||||
| Тестовый раннер | pytest + httpx |
|
||||
| Пакетный менеджер | pip + requirements.txt |
|
||||
|
||||
## 3. Архитектура
|
||||
├── app/
|
||||
│ ├── main.py
|
||||
│ ├── routers/
|
||||
│ │ └── users.py
|
||||
│ ├── models/
|
||||
│ │ └── user.py
|
||||
│ └── schemas/
|
||||
│ └── user.py
|
||||
├── tests/
|
||||
│ └── test_users.py
|
||||
```
|
||||
|
||||
7. `T1 → completed`.
|
||||
Тесты запущены: **12 passed, 0 failed**.
|
||||
|
||||
#### EXECUTION — задача T2
|
||||
|
||||
Создаёт `auth/schemas.py`, request `req-T2`. T2 → completed.
|
||||
|
||||
#### EXECUTION — задача T3
|
||||
|
||||
Создаёт `auth/deps.py`, request `req-T3`. T3 → completed.
|
||||
|
||||
Задачи закончились. Агент ждёт команду.
|
||||
Чекпоинт обновлён: `analysis = "completed"`, `project_type = "existing"`.
|
||||
Фаза DESIGN пропускается.
|
||||
|
||||
---
|
||||
|
||||
### METASTATE (по команде пользователя)
|
||||
### Фаза DECOMPOSITION
|
||||
|
||||
**Пользователь:** «обнови метасостояние».
|
||||
Мета-агент выполняет `PROTOCOLS/03_DECOMPOSITION.md`.
|
||||
|
||||
1. **Ревью requests:** три request-а, все approved.
|
||||
- `req-T1`, `req-T2`, `req-T3` → `.agent/requests/archive/`.
|
||||
Декомпозиция цели "Добавить GET /health с тестами":
|
||||
|
||||
2. **Архивация задач:**
|
||||
- T1, T2, T3 → `.agent/archive/tasks/`.
|
||||
- В `manifest.json` — one-liner: `status: "archived"`.
|
||||
| ID | Задача | Тип | Зависит от | AC |
|
||||
|---|---|---|---|---|
|
||||
| T1 | Создать health-check router | feature | — | Ручка возвращает 200 + {"status":"ok"} |
|
||||
| T2 | Подключить router в main.py | config | T1 | Ручка доступна по /health |
|
||||
| T3 | Написать тесты для /health | test | T2 | Тесты проверяют 200 и структуру ответа |
|
||||
|
||||
3. **Обновление project-state.md:**
|
||||
Создан `.agent/task-manifest.json` и `.agent/task-manifest.md`.
|
||||
|
||||
Чекпоинт обновлён: `decomposition = "completed"`. Tasks: T1-T3 со статусом `pending`.
|
||||
|
||||
---
|
||||
|
||||
### Фаза SETUP
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/04_ENVIRONMENT_SETUP.md` (ветка A: existing).
|
||||
|
||||
- `pip install -r requirements.txt` — OK
|
||||
- Запуск pytest — OK, 12 passed (базовый тест)
|
||||
- Результат в `.agent/baseline-test-report.log`
|
||||
|
||||
Чекпоинт обновлён: `environment = "completed"`.
|
||||
|
||||
---
|
||||
|
||||
### Фаза HANDOFF
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/05_HANDOFF.md`.
|
||||
|
||||
Создан `.agent/handoff-summary.md`:
|
||||
|
||||
```markdown
|
||||
## Key Modules
|
||||
| Module | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| app/auth/router.py | new | Вынесенные роуты |
|
||||
| app/auth/schemas.py | new | Pydantic схемы |
|
||||
| app/auth/deps.py | new | Dependency injection |
|
||||
```
|
||||
|
||||
4. **Создание handoff-summary.md:**
|
||||
|
||||
```markdown
|
||||
## Session Summary
|
||||
**Goal:** Рефакторинг авторизации
|
||||
**Completed:** 3/3 tasks
|
||||
**Approved requests:** req-T1, req-T2, req-T3
|
||||
|
||||
## Project State
|
||||
auth разбит на router + schemas + deps.
|
||||
Исходный auth/login.py: 450 → 120 строк.
|
||||
|
||||
## Next Steps
|
||||
- Проверить, не осталось ли прямых импортов из старого login.py
|
||||
- Обновить main.py если нужно
|
||||
Исполнительный агент начинает с задачи T1: "Создать health-check router".
|
||||
|
||||
## Caveats
|
||||
- Придерживаться стиля существующего роутера users.py
|
||||
- Не менять существующие тесты
|
||||
- Убедиться, что response model соответствует JSON: {"status": "ok"}
|
||||
```
|
||||
|
||||
---
|
||||
Чекпоинт финализирован:
|
||||
|
||||
### HANDOFF
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "1.1.0",
|
||||
"session_id": "ses_abc123",
|
||||
"goal": "Добавить GET /health с тестами",
|
||||
"project_type": "existing",
|
||||
"config": {
|
||||
"depth": 6,
|
||||
"design": { "adr": false, "alternative_arch": false },
|
||||
"red_team": false,
|
||||
"risk_register": false,
|
||||
"decomposition": { "invariant_tests": false },
|
||||
"handoff": { "layer_structure": false }
|
||||
},
|
||||
"phases": {
|
||||
"analysis": "completed",
|
||||
"design": "skipped",
|
||||
"red_team": "skipped",
|
||||
"decomposition": "completed",
|
||||
"environment": "completed",
|
||||
"handoff": "completed"
|
||||
},
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "Создать health-check router", "status": "pending" },
|
||||
{ "id": "T2", "title": "Подключить router в main.py", "status": "pending" },
|
||||
{ "id": "T3", "title": "Написать тесты для /health", "status": "pending" }
|
||||
],
|
||||
"last_updated": "2026-07-12T15:15:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Сигнал пользователю:
|
||||
|
||||
```
|
||||
HANDOFF COMPLETE
|
||||
|
||||
Session: ses_v30_001
|
||||
Session: ses_abc123
|
||||
Target: /tmp/fastapi-app
|
||||
Type: existing
|
||||
Tasks: 3/3 completed
|
||||
Tasks: 3 tasks ready
|
||||
|
||||
Следующий агент начинает с .agent/handoff-summary.md
|
||||
Исполнительный агент может начинать с задачи T1.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Использование команд в процессе
|
||||
## Сценарий B: Greenfield проект (Cashflow Forecasting)
|
||||
|
||||
В любой момент сессии пользователь мог вызвать:
|
||||
**Цель:** Спроектировать и реализовать MVP сервиса прогнозирования денежных потоков.
|
||||
|
||||
- **«запиши это как ADR»** → `COMMANDS/adr.md` создал бы `.agent/decisions/001-modular-auth.md`.
|
||||
- **«red team»** → `COMMANDS/red-team.md` создал бы `.agent/context/red-team-report.md` с попыткой сломать новую структуру.
|
||||
- **«risk register»** → `COMMANDS/risk-register.md` зафиксировал бы допущения (например, «считаем, что порядок middleware не важен»).
|
||||
**Целевой репозиторий:** `github.com/example/cashflow-app`
|
||||
|
||||
Команды **не обязательны**. Если не вызваны — `.agent/decisions/`, `risk-register.md`, `red-team-report.md` не создаются.
|
||||
**README:** README содержит описание:
|
||||
> Сервис для прогнозирования движения денежных средств (cashflow forecasting).
|
||||
> Пользователь загружает CSV с транзакциями, сервис строит прогноз на N дней вперёд.
|
||||
> Стек: Python, FastAPI, SQLite, matplotlib для графиков.
|
||||
|
||||
---
|
||||
|
||||
### Фаза INIT
|
||||
|
||||
```json
|
||||
{
|
||||
"metaagent_version": "1.1.0",
|
||||
"session_id": "ses_def456",
|
||||
"target_repo": "/tmp/cashflow-app",
|
||||
"goal": "Спроектировать и реализовать MVP сервиса прогнозирования денежных потоков",
|
||||
"project_type": "greenfield",
|
||||
"config": {
|
||||
"depth": 7,
|
||||
"design": { "adr": true, "alternative_arch": true },
|
||||
"red_team": false,
|
||||
"risk_register": true,
|
||||
"decomposition": { "invariant_tests": true },
|
||||
"handoff": { "layer_structure": true }
|
||||
},
|
||||
"phases": {
|
||||
"analysis": "pending",
|
||||
"design": "pending",
|
||||
"red_team": "pending",
|
||||
"decomposition": "pending",
|
||||
"environment": "pending",
|
||||
"handoff": "pending"
|
||||
},
|
||||
"tasks": [],
|
||||
"last_updated": "2026-07-12T16:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Фаза ANALYSE
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/01_ANALYSIS.md`. Определяет тип проекта: `greenfield`.
|
||||
|
||||
Сканирование корня: пусто (кроме README.md, LICENSE, .gitignore).
|
||||
|
||||
Извлечение требований из README:
|
||||
|
||||
| Тип | Требование |
|
||||
|---|---|
|
||||
| Функциональное | Загрузка CSV с транзакциями |
|
||||
| Функциональное | Прогноз на N дней вперёд |
|
||||
| Нефункциональное | Python, FastAPI |
|
||||
| Нефункциональное | SQLite |
|
||||
| Нефункциональное | matplotlib для графиков |
|
||||
|
||||
Чекпоинт: `analysis = "completed"`, `project_type = "greenfield"`.
|
||||
|
||||
Так как проект greenfield — мета-агент переходит к фазе DESIGN.
|
||||
|
||||
---
|
||||
|
||||
### Фаза DESIGN
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/02_DESIGN.md`.
|
||||
|
||||
Результат `.agent/design-report.md`:
|
||||
|
||||
```markdown
|
||||
## 1. Технологический стек
|
||||
| Язык | Python 3.12 |
|
||||
| Фреймворк | FastAPI + Pydantic |
|
||||
| БД | SQLite + SQLAlchemy |
|
||||
| Визуализация | matplotlib |
|
||||
| Тесты | pytest |
|
||||
|
||||
## 2. Архитектура
|
||||
[Client] → HTTP → [FastAPI] → [CashflowService] → [SQLite]
|
||||
↓
|
||||
[ForecastEngine] → [matplotlib]
|
||||
|
||||
## 3. Модули
|
||||
| Модуль | Ответственность |
|
||||
|---|---|
|
||||
| app/main.py | Точка входа, роуты |
|
||||
| app/models/transaction.py | Модель транзакции |
|
||||
| app/services/cashflow.py | Бизнес-логика |
|
||||
| app/services/forecast.py | Алгоритм прогноза |
|
||||
| app/services/upload.py | Парсинг CSV |
|
||||
| app/schemas/ | Pydantic схемы |
|
||||
|
||||
## 4. Модели
|
||||
Transaction: id, date, amount, category, description
|
||||
|
||||
## 5. API
|
||||
POST /upload — загрузить CSV
|
||||
GET /forecast?days=30 — прогноз + график
|
||||
|
||||
## 6. Задачи (pre-grouped)
|
||||
T1: init — проект, зависимости, scaffold
|
||||
T2: models — модели + миграции
|
||||
T3: upload — загрузка CSV
|
||||
T4: forecast — алгоритм прогноза
|
||||
T5: API — endpoints
|
||||
T6: tests — тесты
|
||||
```
|
||||
|
||||
Чекпоинт: `design = "completed"`.
|
||||
|
||||
---
|
||||
|
||||
### Фаза DECOMPOSITION
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/03_DECOMPOSITION.md`, используя design-report.
|
||||
|
||||
Итоговые задачи:
|
||||
|
||||
| ID | Задача | Тип | Зависит от |
|
||||
|---|---|---|---|
|
||||
| T1 | Инициализация проекта + зависимости | config | — |
|
||||
| T2 | Модель Transaction + SQLAlchemy + SQLite | feature | T1 |
|
||||
| T3 | Сервис загрузки и парсинга CSV | feature | T2 |
|
||||
| T4 | ForecastEngine — алгоритм прогноза | feature | T2 |
|
||||
| T5 | API endpoints + документация | feature | T3, T4 |
|
||||
| T6 | Тесты (unit + integration) | test | T5 |
|
||||
|
||||
---
|
||||
|
||||
### Фаза SETUP
|
||||
|
||||
Мета-агент выполняет `PROTOCOLS/04_ENVIRONMENT_SETUP.md` (ветка B: greenfield).
|
||||
|
||||
- `poetry init` + создание pyproject.toml
|
||||
- Установка fastapi, uvicorn, sqlalchemy, matplotlib, pytest
|
||||
- Создание scaffold-структуры: `app/models/`, `app/services/`, `app/schemas/`, `tests/`
|
||||
- Пустые заглушки модулей
|
||||
- `.agent/baseline-test-report.log`: "0 tests — greenfield, scaffold готов"
|
||||
|
||||
---
|
||||
|
||||
### Фаза HANDOFF
|
||||
|
||||
```markdown
|
||||
HANDOFF COMPLETE
|
||||
Session: ses_def456
|
||||
Target: /tmp/cashflow-app
|
||||
Type: greenfield
|
||||
Config: depth=7, adr=yes, risk_register=yes, invariant_tests=yes
|
||||
Tasks: 6 tasks ready
|
||||
|
||||
Исполнительный агент может начинать с задачи T1 (init).
|
||||
Архитектурный план: .agent/design-report.md
|
||||
ADR: .agent/layer-1/adr/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## После HANDOFF: работа исполнительного агента
|
||||
|
||||
Исполнительный агент читает `.agent/handoff-summary.md`, `.agent/task-manifest.json`, выполняет задачи по порядку, обновляя checkpoints.json после каждой.
|
||||
|
||||
После завершения всех задач:
|
||||
|
||||
```
|
||||
ALL TASKS COMPLETE
|
||||
Session: ses_def456
|
||||
Tasks: 6/6 completed
|
||||
|
||||
T1: Инициализация проекта ✓
|
||||
T2: Модель Transaction ✓
|
||||
T3: Сервис загрузки CSV ✓
|
||||
T4: ForecastEngine ✓
|
||||
T5: API endpoints ✓
|
||||
T6: Тесты ✓
|
||||
|
||||
Все тесты проходят: 24/24 passed.
|
||||
```
|
||||
|
||||
+72
-274
@@ -1,45 +1,29 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# MetaAgent — установка исходников в целевой проект
|
||||
# Usage: .\install.ps1 [[-Path] target_path] [-Check] [-Update]
|
||||
# Usage: .\install.ps1 [[-Path] target_path] [-Update]
|
||||
|
||||
param(
|
||||
[string]$Path = "",
|
||||
[switch]$Check,
|
||||
[switch]$Update,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$MetaAgentSrc = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# --- helpers ---
|
||||
function Write-Info { Write-Host " →" -NoNewline -ForegroundColor Blue; Write-Host " $args" }
|
||||
function Write-Ok { Write-Host " ✓" -NoNewline -ForegroundColor Green; Write-Host " $args" }
|
||||
function Write-Skip { Write-Host " −" -NoNewline -ForegroundColor Yellow; Write-Host " $args" }
|
||||
function Write-Warn { Write-Host " ⚠" -NoNewline -ForegroundColor Yellow; Write-Host " $args" }
|
||||
function Write-Fail { Write-Host " ✗" -NoNewline -ForegroundColor Red; Write-Host " $args" }
|
||||
function Write-Header { param([string]$Label)
|
||||
Write-Host ""
|
||||
Write-Host ("─" * 40)
|
||||
Write-Host " $Label"
|
||||
Write-Host ("─" * 40)
|
||||
}
|
||||
|
||||
function Show-Usage {
|
||||
@"
|
||||
Usage: install.ps1 [[-Path] target_path] [-Check] [-Update] [-Help]
|
||||
Usage: install.ps1 [[-Path] target_path] [-Update] [-Help]
|
||||
|
||||
Install MetaAgent sources into <target>/.agent/src/
|
||||
|
||||
Options:
|
||||
-Path Path to target project (default: interactive prompt)
|
||||
-Check Dry-run: only check target readiness, no install
|
||||
-Update Overwrite existing files in .agent/src/
|
||||
-Help Show this help
|
||||
|
||||
Examples:
|
||||
.\install.ps1
|
||||
.\install.ps1 -Path C:\Projects\MyApp
|
||||
.\install.ps1 -Path C:\Projects\MyApp -Check
|
||||
.\install.ps1 -Path C:\Projects\MyApp -Update
|
||||
"@
|
||||
exit 0
|
||||
@@ -47,319 +31,133 @@ Examples:
|
||||
|
||||
if ($Help) { Show-Usage }
|
||||
|
||||
# --- resolve target ---
|
||||
$TargetPath = $Path
|
||||
if (-not $TargetPath) {
|
||||
$TargetPath = Read-Host "Enter path to target project"
|
||||
}
|
||||
|
||||
$TargetPath = $TargetPath.Trim()
|
||||
|
||||
# --- pre-flight -----------------------------------------------------------
|
||||
Write-Header "Pre-flight"
|
||||
|
||||
# 1. target exists?
|
||||
if (-not (Test-Path $TargetPath -PathType Container)) {
|
||||
Write-Fail "Target directory '$TargetPath' does not exist."
|
||||
Write-Error "Directory '$TargetPath' does not exist."
|
||||
exit 1
|
||||
}
|
||||
$TargetPath = (Resolve-Path $TargetPath).Path
|
||||
Write-Ok "Target: $TargetPath"
|
||||
|
||||
# 2. write permission? (try to create a temp file as probe)
|
||||
$probe = [System.IO.Path]::Combine($TargetPath, ".metaagent_probe.tmp")
|
||||
try {
|
||||
[System.IO.File]::WriteAllBytes($probe, [byte[]]@())
|
||||
Remove-Item $probe -Force
|
||||
Write-Ok "Write permission: yes"
|
||||
} catch {
|
||||
Write-Fail "No write permission on '$TargetPath'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 3. already installed? compare versions
|
||||
$AgentDir = Join-Path $TargetPath ".agent"
|
||||
$SrcDir = Join-Path $AgentDir "src"
|
||||
$VersionFile = Join-Path $MetaAgentSrc "VERSION"
|
||||
|
||||
$Version = if (Test-Path $VersionFile -PathType Leaf) {
|
||||
(Get-Content $VersionFile -Raw -Encoding UTF8).Trim()
|
||||
} else { "?" }
|
||||
|
||||
$oldVerPath = Join-Path $SrcDir "VERSION"
|
||||
if (Test-Path $oldVerPath -PathType Leaf) {
|
||||
$oldVer = (Get-Content $oldVerPath -Raw -Encoding UTF8).Trim()
|
||||
if ($oldVer -ne $Version) {
|
||||
Write-Info "Existing MetaAgent v$oldVer found → upgrading to v$Version"
|
||||
} else {
|
||||
Write-Skip "MetaAgent v${Version} already installed (use -Update to reinstall)"
|
||||
if (-not $Check) {
|
||||
Write-Warn "No changes applied. Run with -Update to overwrite existing files."
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Info "Fresh install: MetaAgent v$Version"
|
||||
}
|
||||
|
||||
# 4. summary
|
||||
$AgentsMd = Join-Path $TargetPath "AGENTS.md"
|
||||
$RulesDir = Join-Path $AgentDir "rules"
|
||||
$DecisionsDir = Join-Path $AgentDir "decisions"
|
||||
$TasksDir = Join-Path $AgentDir "tasks"
|
||||
$ContextDir = Join-Path $AgentDir "context"
|
||||
$ArchiveDir = Join-Path $AgentDir "archive"
|
||||
$RequestsDir = Join-Path $AgentDir "requests"
|
||||
$RoadmapDir = Join-Path $AgentDir "roadmap"
|
||||
$TempDir = Join-Path $TargetPath ".temp"
|
||||
$VersionFile = Join-Path $MetaAgentSrc "VERSION"
|
||||
$Version = if (Test-Path $VersionFile) { Get-Content $VersionFile -Raw | ForEach-Object { $_.Trim() } } else { "?" }
|
||||
|
||||
$DirList = @(
|
||||
$SrcDir, $RulesDir, $DecisionsDir, $TasksDir,
|
||||
(Join-Path $TasksDir "backlog"), $ContextDir,
|
||||
$ArchiveDir,
|
||||
(Join-Path $ArchiveDir "tasks"),
|
||||
(Join-Path $ArchiveDir "decisions"),
|
||||
(Join-Path $ArchiveDir "checkpoints"),
|
||||
(Join-Path $RequestsDir "active"),
|
||||
(Join-Path $RequestsDir "archive"),
|
||||
$RoadmapDir,
|
||||
(Join-Path $RoadmapDir "archive"),
|
||||
$TempDir
|
||||
)
|
||||
|
||||
if ($Check) {
|
||||
Write-Host ""
|
||||
Write-Info "--check mode: all checks passed, no changes applied."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- phase 1: directories ------------------------------------------------
|
||||
Write-Header "Directories"
|
||||
|
||||
foreach ($d in $DirList) {
|
||||
$null = New-Item -ItemType Directory -Path $d -Force
|
||||
$short = $d.Replace("$TargetPath\", "")
|
||||
if (Test-Path $d -PathType Container) {
|
||||
Write-Ok $short
|
||||
} else {
|
||||
Write-Fail "$short (creation failed)"
|
||||
}
|
||||
}
|
||||
|
||||
# --- phase 2: files ------------------------------------------------------
|
||||
Write-Header "Files"
|
||||
|
||||
$copyCount = 0
|
||||
$skipCount = 0
|
||||
$failCount = 0
|
||||
New-Item -ItemType Directory -Path $SrcDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $RulesDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $ArchiveDir -Force | Out-Null
|
||||
Write-Host "Installing MetaAgent v$Version → $SrcDir"
|
||||
|
||||
# --- copy files ---
|
||||
function Copy-File {
|
||||
param([string]$Src, [string]$DstDir)
|
||||
$name = Split-Path $Src -Leaf
|
||||
$dst = Join-Path $DstDir $name
|
||||
if (-not (Test-Path $Src -PathType Leaf)) {
|
||||
Write-Skip "$name (source not found)"
|
||||
$script:skipCount++
|
||||
Write-Host " [skip] $name (not found)"
|
||||
return
|
||||
}
|
||||
$dst = Join-Path $DstDir $name
|
||||
if ($Update -or -not (Test-Path $dst)) {
|
||||
try {
|
||||
Copy-Item $Src $dst -Force -ErrorAction Stop
|
||||
Write-Ok $name
|
||||
$script:copyCount++
|
||||
} catch {
|
||||
Write-Fail $name
|
||||
$script:failCount++
|
||||
}
|
||||
Copy-Item $Src $dst -Force
|
||||
Write-Host " [copy] $name"
|
||||
} else {
|
||||
Write-Skip "$name (exists, use -Update to overwrite)"
|
||||
$script:skipCount++
|
||||
Write-Host " [skip] $name (exists, use -Update to overwrite)"
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-Dir {
|
||||
param([string]$Src, [string]$DstDir)
|
||||
$name = Split-Path $Src -Leaf
|
||||
$dst = Join-Path $DstDir $name
|
||||
if (-not (Test-Path $Src -PathType Container)) {
|
||||
Write-Skip "$name/ (source not found)"
|
||||
$script:skipCount++
|
||||
Write-Host " [skip] $name/ (not found)"
|
||||
return
|
||||
}
|
||||
$null = New-Item -ItemType Directory -Path $dst -Force
|
||||
try {
|
||||
$dst = Join-Path $DstDir $name
|
||||
New-Item -ItemType Directory -Path $dst -Force | Out-Null
|
||||
if ($Update) {
|
||||
Get-ChildItem $Src | ForEach-Object {
|
||||
Copy-Item $_.FullName $dst -Recurse -Force -ErrorAction Stop
|
||||
Copy-Item $_.FullName $dst -Recurse -Force
|
||||
}
|
||||
} else {
|
||||
Get-ChildItem $Src | ForEach-Object {
|
||||
$targetPath = Join-Path $dst $_.Name
|
||||
if (-not (Test-Path $targetPath)) {
|
||||
Copy-Item $_.FullName $dst -Recurse -ErrorAction Stop
|
||||
Copy-Item $_.FullName $dst -Recurse
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Ok "$name/"
|
||||
$script:copyCount++
|
||||
} catch {
|
||||
Write-Fail "$name/ (partial copy)"
|
||||
$script:failCount++
|
||||
}
|
||||
Write-Host " [copy] $name/"
|
||||
}
|
||||
|
||||
Copy-File (Join-Path $MetaAgentSrc "GUIDE.md") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "META_AGENT_GUIDE.md") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "BOUNDARIES.md") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "CHANGELOG.md") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "WORKFLOW.md") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "VERSION") $SrcDir
|
||||
Copy-Dir (Join-Path $MetaAgentSrc "PROTOCOLS") $SrcDir
|
||||
Copy-Dir (Join-Path $MetaAgentSrc "COMMANDS") $SrcDir
|
||||
Copy-Dir (Join-Path $MetaAgentSrc "TEMPLATES") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "install.sh") $SrcDir
|
||||
Copy-File (Join-Path $MetaAgentSrc "install.ps1") $SrcDir
|
||||
|
||||
# --- phase 3: AGENTS.md --------------------------------------------------
|
||||
Write-Header "AGENTS.md"
|
||||
# --- create / update AGENTS.md in root of target ---
|
||||
$AgentsMd = Join-Path $TargetPath "AGENTS.md"
|
||||
|
||||
function New-AgentsMd {
|
||||
param([string]$Path)
|
||||
@"
|
||||
# MetaAgent
|
||||
|
||||
Этот проект использует [MetaAgent](.agent/src/META_AGENT_GUIDE.md) v$Version —
|
||||
набор инструкций для AI-агента.
|
||||
|
||||
## Контекст MetaAgent
|
||||
|
||||
| Ресурс | Путь |
|
||||
|--------|------|
|
||||
| Главная инструкция | `.agent/src/META_AGENT_GUIDE.md` |
|
||||
| Протоколы фаз | `.agent/src/PROTOCOLS/` |
|
||||
| Шаблоны артефактов | `.agent/src/TEMPLATES/` |
|
||||
| Границы (что разрешено/запрещено) | `.agent/src/BOUNDARIES.md` |
|
||||
| Правила проекта | `.agent/rules/project-rules.md` |
|
||||
| Примеры работы | `.agent/src/WORKFLOW.md` |
|
||||
| Версия | `.agent/src/VERSION` |
|
||||
|
||||
## Состояние сессии (если инициализировано)
|
||||
|
||||
| Артефакт | Путь |
|
||||
|----------|------|
|
||||
| Чекпоинты сессии | `.agent/checkpoints.json` |
|
||||
| Манифест задач | `.agent/task-manifest.json` |
|
||||
| Сводка для exec-агента | `.agent/handoff-summary.md` |
|
||||
| Анализ репозитория | `.agent/analysis-report.md` |
|
||||
|
||||
## Для исполнительного агента
|
||||
|
||||
1. **Прочитай** `.agent/src/META_AGENT_GUIDE.md` — пойми жизненный цикл MetaAgent.
|
||||
2. **Прочитай** `.agent/src/BOUNDARIES.md` — соблюдай границы.
|
||||
3. **Прочитай** `.agent/rules/project-rules.md` — выполни пользовательские правила.
|
||||
4. **Проверь** `.agent/checkpoints.json` — если существует, используй как состояние сессии.
|
||||
5. **Проверь** `.agent/task-manifest.json` — если существует, выполняй задачи по порядку.
|
||||
6. Если `.agent/` не инициализирован или устарел — запусти `install.ps1 -Update` для
|
||||
обновления исходников MetaAgent до актуальной версии.
|
||||
"@
|
||||
}
|
||||
|
||||
if (-not (Test-Path $AgentsMd -PathType Leaf)) {
|
||||
$content = @"
|
||||
# MetaAgent
|
||||
|
||||
Этот проект использует [MetaAgent](.agent/src/GUIDE.md) v$Version —
|
||||
набор инструкций для AI-агента.
|
||||
|
||||
## Контекст MetaAgent
|
||||
|
||||
| Ресурс | Путь |
|
||||
|--------|------|
|
||||
| Главная инструкция | `.agent/src/GUIDE.md` |
|
||||
| Протоколы фаз | `.agent/src/PROTOCOLS/` |
|
||||
| Команды (on-demand) | `.agent/src/COMMANDS/` |
|
||||
| Шаблоны артефактов | `.agent/src/TEMPLATES/` |
|
||||
| Границы (что разрешено/запрещено) | `.agent/src/BOUNDARIES.md` |
|
||||
| История версий | `.agent/src/CHANGELOG.md` |
|
||||
| Правила проекта | `.agent/rules/project-rules.md` |
|
||||
| Пример работы | `.agent/src/WORKFLOW.md` |
|
||||
| Версия | `.agent/src/VERSION` |
|
||||
|
||||
## Состояние сессии (если инициализировано)
|
||||
|
||||
| Артефакт | Путь |
|
||||
|----------|------|
|
||||
| Чекпоинты сессии | `.agent/checkpoints.json` |
|
||||
| Слепок проекта | `.agent/context/project-state.md` |
|
||||
| Анализ репозитория | `.agent/context/analysis-report.md` |
|
||||
| Дорожная карта | `.agent/roadmap/sources.md` |
|
||||
| Манифест задач | `.agent/tasks/manifest.json` |
|
||||
| Сводка для следующего агента | `.agent/handoff-summary.md` |
|
||||
| Сводка сессии | `.agent/session-summary.md` |
|
||||
|
||||
## Для агента
|
||||
|
||||
Жизненный цикл MetaAgent v$Version:
|
||||
|
||||
```
|
||||
INIT → ANALYSE → ROADMAP → [DESIGN] → DECOMPOSITION → EXECUTION → METASTATE → HANDOFF
|
||||
```
|
||||
|
||||
1. **Прочитай** `.agent/src/GUIDE.md` — пойми цикл и доступные команды.
|
||||
2. **Прочитай** `.agent/src/BOUNDARIES.md` — соблюдай границы.
|
||||
3. **Прочитай** `.agent/rules/project-rules.md` — выполни правила пользователя.
|
||||
4. **Проверь** `.agent/checkpoints.json` — если существует, используй как состояние сессии.
|
||||
5. **Проверь** `.agent/context/project-state.md` — получи актуальную картину.
|
||||
6. **Проверь** `.agent/tasks/manifest.json` — если существует, выполняй задачи по порядку.
|
||||
7. Если `.agent/` не инициализирован или устарел — запусти `install.sh --update` для
|
||||
обновления исходников MetaAgent до актуальной версии.
|
||||
|
||||
## Команды (on-demand)
|
||||
|
||||
В любой момент пользователь может вызвать:
|
||||
- `/adr` — записать архитектурное решение
|
||||
- `/red-team` — попытаться сломать дизайн
|
||||
- `/risk-register` — зафиксировать допущения
|
||||
- `/alt-arch` — описать альтернативу
|
||||
- `/invariant-tests` — тесты-инварианты для ADR
|
||||
"@
|
||||
$utf8 = [System.Text.Encoding]::UTF8
|
||||
[System.IO.File]::WriteAllBytes($AgentsMd, $utf8.GetBytes($content))
|
||||
Write-Ok "AGENTS.md created"
|
||||
New-AgentsMd $AgentsMd | Out-File -FilePath $AgentsMd -Encoding utf8
|
||||
Write-Host " [create] AGENTS.md"
|
||||
} elseif ($Update) {
|
||||
$content = @"
|
||||
# MetaAgent
|
||||
|
||||
Этот проект использует [MetaAgent](.agent/src/GUIDE.md) v$Version —
|
||||
набор инструкций для AI-агента.
|
||||
|
||||
## Контекст MetaAgent
|
||||
|
||||
| Ресурс | Путь |
|
||||
|--------|------|
|
||||
| Главная инструкция | `.agent/src/GUIDE.md` |
|
||||
| Протоколы фаз | `.agent/src/PROTOCOLS/` |
|
||||
| Команды (on-demand) | `.agent/src/COMMANDS/` |
|
||||
| Шаблоны артефактов | `.agent/src/TEMPLATES/` |
|
||||
| Границы (что разрешено/запрещено) | `.agent/src/BOUNDARIES.md` |
|
||||
| История версий | `.agent/src/CHANGELOG.md` |
|
||||
| Правила проекта | `.agent/rules/project-rules.md` |
|
||||
| Пример работы | `.agent/src/WORKFLOW.md` |
|
||||
| Версия | `.agent/src/VERSION` |
|
||||
|
||||
## Состояние сессии (если инициализировано)
|
||||
|
||||
| Артефакт | Путь |
|
||||
|----------|------|
|
||||
| Чекпоинты сессии | `.agent/checkpoints.json` |
|
||||
| Слепок проекта | `.agent/context/project-state.md` |
|
||||
| Анализ репозитория | `.agent/context/analysis-report.md` |
|
||||
| Дорожная карта | `.agent/roadmap/sources.md` |
|
||||
| Манифест задач | `.agent/tasks/manifest.json` |
|
||||
| Сводка для следующего агента | `.agent/handoff-summary.md` |
|
||||
| Сводка сессии | `.agent/session-summary.md` |
|
||||
|
||||
## Для агента
|
||||
|
||||
Жизненный цикл MetaAgent v$Version:
|
||||
|
||||
```
|
||||
INIT → ANALYSE → ROADMAP → [DESIGN] → DECOMPOSITION → EXECUTION → METASTATE → HANDOFF
|
||||
```
|
||||
|
||||
1. **Прочитай** `.agent/src/GUIDE.md` — пойми цикл и доступные команды.
|
||||
2. **Прочитай** `.agent/src/BOUNDARIES.md` — соблюдай границы.
|
||||
3. **Прочитай** `.agent/rules/project-rules.md` — выполни правила пользователя.
|
||||
4. **Проверь** `.agent/checkpoints.json` — если существует, используй как состояние сессии.
|
||||
5. **Проверь** `.agent/context/project-state.md` — получи актуальную картину.
|
||||
6. **Проверь** `.agent/tasks/manifest.json` — если существует, выполняй задачи по порядку.
|
||||
7. Если `.agent/` не инициализирован или устарел — запусти `install.sh --update` для
|
||||
обновления исходников MetaAgent до актуальной версии.
|
||||
|
||||
## Команды (on-demand)
|
||||
|
||||
В любой момент пользователь может вызвать:
|
||||
- `/adr` — записать архитектурное решение
|
||||
- `/red-team` — попытаться сломать дизайн
|
||||
- `/risk-register` — зафиксировать допущения
|
||||
- `/alt-arch` — описать альтернативу
|
||||
- `/invariant-tests` — тесты-инварианты для ADR
|
||||
"@
|
||||
$utf8 = [System.Text.Encoding]::UTF8
|
||||
[System.IO.File]::WriteAllBytes($AgentsMd, $utf8.GetBytes($content))
|
||||
Write-Ok "AGENTS.md updated"
|
||||
New-AgentsMd $AgentsMd | Out-File -FilePath $AgentsMd -Encoding utf8
|
||||
Write-Host " [update] AGENTS.md"
|
||||
} else {
|
||||
Write-Skip "AGENTS.md (exists, use -Update to overwrite)"
|
||||
$script:skipCount++
|
||||
Write-Host " [skip] AGENTS.md (exists, use -Update to overwrite)"
|
||||
}
|
||||
|
||||
# --- summary -------------------------------------------------------------
|
||||
Write-Header "Summary"
|
||||
Write-Host " MetaAgent v$Version → $SrcDir"
|
||||
Write-Host ""
|
||||
if ($copyCount -gt 0) { Write-Ok "$copyCount file(s) copied" }
|
||||
if ($skipCount -gt 0) { Write-Skip "$skipCount file(s) skipped" }
|
||||
if ($failCount -gt 0) { Write-Fail "$failCount file(s) failed" }
|
||||
Write-Host ""
|
||||
if ($failCount -eq 0) {
|
||||
Write-Ok "Installation completed successfully."
|
||||
} else {
|
||||
Write-Fail "Installation completed with $failCount error(s)."
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Done! MetaAgent v$Version installed at $SrcDir"
|
||||
|
||||
Executable → Regular
+36
-196
@@ -1,242 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
# MetaAgent — установка исходников в целевой проект
|
||||
# Usage: ./install.sh [--check|--update] [target_path]
|
||||
# Usage: ./install.sh [--update] [target_path]
|
||||
set -euo pipefail
|
||||
|
||||
METAAGENT_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# --- helpers ---
|
||||
red=; grn=; ylw=; blu=; rst=
|
||||
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
|
||||
red=$(tput setaf 1); grn=$(tput setaf 2)
|
||||
ylw=$(tput setaf 3); blu=$(tput setaf 4)
|
||||
rst=$(tput sgr0)
|
||||
fi
|
||||
info() { echo " ${blu}→${rst} $*"; }
|
||||
ok() { echo " ${grn}✓${rst} $*"; }
|
||||
skip() { echo " ${ylw}−${rst} $*"; }
|
||||
warn() { echo " ${ylw}⚠${rst} $*"; }
|
||||
fail() { echo " ${red}✗${rst} $*"; }
|
||||
header(){ echo; echo "────────────────────────────────────────"; echo " $*"; echo "────────────────────────────────────────"; }
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [--check|--update] [target_path]
|
||||
Usage: $0 [--update] [target_path]
|
||||
|
||||
Install MetaAgent sources into <target>/.agent/src/
|
||||
|
||||
Options:
|
||||
--check, -c Dry-run: only check target readiness, no install
|
||||
--update, -u Overwrite existing files in .agent/src/
|
||||
--help, -h Show this help
|
||||
|
||||
Examples:
|
||||
$0
|
||||
$0 /path/to/project
|
||||
$0 --check /path/to/project
|
||||
$0 --update /path/to/project
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- arg parsing ---
|
||||
CHECK=false
|
||||
UPDATE=false
|
||||
TARGET_PATH=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--check|-c) CHECK=true; shift ;;
|
||||
--update|-u) UPDATE=true; shift ;;
|
||||
--help|-h) usage ;;
|
||||
--*) echo "${red}Unknown option:${rst} $1"; usage ;;
|
||||
--*) echo "Unknown option: $1"; usage ;;
|
||||
*) TARGET_PATH="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- resolve target ---
|
||||
if [[ -z "$TARGET_PATH" ]]; then
|
||||
read -r -p "Enter path to target project: " TARGET_PATH
|
||||
fi
|
||||
|
||||
TARGET_PATH="${TARGET_PATH/#\~/$HOME}"
|
||||
|
||||
# --- pre-flight -----------------------------------------------------------
|
||||
header "Pre-flight"
|
||||
|
||||
# 1. target exists?
|
||||
if [[ ! -d "$TARGET_PATH" ]]; then
|
||||
fail "Target directory '$TARGET_PATH' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# resolve to absolute path
|
||||
TARGET_PATH="$(cd "$TARGET_PATH" 2>/dev/null && pwd)" || {
|
||||
fail "Cannot access '$TARGET_PATH'."
|
||||
echo "Error: Directory '$TARGET_PATH' does not exist."
|
||||
exit 1
|
||||
}
|
||||
ok "Target: $TARGET_PATH"
|
||||
|
||||
# 2. write permission?
|
||||
if [[ ! -w "$TARGET_PATH" ]]; then
|
||||
fail "No write permission on '$TARGET_PATH'."
|
||||
exit 1
|
||||
fi
|
||||
ok "Write permission: yes"
|
||||
|
||||
# 3. already installed? compare versions
|
||||
AGENT_DIR="$TARGET_PATH/.agent"
|
||||
SRC_DIR="$AGENT_DIR/src"
|
||||
VERSION="$(cat "$METAAGENT_SRC/VERSION" 2>/dev/null || echo '?')"
|
||||
|
||||
if [[ -f "$SRC_DIR/VERSION" ]]; then
|
||||
OLD_VER="$(cat "$SRC_DIR/VERSION" 2>/dev/null || echo '?')"
|
||||
if [[ "$OLD_VER" != "$VERSION" ]]; then
|
||||
info "Existing MetaAgent v${OLD_VER} found → upgrading to v${VERSION}"
|
||||
else
|
||||
skip "MetaAgent v${VERSION} already installed (use --update to reinstall)"
|
||||
if [[ "$CHECK" == false ]]; then
|
||||
warn "No changes applied. Run with --update to overwrite existing files."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
info "Fresh install: MetaAgent v$VERSION"
|
||||
fi
|
||||
|
||||
# 4. summary
|
||||
AGENTS_MD="$TARGET_PATH/AGENTS.md"
|
||||
RULES_DIR="$AGENT_DIR/rules"
|
||||
DECISIONS_DIR="$AGENT_DIR/decisions"
|
||||
TASKS_DIR="$AGENT_DIR/tasks"
|
||||
CONTEXT_DIR="$AGENT_DIR/context"
|
||||
ARCHIVE_DIR="$AGENT_DIR/archive"
|
||||
ARCHIVE_TASKS_DIR="$ARCHIVE_DIR/tasks"
|
||||
ARCHIVE_DECISIONS_DIR="$ARCHIVE_DIR/decisions"
|
||||
ARCHIVE_CHECKPOINTS_DIR="$ARCHIVE_DIR/checkpoints"
|
||||
REQUESTS_DIR="$AGENT_DIR/requests"
|
||||
REQUESTS_ACTIVE_DIR="$REQUESTS_DIR/active"
|
||||
REQUESTS_ARCHIVE_DIR="$REQUESTS_DIR/archive"
|
||||
ROADMAP_DIR="$AGENT_DIR/roadmap"
|
||||
ROADMAP_ARCHIVE_DIR="$ROADMAP_DIR/archive"
|
||||
TEMP_DIR="$TARGET_PATH/.temp"
|
||||
|
||||
if [[ "$CHECK" == true ]]; then
|
||||
echo ""
|
||||
info "${ylw}--check mode:${rst} all checks passed, no changes applied."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- phase 1: directories ------------------------------------------------
|
||||
header "Directories"
|
||||
|
||||
mkdir -p "$SRC_DIR" "$RULES_DIR" "$DECISIONS_DIR" "$TASKS_DIR" "$TASKS_DIR/backlog" \
|
||||
"$CONTEXT_DIR" "$ARCHIVE_DIR" "$ARCHIVE_TASKS_DIR" "$ARCHIVE_DECISIONS_DIR" \
|
||||
"$ARCHIVE_CHECKPOINTS_DIR" \
|
||||
"$REQUESTS_ACTIVE_DIR" "$REQUESTS_ARCHIVE_DIR" \
|
||||
"$ROADMAP_DIR" "$ROADMAP_ARCHIVE_DIR" \
|
||||
"$TEMP_DIR"
|
||||
|
||||
for d in "$SRC_DIR" "$RULES_DIR" "$DECISIONS_DIR" "$TASKS_DIR" "$TASKS_DIR/backlog" \
|
||||
"$CONTEXT_DIR" "$ARCHIVE_DIR" "$ARCHIVE_TASKS_DIR" "$ARCHIVE_DECISIONS_DIR" \
|
||||
"$ARCHIVE_CHECKPOINTS_DIR" \
|
||||
"$REQUESTS_ACTIVE_DIR" "$REQUESTS_ARCHIVE_DIR" \
|
||||
"$ROADMAP_DIR" "$ROADMAP_ARCHIVE_DIR" \
|
||||
"$TEMP_DIR"; do
|
||||
short="${d#$TARGET_PATH/}"
|
||||
if [[ -d "$d" ]]; then
|
||||
ok "$short"
|
||||
else
|
||||
fail "$short (creation failed)"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- phase 2: files ------------------------------------------------------
|
||||
header "Files"
|
||||
|
||||
COPY_COUNT=0
|
||||
SKIP_COUNT=0
|
||||
FAIL_COUNT=0
|
||||
mkdir -p "$SRC_DIR" "$RULES_DIR" "$ARCHIVE_DIR"
|
||||
echo "Installing MetaAgent v$VERSION → $SRC_DIR"
|
||||
|
||||
# --- copy files ---
|
||||
copy_file() {
|
||||
local src="$1" dst_dir="$2"
|
||||
local name; name="$(basename "$src")"
|
||||
local dst="$dst_dir/$name"
|
||||
if [[ ! -f "$src" ]]; then
|
||||
skip "$name (source not found)"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo " [skip] $name (not found)"
|
||||
return
|
||||
fi
|
||||
if [[ "$UPDATE" == true ]] || [[ ! -f "$dst" ]]; then
|
||||
if cp "$src" "$dst"; then
|
||||
ok "$name"
|
||||
COPY_COUNT=$((COPY_COUNT + 1))
|
||||
if [[ "$UPDATE" == true ]] || [[ ! -f "$dst_dir/$name" ]]; then
|
||||
cp "$src" "$dst_dir/$name"
|
||||
echo " [copy] $name"
|
||||
else
|
||||
fail "$name"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
fi
|
||||
else
|
||||
skip "$name (exists, use --update to overwrite)"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo " [skip] $name (exists, use --update to overwrite)"
|
||||
fi
|
||||
}
|
||||
|
||||
copy_dir() {
|
||||
local src="$1" dst_dir="$2"
|
||||
local name; name="$(basename "$src")"
|
||||
local dst="$dst_dir/$name"
|
||||
if [[ ! -d "$src" ]]; then
|
||||
skip "$name/ (source not found)"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo " [skip] $name/ (not found)"
|
||||
return
|
||||
fi
|
||||
mkdir -p "$dst"
|
||||
mkdir -p "$dst_dir/$name"
|
||||
if [[ "$UPDATE" == true ]]; then
|
||||
if cp -rf "$src"/* "$dst/" 2>/dev/null; then
|
||||
ok "$name/"
|
||||
COPY_COUNT=$((COPY_COUNT + 1))
|
||||
cp -rf "$src"/* "$dst_dir/$name/" 2>/dev/null || true
|
||||
else
|
||||
fail "$name/ (partial copy)"
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
fi
|
||||
else
|
||||
cp -rn "$src"/* "$dst/" 2>/dev/null || true
|
||||
ok "$name/"
|
||||
COPY_COUNT=$((COPY_COUNT + 1))
|
||||
cp -rn "$src"/* "$dst_dir/$name/" 2>/dev/null || true
|
||||
fi
|
||||
echo " [copy] $name/"
|
||||
}
|
||||
|
||||
copy_file "$METAAGENT_SRC/GUIDE.md" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/META_AGENT_GUIDE.md" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/BOUNDARIES.md" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/CHANGELOG.md" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/WORKFLOW.md" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/VERSION" "$SRC_DIR"
|
||||
copy_dir "$METAAGENT_SRC/PROTOCOLS" "$SRC_DIR"
|
||||
copy_dir "$METAAGENT_SRC/COMMANDS" "$SRC_DIR"
|
||||
copy_dir "$METAAGENT_SRC/TEMPLATES" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/install.sh" "$SRC_DIR"
|
||||
copy_file "$METAAGENT_SRC/install.ps1" "$SRC_DIR"
|
||||
|
||||
# --- phase 3: AGENTS.md --------------------------------------------------
|
||||
header "AGENTS.md"
|
||||
# --- create / update AGENTS.md in root of target ---
|
||||
AGENTS_MD="$TARGET_PATH/AGENTS.md"
|
||||
|
||||
create_agents_md() {
|
||||
cat > "$1" << AGENTS_EOF
|
||||
# MetaAgent
|
||||
|
||||
Этот проект использует [MetaAgent](.agent/src/GUIDE.md) v$VERSION —
|
||||
Этот проект использует [MetaAgent](.agent/src/META_AGENT_GUIDE.md) v$VERSION —
|
||||
набор инструкций для AI-агента.
|
||||
|
||||
## Контекст MetaAgent
|
||||
|
||||
| Ресурс | Путь |
|
||||
|--------|------|
|
||||
| Главная инструкция | \`.agent/src/GUIDE.md\` |
|
||||
| Главная инструкция | \`.agent/src/META_AGENT_GUIDE.md\` |
|
||||
| Протоколы фаз | \`.agent/src/PROTOCOLS/\` |
|
||||
| Команды (on-demand) | \`.agent/src/COMMANDS/\` |
|
||||
| Шаблоны артефактов | \`.agent/src/TEMPLATES/\` |
|
||||
| Границы (что разрешено/запрещено) | \`.agent/src/BOUNDARIES.md\` |
|
||||
| История версий | \`.agent/src/CHANGELOG.md\` |
|
||||
| Правила проекта | \`.agent/rules/project-rules.md\` |
|
||||
| Пример работы | \`.agent/src/WORKFLOW.md\` |
|
||||
| Примеры работы | \`.agent/src/WORKFLOW.md\` |
|
||||
| Версия | \`.agent/src/VERSION\` |
|
||||
|
||||
## Состояние сессии (если инициализировано)
|
||||
@@ -244,69 +122,31 @@ create_agents_md() {
|
||||
| Артефакт | Путь |
|
||||
|----------|------|
|
||||
| Чекпоинты сессии | \`.agent/checkpoints.json\` |
|
||||
| Слепок проекта | \`.agent/context/project-state.md\` |
|
||||
| Анализ репозитория | \`.agent/context/analysis-report.md\` |
|
||||
| Дорожная карта | \`.agent/roadmap/sources.md\` |
|
||||
| Манифест задач | \`.agent/tasks/manifest.json\` |
|
||||
| Сводка для следующего агента | \`.agent/handoff-summary.md\` |
|
||||
| Сводка сессии | \`.agent/session-summary.md\` |
|
||||
| Манифест задач | \`.agent/task-manifest.json\` |
|
||||
| Сводка для exec-агента | \`.agent/handoff-summary.md\` |
|
||||
| Анализ репозитория | \`.agent/analysis-report.md\` |
|
||||
|
||||
## Для агента
|
||||
## Для исполнительного агента
|
||||
|
||||
Жизненный цикл MetaAgent v$VERSION:
|
||||
|
||||
\`\`\`
|
||||
INIT → ANALYSE → ROADMAP → [DESIGN] → DECOMPOSITION → EXECUTION → METASTATE → HANDOFF
|
||||
\`\`\`
|
||||
|
||||
1. **Прочитай** \`.agent/src/GUIDE.md\` — пойми цикл и доступные команды.
|
||||
1. **Прочитай** \`.agent/src/META_AGENT_GUIDE.md\` — пойми жизненный цикл MetaAgent.
|
||||
2. **Прочитай** \`.agent/src/BOUNDARIES.md\` — соблюдай границы.
|
||||
3. **Прочитай** \`.agent/rules/project-rules.md\` — выполни правила пользователя.
|
||||
3. **Прочитай** \`.agent/rules/project-rules.md\` — выполни пользовательские правила.
|
||||
4. **Проверь** \`.agent/checkpoints.json\` — если существует, используй как состояние сессии.
|
||||
5. **Проверь** \`.agent/context/project-state.md\` — получи актуальную картину.
|
||||
6. **Проверь** \`.agent/tasks/manifest.json\` — если существует, выполняй задачи по порядку.
|
||||
7. Если \`.agent/\` не инициализирован или устарел — запусти \`install.sh --update\` для
|
||||
5. **Проверь** \`.agent/task-manifest.json\` — если существует, выполняй задачи по порядку.
|
||||
6. Если \`.agent/\` не инициализирован или устарел — запусти \`install.sh --update\` для
|
||||
обновления исходников MetaAgent до актуальной версии.
|
||||
|
||||
## Команды (on-demand)
|
||||
|
||||
В любой момент пользователь может вызвать:
|
||||
- \`/adr\` — записать архитектурное решение
|
||||
- \`/red-team\` — попытаться сломать дизайн
|
||||
- \`/risk-register\` — зафиксировать допущения
|
||||
- \`/alt-arch\` — описать альтернативу
|
||||
- \`/invariant-tests\` — тесты-инварианты для ADR
|
||||
AGENTS_EOF
|
||||
}
|
||||
|
||||
if [[ ! -f "$AGENTS_MD" ]]; then
|
||||
create_agents_md "$AGENTS_MD"
|
||||
ok "AGENTS.md created"
|
||||
echo " [create] AGENTS.md"
|
||||
elif [[ "$UPDATE" == true ]]; then
|
||||
create_agents_md "$AGENTS_MD"
|
||||
ok "AGENTS.md updated"
|
||||
echo " [update] AGENTS.md"
|
||||
else
|
||||
skip "AGENTS.md (exists, use --update to overwrite)"
|
||||
SKIP_COUNT=$((SKIP_COUNT + 1))
|
||||
echo " [skip] AGENTS.md (exists, use --update to overwrite)"
|
||||
fi
|
||||
|
||||
# --- summary -------------------------------------------------------------
|
||||
header "Summary"
|
||||
echo " MetaAgent v$VERSION → $SRC_DIR"
|
||||
echo ""
|
||||
if (( COPY_COUNT > 0 )); then
|
||||
ok "${COPY_COUNT} file(s) copied"
|
||||
fi
|
||||
if (( SKIP_COUNT > 0 )); then
|
||||
skip "${SKIP_COUNT} file(s) skipped"
|
||||
fi
|
||||
if (( FAIL_COUNT > 0 )); then
|
||||
fail "${FAIL_COUNT} file(s) failed"
|
||||
fi
|
||||
echo ""
|
||||
if (( FAIL_COUNT == 0 )); then
|
||||
ok "Installation completed successfully."
|
||||
else
|
||||
fail "Installation completed with ${FAIL_COUNT} error(s)."
|
||||
exit 1
|
||||
fi
|
||||
echo "Done! MetaAgent v$VERSION installed at $SRC_DIR"
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"$schema": "metaagent-task-manifest",
|
||||
"version": "1.0",
|
||||
"session_id": "metaagent-002",
|
||||
"goal": "Обновление metaagent-артефактов до v1.0.0, валидация существующего кода и окружения",
|
||||
"created_at": "2026-07-12T20:00:00Z",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T1",
|
||||
"title": "Инициализация проекта и зависимостей",
|
||||
"description": "Создать структуру директорий, pyproject.toml, venv, установить зависимости",
|
||||
"type": "config",
|
||||
"files": [
|
||||
"pyproject.toml",
|
||||
"cashflow_model/__init__.py",
|
||||
"sync/__init__.py",
|
||||
"engine/__init__.py",
|
||||
"ai/__init__.py",
|
||||
"cli/__init__.py",
|
||||
"data/.gitkeep",
|
||||
"exports/.gitkeep"
|
||||
],
|
||||
"depends_on": [],
|
||||
"acceptance_criteria": [
|
||||
"pyproject.toml создан с правильными зависимостями",
|
||||
"Все директории модулей созданы с __init__.py",
|
||||
"ruff lint проходит без ошибок",
|
||||
"pytest запускается"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T2",
|
||||
"title": "Модель данных (dataclass + JSON serialization)",
|
||||
"description": "Реализовать все сущности: Account, Transaction, RecurringCashflow, Asset, Liability, ForecastScenario, FinancialModel",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"cashflow_model/__init__.py",
|
||||
"cashflow_model/account.py",
|
||||
"cashflow_model/transaction.py",
|
||||
"cashflow_model/recurring.py",
|
||||
"cashflow_model/asset.py",
|
||||
"cashflow_model/liability.py",
|
||||
"cashflow_model/scenario.py",
|
||||
"cashflow_model/model.py"
|
||||
],
|
||||
"depends_on": ["T1"],
|
||||
"acceptance_criteria": [
|
||||
"Все сущности — dataclass с правильными полями и типами",
|
||||
"FinancialModel корректно сохраняется и загружается из JSON",
|
||||
"Создание Account, Transaction, Asset, Liability через конструктор работает"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T3",
|
||||
"title": "Forecast Engine (базовый прогноз)",
|
||||
"description": "Реализовать ForecastService с методами forecast_cashflow, apply_recurring, project_balance",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"engine/__init__.py",
|
||||
"engine/forecast.py"
|
||||
],
|
||||
"depends_on": ["T2"],
|
||||
"acceptance_criteria": [
|
||||
"forecast_cashflow(months=12) возвращает список помесячных балансов",
|
||||
"Регулярные платежи корректно проецируются на будущие периоды",
|
||||
"Активы учитываются с ростом (growth_rate)",
|
||||
"Обязательства учитываются с процентами и платежами"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T4",
|
||||
"title": "Scenario Analysis",
|
||||
"description": "Реализовать ScenarioService с методами: сценарии, what-if, сравнение",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"engine/__init__.py",
|
||||
"engine/scenarios.py"
|
||||
],
|
||||
"depends_on": ["T3"],
|
||||
"acceptance_criteria": [
|
||||
"Три предустановленных сценария (baseline, optimistic, pessimistic)",
|
||||
"What-if: изменение параметров (доход +10%, расход -5%)",
|
||||
"Сравнение сценариев возвращает сводку различий"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T5",
|
||||
"title": "Excel Sync (import/export)",
|
||||
"description": "Реализовать ExcelSync: чтение модели из .xlsx, запись результатов прогноза в .xlsx",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"sync/__init__.py",
|
||||
"sync/excel_sync.py"
|
||||
],
|
||||
"depends_on": ["T2"],
|
||||
"acceptance_criteria": [
|
||||
"Импорт из Excel заполняет FinancialModel",
|
||||
"Экспорт FinancialModel в Excel создаёт корректный .xlsx",
|
||||
"Обработка ошибок при невалидном формате Excel"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T6",
|
||||
"title": "CLI (Typer) — все команды",
|
||||
"description": "Реализовать CLI через Typer с командами: init, import, export, forecast, scenario, analyze, whatif, compare",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"cli/__init__.py",
|
||||
"cli/main.py",
|
||||
"pyproject.toml"
|
||||
],
|
||||
"depends_on": ["T2", "T3", "T4", "T5", "T7"],
|
||||
"acceptance_criteria": [
|
||||
"Команда 'cf init' создаёт пустую модель и JSON",
|
||||
"Команда 'cf forecast --months 12' выводит таблицу прогноза",
|
||||
"Команда 'cf analyze' вызывает AI Assistant",
|
||||
"Команда 'cf import' и 'cf export' работают с Excel",
|
||||
"Команда 'cf scenario' применяет и выводит сценарий",
|
||||
"Команда 'cf whatif' выполняет what-if анализ",
|
||||
"Команда 'cf compare' сравнивает сценарии"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T7",
|
||||
"title": "AI Assistant (промпты + интерфейс)",
|
||||
"description": "Реализовать AssistantService: генерация промптов, заглушка для вызова AI API",
|
||||
"type": "feature",
|
||||
"files": [
|
||||
"ai/__init__.py",
|
||||
"ai/prompts.py",
|
||||
"ai/assistant.py"
|
||||
],
|
||||
"depends_on": ["T3"],
|
||||
"acceptance_criteria": [
|
||||
"Промпт 'analyze' включает модель и прогноз в JSON",
|
||||
"Промпт 'advice' формирует запрос на финансовые рекомендации",
|
||||
"AssistantService возвращает структурированный ответ (заглушка)"
|
||||
],
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": "T8",
|
||||
"title": "Тесты на все модули",
|
||||
"description": "Написать pytest-тесты для всех модулей",
|
||||
"type": "test",
|
||||
"files": [
|
||||
"tests/test_model.py",
|
||||
"tests/test_forecast.py",
|
||||
"tests/test_scenarios.py",
|
||||
"tests/test_excel_sync.py",
|
||||
"tests/test_cli.py",
|
||||
"tests/test_ai.py",
|
||||
"tests/conftest.py"
|
||||
],
|
||||
"depends_on": ["T2", "T3", "T4", "T5", "T6", "T7"],
|
||||
"acceptance_criteria": [
|
||||
"pytest запускается и все тесты проходят",
|
||||
"Покрытие базовых сценариев для каждой сущности",
|
||||
"Roundtrip-тест Excel: export → import → compare",
|
||||
"Forecast-тест: известные входные данные → ожидаемый результат"
|
||||
],
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Task Manifest
|
||||
|
||||
**Session:** metaagent-002
|
||||
**Goal:** Обновление metaagent-артефактов до v1.0.0, валидация существующего кода и окружения
|
||||
**Date:** 2026-07-12T20:00:00Z
|
||||
|
||||
---
|
||||
|
||||
## Task Overview
|
||||
|
||||
| ID | Title | Type | Depends On | Status |
|
||||
|---|---|---|---|---|
|
||||
| T1 | Инициализация проекта и зависимостей | config | — | completed |
|
||||
| T2 | Модель данных (dataclass + JSON serialization) | feature | T1 | completed |
|
||||
| T3 | Forecast Engine (базовый прогноз) | feature | T2 | completed |
|
||||
| T4 | Scenario Analysis | feature | T3 | completed |
|
||||
| T5 | Excel Sync (import/export) | feature | T2 | completed |
|
||||
| T6 | CLI (Typer) — все команды | feature | T2, T3, T4, T5, T7 | completed |
|
||||
| T7 | AI Assistant (промпты + интерфейс) | feature | T3 | completed |
|
||||
| T8 | Тесты на все модули | test | T2, T3, T4, T5, T6, T7 | completed |
|
||||
|
||||
**Total tasks:** 8 — all completed
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"$schema": "metaagent-task-manifest",
|
||||
"version": "3.0",
|
||||
"session_id": "metaagent-005",
|
||||
"goal": "Серьёзный архитектурный рефактор: A1+A10 (слои+version), A2+A3 (pydantic), A4 (decimal), A7+A8+A9 (DI+repo), A5 (CLI decompose)",
|
||||
"created_at": "2026-10-08T15:58:00Z",
|
||||
"tasks": [
|
||||
{ "id": "T1", "title": "Реструктуризация в domain/application/infrastructure + version=1", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T2", "title": "Pydantic v2 — миграция моделей", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T3", "title": "Decimal для денег", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T4", "title": "Repository pattern — ModelRepository", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T5", "title": "Dependency Injection в сервисах", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T6", "title": "Декомпозиция CLI", "status": "archived", "origin": "user:direct" },
|
||||
{ "id": "T7", "title": "Финальная валидация", "status": "archived", "origin": "user:direct" }
|
||||
]
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
# Task Manifest
|
||||
|
||||
**Session:** `metaagent-005`
|
||||
**Goal:** Серьёзный архитектурный рефактор
|
||||
**Date:** 2026-10-08
|
||||
**Total tasks:** 7
|
||||
|
||||
---
|
||||
|
||||
## T1: Реструктуризация в domain/application/infrastructure + version=1
|
||||
|
||||
**Зависимости:** —
|
||||
**Файлы:** domain/ (new), application/ (new), infrastructure/{cli,sync,ai}/ (new), tests/
|
||||
|
||||
**Что:** Ввести явные слои. Переместить пакеты. Добавить version: 1 в FinancialModel.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] Структура domain/application/infrastructure создана
|
||||
- [ ] Все исходные файлы перемещены
|
||||
- [ ] Все импорты обновлены
|
||||
- [ ] `FinancialModel.to_dict()` → `{'version': 1, ...}`
|
||||
- [ ] `from_dict()` поддерживает v0 (без version) и v1
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T2: Pydantic v2 — миграция моделей
|
||||
|
||||
**Зависимости:** T1
|
||||
**Файлы:** domain/*.py, pyproject.toml, infrastructure/sync/excel_sync.py
|
||||
|
||||
**Что:** `@dataclass` → `pydantic.BaseModel`. Удалить ручные `to_dict`/`from_dict`.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] Все модели — `BaseModel`
|
||||
- [ ] Удалены ручные to_dict/from_dict
|
||||
- [ ] UUID в JSON как str
|
||||
- [ ] Валидация (balance >= 0, и т.п.)
|
||||
- [ ] Excel-sync адаптирован
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T3: Decimal для денег
|
||||
|
||||
**Зависимости:** T2
|
||||
**Файлы:** domain/*.py, application/*.py, infrastructure/sync/excel_sync.py, infrastructure/cli/{main,config}.py
|
||||
|
||||
**Что:** `float` → `Decimal` для всех monetary полей. Арифметика engine, форматирование.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] monetary поля — `Decimal`
|
||||
- [ ] CurrencyConverter с Decimal
|
||||
- [ ] ForecastService арифметика — Decimal
|
||||
- [ ] Excel-sync читает числа как Decimal
|
||||
- [ ] rich.print форматирует Decimal (2 знака)
|
||||
- [ ] JSON-сериализация Decimal работает
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T4: Repository pattern — ModelRepository
|
||||
|
||||
**Зависимости:** T1
|
||||
**Файлы:** application/repositories/model_repository.py, infrastructure/repositories/{json_file,excel}_repository.py, infrastructure/sync/excel_sync.py
|
||||
|
||||
**Что:** `ModelRepository` Protocol + `JsonFileRepository` + `ExcelRepository` (адаптер над ExcelSync).
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] `ModelRepository` Protocol (load/save)
|
||||
- [ ] `JsonFileRepository` реализует Protocol
|
||||
- [ ] `ExcelRepository` реализует Protocol
|
||||
- [ ] `FinancialModel.save/load` удалены
|
||||
- [ ] Тесты на каждый репозиторий
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T5: Dependency Injection в сервисах
|
||||
|
||||
**Зависимости:** T4
|
||||
**Файлы:** application/forecast.py, scenarios.py, infrastructure/ai/assistant.py, infrastructure/cli/{main,config}.py
|
||||
|
||||
**Что:** Зависимости через конструктор. Composition root в CLI.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] `ForecastService.__init__(model, repository, converter)`
|
||||
- [ ] ScenarioService, AssistantService — то же
|
||||
- [ ] Нет `new ForecastService()` внутри других сервисов
|
||||
- [ ] CLI собирает граф зависимостей
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T6: Декомпозиция CLI
|
||||
|
||||
**Зависимости:** T5
|
||||
**Файлы:** infrastructure/cli/main.py → app.py, infrastructure/cli/commands/*.py, infrastructure/cli/{paths,services}.py
|
||||
|
||||
**Что:** 8 команд в отдельных файлах. config.py → paths.py + services.py.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] Каждая команда в cli/commands/*.py
|
||||
- [ ] cli/paths.py — только пути
|
||||
- [ ] cli/services.py — composition root
|
||||
- [ ] Размер файлов < 100-150 LOC
|
||||
- [ ] Поведение идентично
|
||||
- [ ] pytest 63/63
|
||||
|
||||
---
|
||||
|
||||
## T7: Финальная валидация
|
||||
|
||||
**Зависимости:** T6
|
||||
**Файлы:** tests/, README.md, pyproject.toml
|
||||
|
||||
**Что:** Прогнать pytest, ручная проверка CLI, обновить README.
|
||||
|
||||
**Acceptance:**
|
||||
- [ ] pytest 63/63+
|
||||
- [ ] cf init, cf forecast, cf scenario, cf compare — работают
|
||||
- [ ] cf import data.xlsx → cf export — round-trip
|
||||
- [ ] README.md обновлён под новую структуру
|
||||
@@ -174,9 +174,3 @@ poetry.toml
|
||||
pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
|
||||
# MetaAgent temp files
|
||||
.temp/
|
||||
|
||||
# opencode local state
|
||||
.omo/
|
||||
|
||||
@@ -1,56 +1,186 @@
|
||||
# MetaAgent
|
||||
# AGENTS.md — контекст для AI-сессий
|
||||
|
||||
Этот проект использует [MetaAgent](.agent/src/GUIDE.md) v3.0.0 —
|
||||
набор инструкций для AI-агента.
|
||||
## Project Overview
|
||||
|
||||
## Контекст MetaAgent
|
||||
**CashFlow Forecast** — личная финансовая модель с прогнозом денежных потоков. Python CLI-инструмент.
|
||||
|
||||
| Ресурс | Путь |
|
||||
|--------|------|
|
||||
| Главная инструкция | `.agent/src/GUIDE.md` |
|
||||
| Протоколы фаз | `.agent/src/PROTOCOLS/` |
|
||||
| Команды (on-demand) | `.agent/src/COMMANDS/` |
|
||||
| Шаблоны артефактов | `.agent/src/TEMPLATES/` |
|
||||
| Границы (что разрешено/запрещено) | `.agent/src/BOUNDARIES.md` |
|
||||
| История версий | `.agent/src/CHANGELOG.md` |
|
||||
| Правила проекта | `.agent/rules/project-rules.md` |
|
||||
| Пример работы | `.agent/src/WORKFLOW.md` |
|
||||
| Версия | `.agent/src/VERSION` |
|
||||
**Цель:** отвечать на вопрос "что произойдет дальше?" (forecast), а не "что произошло?" (accounting).
|
||||
|
||||
## Состояние сессии (если инициализировано)
|
||||
**Стек:** Python 3.11+, JSON (хранение), openpyxl (Excel), typer (CLI), rich (вывод), pytest (тесты), ruff (линтер).
|
||||
|
||||
| Артефакт | Путь |
|
||||
|----------|------|
|
||||
| Чекпоинты сессии | `.agent/checkpoints.json` |
|
||||
| Слепок проекта | `.agent/context/project-state.md` |
|
||||
| Анализ репозитория | `.agent/context/analysis-report.md` |
|
||||
| Дорожная карта | `.agent/roadmap/sources.md` |
|
||||
| Манифест задач | `.agent/tasks/manifest.json` |
|
||||
| Сводка для следующего агента | `.agent/handoff-summary.md` |
|
||||
| Сводка сессии | `.agent/session-summary.md` |
|
||||
**Тип проекта:** greenfield, MVP реализован.
|
||||
|
||||
## Для агента
|
||||
---
|
||||
|
||||
Жизненный цикл MetaAgent v3.0.0:
|
||||
## Quick Start
|
||||
|
||||
```
|
||||
INIT → ANALYSE → ROADMAP → [DESIGN] → DECOMPOSITION → EXECUTION → METASTATE → HANDOFF
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
cf init
|
||||
cf forecast --months 12
|
||||
pytest
|
||||
ruff check .
|
||||
```
|
||||
|
||||
1. **Прочитай** `.agent/src/GUIDE.md` — пойми цикл и доступные команды.
|
||||
2. **Прочитай** `.agent/src/BOUNDARIES.md` — соблюдай границы.
|
||||
3. **Прочитай** `.agent/rules/project-rules.md` — выполни правила пользователя.
|
||||
4. **Проверь** `.agent/checkpoints.json` — если существует, используй как состояние сессии.
|
||||
5. **Проверь** `.agent/context/project-state.md` — получи актуальную картину.
|
||||
6. **Проверь** `.agent/tasks/manifest.json` — если существует, выполняй задачи по порядку.
|
||||
7. Если `.agent/` не инициализирован или устарел — запусти `install.sh --update` для
|
||||
обновления исходников MetaAgent до актуальной версии.
|
||||
---
|
||||
|
||||
## Команды (on-demand)
|
||||
## Архитектура
|
||||
|
||||
В любой момент пользователь может вызвать:
|
||||
- `/adr` — записать архитектурное решение
|
||||
- `/red-team` — попытаться сломать дизайн
|
||||
- `/risk-register` — зафиксировать допущения
|
||||
- `/alt-arch` — описать альтернативу
|
||||
- `/invariant-tests` — тесты-инварианты для ADR
|
||||
Модульный монолит (layered):
|
||||
|
||||
```
|
||||
[CLI / Excel File]
|
||||
|
|
||||
v
|
||||
sync/ --> cashflow_model/ --> engine/ --> ai/
|
||||
(Excel R/W) (Entity Model) (Forecast) (Prompts)
|
||||
| | |
|
||||
v v v
|
||||
data/model.json data/model.json data/model.json
|
||||
```
|
||||
|
||||
**Поток данных:**
|
||||
1. Excel -> sync (импорт) -> JSON
|
||||
2. JSON -> cashflow_model (dataclass)
|
||||
3. engine (forecast) читает модель
|
||||
4. ai (assistant) анализирует результаты
|
||||
5. Результаты -> sync (экспорт) -> Excel
|
||||
|
||||
---
|
||||
|
||||
## Модули
|
||||
|
||||
| Модуль | Ответственность | Ключевые файлы |
|
||||
|---|---|---|
|
||||
| `cashflow_model/` | dataclass-сущности + JSON serialization | `model.py`, `account.py`, `transaction.py`, `recurring.py`, `asset.py`, `liability.py`, `scenario.py` |
|
||||
| `engine/` | ForecastService, ScenarioService | `forecast.py`, `scenarios.py` |
|
||||
| `sync/` | Excel <-> JSON | `excel_sync.py` |
|
||||
| `ai/` | Промпты, AssistantService (заглушка) | `prompts.py`, `assistant.py` |
|
||||
| `cli/` | Typer CLI | `main.py` |
|
||||
|
||||
---
|
||||
|
||||
## Data Model
|
||||
|
||||
### Account
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| name | str |
|
||||
| currency | str (default USD) |
|
||||
| balance | float |
|
||||
|
||||
### Transaction
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| date | str (ISO) |
|
||||
| account | str (UUID счёта) |
|
||||
| category | str |
|
||||
| amount | float (positive=income, negative=expense) |
|
||||
| description | str |
|
||||
|
||||
### RecurringCashflow
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| start_date | str (ISO) |
|
||||
| end_date | str (ISO, optional) |
|
||||
| frequency | str (monthly/weekly/yearly) |
|
||||
| amount | float |
|
||||
| category | str |
|
||||
|
||||
### Asset
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| name | str |
|
||||
| value | float |
|
||||
| growth_rate | float (% годовых) |
|
||||
|
||||
### Liability
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| name | str |
|
||||
| balance | float |
|
||||
| interest | float (% годовых) |
|
||||
| payment | float (ежемесячный) |
|
||||
|
||||
### ForecastScenario
|
||||
| Поле | Тип |
|
||||
|---|---|
|
||||
| id | UUID |
|
||||
| name | str (baseline/optimistic/pessimistic) |
|
||||
| income_multiplier | float |
|
||||
| expense_multiplier | float |
|
||||
| growth_multiplier | float |
|
||||
|
||||
**FinancialModel** — корневой объект, содержит списки всех сущностей. Методы: `save(path)`, `load(path)`. JSON-файл в `data/model.json`.
|
||||
|
||||
---
|
||||
|
||||
## CLI Reference
|
||||
|
||||
Команда `cf` (entry point: `cli.main:app`):
|
||||
|
||||
| Команда | Аргументы | Описание |
|
||||
|---|---|---|
|
||||
| `init` | — | Создать пустую модель |
|
||||
| `forecast` | `--months 12` | Прогноз cashflow |
|
||||
| `scenario` | `<name>` | Сценарий baseline/optimistic/pessimistic |
|
||||
| `whatif` | `--income 1.0 --expense 1.0 --growth 1.0` | What-if анализ |
|
||||
| `compare` | `--months 12` | Сравнение сценариев |
|
||||
| `import` | `<path.xlsx>` | Импорт из Excel |
|
||||
| `export` | `<path.xlsx>` | Экспорт в Excel |
|
||||
| `analyze` | `--months 12` | AI-анализ (промпт + заглушка) |
|
||||
|
||||
---
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
- Python 3.11+, dataclass для моделей
|
||||
- from_dict/to_dict для JSON-сериализации
|
||||
- ruff (E, F, I, N, W), line-length=100
|
||||
- pytest для тестов
|
||||
- typer + rich для CLI
|
||||
- f-строки, без лишних комментариев
|
||||
- Имена: snake_case, классы PascalCase
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
pytest # запуск тестов (26 tests)
|
||||
ruff check . # линтер
|
||||
ruff format . # автоформат
|
||||
cf <command> # запуск CLI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Issues / TODOs
|
||||
|
||||
- AI-ассистент — заглушка (`ai/assistant.py`). Промпты готовы, нужно подключить API (OpenAI и т.д.)
|
||||
- Нет лицензии — требуется выбрать
|
||||
- JSON-файлы — нет конкурентного доступа
|
||||
- Excel — только .xlsx (openpyxl), нет поддержки Google Sheets
|
||||
- Нет веб-интерфейса, только CLI
|
||||
- `engine/forecast.py` — упрощённый алгоритм (без Monte Carlo)
|
||||
|
||||
---
|
||||
|
||||
## .agent/ directory
|
||||
|
||||
Директория `.agent/` содержит артефакты MetaAgent — планирование, дизайн, декомпозицию задач. **Не удалять**. Там же `checkpoints.json` с состоянием задач.
|
||||
|
||||
---
|
||||
|
||||
## Границы (Boundaries)
|
||||
|
||||
**Что НЕ входит в задачу AI-агента:**
|
||||
- Изменение архитектуры без обсуждения с пользователем
|
||||
- Подключение внешних платных API без согласования
|
||||
- Массовый рефакторинг без acceptance criteria
|
||||
- Удаление `.agent/` или `README.arch.md`
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Jor Oqyude
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,8 +1,8 @@
|
||||
# CashFlow Forecast
|
||||
|
||||
Личная финансовая модель с прогнозом денежных потоков, сценарным анализом.
|
||||
Личная финансовая модель с прогнозом денежных потоков, сценарным анализом и AI-ассистентом.
|
||||
|
||||
Python + Pydantic + JSON + Excel.
|
||||
Python + JSON + Excel + AI.
|
||||
|
||||
## Установка
|
||||
|
||||
@@ -35,17 +35,12 @@ cf whatif --income 1.2 --expense 0.9 --growth 1.0 --months 12
|
||||
# Сравнение всех сценариев
|
||||
cf compare --months 12
|
||||
|
||||
# Сводка модели
|
||||
cf info
|
||||
|
||||
# Редактирование модели
|
||||
cf config account-add --name "Main" --balance 5000
|
||||
cf config transaction-add --account Main --amount -1200 --category rent
|
||||
cf config rate-set USD RUB 80.0
|
||||
|
||||
# Импорт/экспорт Excel
|
||||
cf import-xlsx data.xlsx
|
||||
cf export-xlsx exports/report.xlsx
|
||||
cf import data.xlsx
|
||||
cf export exports/report.xlsx
|
||||
|
||||
# AI-анализ (заглушка, генерация промпта)
|
||||
cf analyze
|
||||
```
|
||||
|
||||
### Пример: создание тестовых данных
|
||||
@@ -53,86 +48,43 @@ cf export-xlsx exports/report.xlsx
|
||||
Подготовьте Excel-файл с листами: `Accounts`, `Transactions`, `Recurring`, `Assets`, `Liabilities`. Заголовки колонок соответствуют полям моделей. Затем импортируйте:
|
||||
|
||||
```bash
|
||||
cf import-xlsx my_finances.xlsx
|
||||
cf import my_finances.xlsx
|
||||
cf forecast --months 12
|
||||
```
|
||||
|
||||
## Архитектура
|
||||
|
||||
Проект разделён на три слоя по принципам Clean Architecture:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ domain/ — бизнес-модели │
|
||||
│ Account, Transaction, Asset, Liability, │
|
||||
│ Recurring, Scenario, FinancialModel, │
|
||||
│ ExchangeRate, CurrencyConverter │
|
||||
│ (pydantic.BaseModel, Decimal) │
|
||||
└──────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────┐
|
||||
│ application/ — прикладные сервисы │
|
||||
│ ForecastService, ScenarioService, │
|
||||
│ ModelRepository (Protocol) │
|
||||
└──────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌──────────────────▼──────────────────────────┐
|
||||
│ infrastructure/ — внешний мир │
|
||||
│ cli/ (Typer), ai/ (Assistant), │
|
||||
│ repositories/ (JsonFile, Excel) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
cashflow-forecast/
|
||||
├── domain/ # Бизнес-модели (pydantic + Decimal)
|
||||
├── cashflow_model/ # Модели данных (dataclass + JSON)
|
||||
│ ├── account.py # Account
|
||||
│ ├── transaction.py # Transaction
|
||||
│ ├── recurring.py # RecurringCashflow
|
||||
│ ├── asset.py # Asset
|
||||
│ ├── liability.py # Liability
|
||||
│ ├── scenario.py # ForecastScenario
|
||||
│ ├── currency.py # ExchangeRate + CurrencyConverter
|
||||
│ └── model.py # FinancialModel (корень)
|
||||
│
|
||||
├── application/ # Прикладные сервисы
|
||||
│ └── model.py # FinancialModel (корень, save/load JSON)
|
||||
├── engine/ # Вычислительное ядро
|
||||
│ ├── forecast.py # ForecastService — прогноз
|
||||
│ ├── scenarios.py # ScenarioService — сценарии + what-if
|
||||
│ └── repositories/
|
||||
│ └── model_repository.py # ModelRepository Protocol
|
||||
│
|
||||
├── infrastructure/ # Адаптеры к внешнему миру
|
||||
│ ├── cli/ # Typer CLI (cf ...)
|
||||
│ │ ├── app.py # Entry point
|
||||
│ │ ├── commands/ # 9 файлов команд + config sub-typer
|
||||
│ │ ├── paths.py # DATA_DIR, MODEL_PATH
|
||||
│ │ ├── services.py # Composition root + helpers
|
||||
│ │ └── i18n.py # ru/en переводы
|
||||
│ ├── ai/ # AI-ассистент (заглушка)
|
||||
│ │ ├── prompts.py
|
||||
│ │ └── assistant.py # AssistantService
|
||||
│ └── repositories/ # Реализации ModelRepository
|
||||
│ ├── json_file_repository.py
|
||||
│ └── excel_repository.py
|
||||
│
|
||||
├── tests/ # pytest, 67 тестов
|
||||
│ ├── conftest.py
|
||||
│ └── scenarios.py # ScenarioService — сценарии + what-if
|
||||
├── sync/ # Синхронизация с Excel
|
||||
│ └── excel_sync.py # ExcelSync — import/export .xlsx
|
||||
├── ai/ # AI-ассистент
|
||||
│ ├── prompts.py # Шаблоны промптов
|
||||
│ └── assistant.py # AssistantService (заглушка)
|
||||
├── cli/ # CLI (Typer)
|
||||
│ └── main.py # Команды: cf init/forecast/scenario/...
|
||||
├── tests/ # Тесты pytest
|
||||
│ ├── conftest.py # Фикстуры
|
||||
│ ├── test_model.py
|
||||
│ ├── test_forecast.py
|
||||
│ ├── test_scenarios.py
|
||||
│ ├── test_currency.py
|
||||
│ ├── test_excel_sync.py
|
||||
│ ├── test_ai.py
|
||||
│ ├── test_cli.py
|
||||
│ ├── test_excel_sync.py # Тесты ExcelRepository
|
||||
│ ├── test_i18n.py
|
||||
│ └── test_repositories.py # Тесты репозиториев
|
||||
│
|
||||
├── data/ # JSON-модели (runtime, версионируется SCHEMA_VERSION=1)
|
||||
│ └── test_cli.py
|
||||
├── data/ # JSON-модели
|
||||
├── exports/ # Экспортированные .xlsx
|
||||
├── .agent/ # Артефакты MetaAgent v3.0
|
||||
├── pyproject.toml # Зависимости + entry point `cf`
|
||||
├── .agent/ # Артефакты MetaAgent (планирование)
|
||||
├── pyproject.toml # Зависимости и конфигурация
|
||||
└── README.arch.md # Оригинальная архитектурная концепция
|
||||
```
|
||||
|
||||
@@ -142,7 +94,7 @@ cashflow-forecast/
|
||||
# Тесты
|
||||
pytest
|
||||
|
||||
# Линтер (если доступен ruff)
|
||||
# Линтер
|
||||
ruff check .
|
||||
|
||||
# Автоформат
|
||||
@@ -155,24 +107,12 @@ ruff format .
|
||||
- openpyxl — работа с Excel
|
||||
- typer — CLI
|
||||
- rich — форматирование вывода
|
||||
- pydantic >= 2.0 — валидация моделей
|
||||
- pytest — тесты
|
||||
- ruff — линтер (опционально)
|
||||
|
||||
## Архитектурные решения
|
||||
|
||||
- **Слои**: `domain/` (модели), `application/` (сервисы), `infrastructure/` (адаптеры).
|
||||
- **Pydantic v2**: все модели — `pydantic.BaseModel` с валидацией (balance >= 0, amount != 0, и т.п.).
|
||||
- **Decimal**: все денежные поля — `Decimal`, арифметика без потери точности.
|
||||
- **Repository pattern**: `ModelRepository` Protocol, реализации `JsonFileRepository` и `ExcelRepository`.
|
||||
- **DI**: Composition root в `infrastructure/cli/services.py:build_services()`.
|
||||
- **Schema versioning**: `FinancialModel.to_dict()` пишет `version: 1`; `from_dict()` поддерживает legacy v0.
|
||||
- **i18n**: `infrastructure/cli/i18n.py`, ru (default) + en (fallback).
|
||||
- ruff — линтер
|
||||
|
||||
## Известные ограничения (MVP)
|
||||
|
||||
- **AI-ассистент** — заглушка (`ai_response: None`). Промпты готовы, но не подключены к API.
|
||||
- **Хранилище** — JSON-файлы (не подходит для многопользовательской работы).
|
||||
- **AI-ассистент** — заглушка. Промпты готовы, но не подключены к API.
|
||||
- **База данных** — JSON-файлы (не подходит для многопользовательской работы).
|
||||
- **Excel** — только `.xlsx` через openpyxl.
|
||||
- **Лицензия** — не выбрана.
|
||||
- **CI/CD** — не настроен.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from ai import prompts
|
||||
from ai.assistant import AssistantError, AssistantService
|
||||
|
||||
__all__ = ["AssistantService", "AssistantError", "prompts"]
|
||||
@@ -0,0 +1,56 @@
|
||||
import json
|
||||
|
||||
from ai import prompts
|
||||
from cashflow_model import FinancialModel
|
||||
from engine.forecast import ForecastService
|
||||
|
||||
|
||||
class AssistantError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AssistantService:
|
||||
def __init__(self, model: FinancialModel):
|
||||
self.model = model
|
||||
|
||||
def analyze(self, months: int = 12) -> dict:
|
||||
forecast_service = ForecastService(self.model)
|
||||
forecast_result = forecast_service.forecast_cashflow(months)
|
||||
summary = forecast_service.summary(months)
|
||||
|
||||
prompt = prompts.format_context(
|
||||
model_json=json.dumps(self.model.to_dict(), indent=2, ensure_ascii=False),
|
||||
forecast_json=json.dumps(forecast_result, indent=2, ensure_ascii=False),
|
||||
months=months,
|
||||
)
|
||||
|
||||
return {
|
||||
"prompt": prompt,
|
||||
"summary": summary,
|
||||
"forecast": forecast_result,
|
||||
"ai_response": None,
|
||||
}
|
||||
|
||||
def advice(self, question: str, months: int = 12) -> dict:
|
||||
forecast_service = ForecastService(self.model)
|
||||
forecast_result = forecast_service.forecast_cashflow(months)
|
||||
|
||||
prompt = prompts.ADVICE_PROMPT.format(
|
||||
model_json=json.dumps(self.model.to_dict(), indent=2, ensure_ascii=False),
|
||||
forecast_json=json.dumps(forecast_result, indent=2, ensure_ascii=False),
|
||||
question=question,
|
||||
)
|
||||
|
||||
return {
|
||||
"prompt": prompt,
|
||||
"ai_response": None,
|
||||
}
|
||||
|
||||
def compare_scenarios(self, scenarios_json: str) -> dict:
|
||||
prompt = prompts.SCENARIO_COMPARISON_PROMPT.format(
|
||||
scenarios_json=scenarios_json,
|
||||
)
|
||||
return {
|
||||
"prompt": prompt,
|
||||
"ai_response": None,
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
ANALYZE_PROMPT = """
|
||||
Ты — финансовый AI-ассистент. Проанализируй финансовую модель пользователя.
|
||||
|
||||
### Модель (JSON):
|
||||
{model_json}
|
||||
|
||||
### Прогноз на {months} месяцев:
|
||||
{forecast_json}
|
||||
|
||||
Дай анализ по пунктам:
|
||||
1. Общее финансовое состояние
|
||||
2. Тренд денежного потока (рост/падение)
|
||||
3. Достаточность ликвидности
|
||||
4. Рекомендации по улучшению
|
||||
"""
|
||||
|
||||
ADVICE_PROMPT = """
|
||||
Ты — финансовый AI-ассистент. Дай персональные рекомендации.
|
||||
|
||||
### Модель:
|
||||
{model_json}
|
||||
|
||||
### Прогноз:
|
||||
{forecast_json}
|
||||
|
||||
Вопрос пользователя: {question}
|
||||
|
||||
Ответь как опытный финансовый консультант.
|
||||
"""
|
||||
|
||||
SCENARIO_COMPARISON_PROMPT = """
|
||||
Ты — финансовый AI-ассистент. Сравни сценарии прогноза.
|
||||
|
||||
### Результаты сценариев:
|
||||
{scenarios_json}
|
||||
|
||||
Дай рекомендацию: какой сценарий наиболее вероятен и почему.
|
||||
"""
|
||||
|
||||
|
||||
def format_context(model_json: str, forecast_json: str, months: int = 12) -> str:
|
||||
return ANALYZE_PROMPT.format(
|
||||
model_json=model_json,
|
||||
forecast_json=forecast_json,
|
||||
months=months,
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
from application.forecast import ForecastError, ForecastService
|
||||
from application.scenarios import DEFAULT_SCENARIOS, ScenarioError, ScenarioService
|
||||
|
||||
__all__ = [
|
||||
"ForecastService",
|
||||
"ForecastError",
|
||||
"ScenarioService",
|
||||
"ScenarioError",
|
||||
"DEFAULT_SCENARIOS",
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
from application.repositories.model_repository import ModelRepository
|
||||
|
||||
__all__ = ["ModelRepository"]
|
||||
@@ -1,20 +0,0 @@
|
||||
"""Repository protocol для хранения FinancialModel.
|
||||
|
||||
Определяет контракт: load(path) -> FinancialModel, save(model, path) -> None.
|
||||
Реализации: JsonFileRepository, ExcelRepository.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Protocol, runtime_checkable
|
||||
|
||||
from domain import FinancialModel
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class ModelRepository(Protocol):
|
||||
"""Любой storage, способный прочитать и записать FinancialModel."""
|
||||
|
||||
def load(self, path: str | Path) -> FinancialModel: ...
|
||||
|
||||
def save(self, model: FinancialModel, path: str | Path) -> None: ...
|
||||
@@ -0,0 +1,17 @@
|
||||
from cashflow_model.account import Account
|
||||
from cashflow_model.asset import Asset
|
||||
from cashflow_model.liability import Liability
|
||||
from cashflow_model.model import FinancialModel
|
||||
from cashflow_model.recurring import RecurringCashflow
|
||||
from cashflow_model.scenario import ForecastScenario
|
||||
from cashflow_model.transaction import Transaction
|
||||
|
||||
__all__ = [
|
||||
"Account",
|
||||
"Transaction",
|
||||
"RecurringCashflow",
|
||||
"Asset",
|
||||
"Liability",
|
||||
"ForecastScenario",
|
||||
"FinancialModel",
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class Account:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
currency: str = "USD"
|
||||
balance: float = 0.0
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"currency": self.currency,
|
||||
"balance": self.balance,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "Account":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
name=data["name"],
|
||||
currency=data.get("currency", "USD"),
|
||||
balance=data.get("balance", 0.0),
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class Asset:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
value: float = 0.0
|
||||
growth_rate: float = 0.0
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"value": self.value,
|
||||
"growth_rate": self.growth_rate,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "Asset":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
name=data["name"],
|
||||
value=data.get("value", 0.0),
|
||||
growth_rate=data.get("growth_rate", 0.0),
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class Liability:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
balance: float = 0.0
|
||||
interest: float = 0.0
|
||||
payment: float = 0.0
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"balance": self.balance,
|
||||
"interest": self.interest,
|
||||
"payment": self.payment,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "Liability":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
name=data["name"],
|
||||
balance=data.get("balance", 0.0),
|
||||
interest=data.get("interest", 0.0),
|
||||
payment=data.get("payment", 0.0),
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
from cashflow_model.account import Account
|
||||
from cashflow_model.asset import Asset
|
||||
from cashflow_model.liability import Liability
|
||||
from cashflow_model.recurring import RecurringCashflow
|
||||
from cashflow_model.scenario import ForecastScenario
|
||||
from cashflow_model.transaction import Transaction
|
||||
|
||||
|
||||
@dataclass
|
||||
class FinancialModel:
|
||||
accounts: list[Account] = field(default_factory=list)
|
||||
transactions: list[Transaction] = field(default_factory=list)
|
||||
recurring: list[RecurringCashflow] = field(default_factory=list)
|
||||
assets: list[Asset] = field(default_factory=list)
|
||||
liabilities: list[Liability] = field(default_factory=list)
|
||||
scenarios: list[ForecastScenario] = field(default_factory=list)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"accounts": [a.to_dict() for a in self.accounts],
|
||||
"transactions": [t.to_dict() for t in self.transactions],
|
||||
"recurring": [r.to_dict() for r in self.recurring],
|
||||
"assets": [a.to_dict() for a in self.assets],
|
||||
"liabilities": [li.to_dict() for li in self.liabilities],
|
||||
"scenarios": [s.to_dict() for s in self.scenarios],
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "FinancialModel":
|
||||
return cls(
|
||||
accounts=[Account.from_dict(a) for a in data.get("accounts", [])],
|
||||
transactions=[Transaction.from_dict(t) for t in data.get("transactions", [])],
|
||||
recurring=[RecurringCashflow.from_dict(r) for r in data.get("recurring", [])],
|
||||
assets=[Asset.from_dict(a) for a in data.get("assets", [])],
|
||||
liabilities=[Liability.from_dict(li) for li in data.get("liabilities", [])],
|
||||
scenarios=[ForecastScenario.from_dict(s) for s in data.get("scenarios", [])],
|
||||
)
|
||||
|
||||
def save(self, path: str | Path) -> None:
|
||||
path = Path(path)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
|
||||
|
||||
@classmethod
|
||||
def load(cls, path: str | Path) -> "FinancialModel":
|
||||
path = Path(path)
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return cls.from_dict(data)
|
||||
@@ -0,0 +1,33 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class RecurringCashflow:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
start_date: str = ""
|
||||
end_date: str = ""
|
||||
frequency: str = "monthly"
|
||||
amount: float = 0.0
|
||||
category: str = ""
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"start_date": self.start_date,
|
||||
"end_date": self.end_date,
|
||||
"frequency": self.frequency,
|
||||
"amount": self.amount,
|
||||
"category": self.category,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "RecurringCashflow":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
start_date=data.get("start_date", ""),
|
||||
end_date=data.get("end_date", ""),
|
||||
frequency=data.get("frequency", "monthly"),
|
||||
amount=data.get("amount", 0.0),
|
||||
category=data.get("category", ""),
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class ForecastScenario:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
name: str = "baseline"
|
||||
income_multiplier: float = 1.0
|
||||
expense_multiplier: float = 1.0
|
||||
growth_multiplier: float = 1.0
|
||||
description: str = ""
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"income_multiplier": self.income_multiplier,
|
||||
"expense_multiplier": self.expense_multiplier,
|
||||
"growth_multiplier": self.growth_multiplier,
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "ForecastScenario":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
name=data["name"],
|
||||
income_multiplier=data.get("income_multiplier", 1.0),
|
||||
expense_multiplier=data.get("expense_multiplier", 1.0),
|
||||
growth_multiplier=data.get("growth_multiplier", 1.0),
|
||||
description=data.get("description", ""),
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
from dataclasses import dataclass, field
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
|
||||
@dataclass
|
||||
class Transaction:
|
||||
id: UUID = field(default_factory=uuid4)
|
||||
date: str = ""
|
||||
account: str = ""
|
||||
category: str = ""
|
||||
amount: float = 0.0
|
||||
description: str = ""
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"date": self.date,
|
||||
"account": self.account,
|
||||
"category": self.category,
|
||||
"amount": self.amount,
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "Transaction":
|
||||
return cls(
|
||||
id=UUID(data["id"]),
|
||||
date=data["date"],
|
||||
account=data.get("account", ""),
|
||||
category=data.get("category", ""),
|
||||
amount=data.get("amount", 0.0),
|
||||
description=data.get("description", ""),
|
||||
)
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from ai.assistant import AssistantService
|
||||
from cashflow_model import FinancialModel
|
||||
from engine.forecast import ForecastService
|
||||
from engine.scenarios import DEFAULT_SCENARIOS, ScenarioService
|
||||
from sync.excel_sync import ExcelSync
|
||||
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except (AttributeError, OSError):
|
||||
pass
|
||||
|
||||
app = typer.Typer(name="cf", help="CashFlow Forecast - personal finance model")
|
||||
console = Console()
|
||||
|
||||
DATA_DIR = Path("data")
|
||||
MODEL_PATH = DATA_DIR / "model.json"
|
||||
|
||||
|
||||
def _load_model() -> FinancialModel:
|
||||
if MODEL_PATH.exists():
|
||||
return FinancialModel.load(MODEL_PATH)
|
||||
return FinancialModel()
|
||||
|
||||
|
||||
def _save_model(model: FinancialModel) -> None:
|
||||
model.save(MODEL_PATH)
|
||||
|
||||
|
||||
@app.command()
|
||||
def init() -> None:
|
||||
"""Создать пустую финансовую модель"""
|
||||
model = FinancialModel()
|
||||
_save_model(model)
|
||||
console.print("[green]OK[/green] Пустая модель создана в data/model.json")
|
||||
|
||||
|
||||
@app.command()
|
||||
def forecast(
|
||||
months: int = typer.Option(12, "--months", "-m", help="Количество месяцев прогноза"),
|
||||
) -> None:
|
||||
"""Запустить прогноз денежных потоков"""
|
||||
model = _load_model()
|
||||
service = ForecastService(model)
|
||||
results = service.forecast_cashflow(months)
|
||||
summary = service.summary(months)
|
||||
|
||||
if results:
|
||||
table = Table(title=f"Прогноз на {months} мес.")
|
||||
table.add_column("Счёт", style="cyan")
|
||||
table.add_column("Месяц", style="white")
|
||||
table.add_column("Баланс", justify="right", style="green")
|
||||
table.add_column("Доход", justify="right")
|
||||
table.add_column("Расход", justify="right")
|
||||
|
||||
for r in results:
|
||||
table.add_row(
|
||||
r["account"], str(r["month"]),
|
||||
f"${r['balance']:.2f}",
|
||||
f"${r['income']:.2f}",
|
||||
f"${r['expenses']:.2f}",
|
||||
)
|
||||
console.print(table)
|
||||
|
||||
console.print(f"\n[bold]Итог:[/bold] Баланс: ${summary['total_balance']:.2f} | "
|
||||
f"Доход: ${summary['total_income']:.2f} | "
|
||||
f"Расход: ${summary['total_expenses']:.2f}")
|
||||
|
||||
|
||||
@app.command()
|
||||
def scenario(
|
||||
name: str = typer.Argument("baseline", help="Имя сценария: baseline, optimistic, pessimistic"),
|
||||
months: int = typer.Option(12, "--months", "-m", help="Количество месяцев"),
|
||||
) -> None:
|
||||
"""Применить сценарий и показать прогноз"""
|
||||
model = _load_model()
|
||||
service = ScenarioService(model)
|
||||
|
||||
if name in DEFAULT_SCENARIOS:
|
||||
scenario_obj = DEFAULT_SCENARIOS[name]
|
||||
else:
|
||||
console.print(f"[red]Неизвестный сценарий: {name}[/red]")
|
||||
console.print(f"Доступны: {', '.join(DEFAULT_SCENARIOS.keys())}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
result = service.apply(scenario_obj, months)
|
||||
console.print(f"[bold]Сценарий:[/bold] {result['scenario']}")
|
||||
console.print(f"[dim]{result['scenario_description']}[/dim]")
|
||||
console.print(f"Баланс: ${result['total_balance']:.2f}")
|
||||
console.print(f"Доход: ${result['total_income']:.2f}")
|
||||
console.print(f"Расход: ${result['total_expenses']:.2f}")
|
||||
|
||||
|
||||
@app.command()
|
||||
def whatif(
|
||||
income_mult: float = typer.Option(1.0, "--income", "-i", help="Множитель дохода"),
|
||||
expense_mult: float = typer.Option(1.0, "--expense", "-e", help="Множитель расхода"),
|
||||
growth_mult: float = typer.Option(1.0, "--growth", "-g", help="Множитель роста активов"),
|
||||
months: int = typer.Option(12, "--months", "-m", help="Количество месяцев"),
|
||||
) -> None:
|
||||
"""What-if анализ с произвольными множителями"""
|
||||
model = _load_model()
|
||||
service = ScenarioService(model)
|
||||
result = service.what_if(income_mult, expense_mult, growth_mult, months)
|
||||
|
||||
console.print("[bold]What-if анализ[/bold]")
|
||||
console.print(f"Доход x{income_mult} | Расход x{expense_mult} | Рост x{growth_mult}")
|
||||
console.print(f"Баланс: ${result['total_balance']:.2f}")
|
||||
console.print(f"Доход: ${result['total_income']:.2f}")
|
||||
console.print(f"Расход: ${result['total_expenses']:.2f}")
|
||||
|
||||
|
||||
@app.command()
|
||||
def compare(
|
||||
months: int = typer.Option(12, "--months", "-m", help="Количество месяцев"),
|
||||
) -> None:
|
||||
"""Сравнить все сценарии"""
|
||||
model = _load_model()
|
||||
service = ScenarioService(model)
|
||||
results = service.compare(months)
|
||||
|
||||
table = Table(title="Сравнение сценариев")
|
||||
table.add_column("Сценарий", style="cyan")
|
||||
table.add_column("Баланс", justify="right")
|
||||
table.add_column("Доход", justify="right")
|
||||
table.add_column("Расход", justify="right")
|
||||
|
||||
for name, r in results.items():
|
||||
table.add_row(
|
||||
name,
|
||||
f"${r['total_balance']:.2f}",
|
||||
f"${r['total_income']:.2f}",
|
||||
f"${r['total_expenses']:.2f}",
|
||||
)
|
||||
console.print(table)
|
||||
|
||||
|
||||
@app.command()
|
||||
def import_xlsx(
|
||||
path: str = typer.Argument(..., help="Путь к .xlsx файлу"),
|
||||
) -> None:
|
||||
"""Импорт данных из Excel"""
|
||||
sync = ExcelSync()
|
||||
try:
|
||||
model = sync.import_model(path)
|
||||
_save_model(model)
|
||||
console.print(f"[green]OK[/green] Импортировано: {len(model.accounts)} счетов, "
|
||||
f"{len(model.transactions)} транзакций, "
|
||||
f"{len(model.recurring)} регулярных платежей, "
|
||||
f"{len(model.assets)} активов, "
|
||||
f"{len(model.liabilities)} обязательств")
|
||||
except Exception as e:
|
||||
console.print(f"[red]Ошибка импорта: {e}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@app.command()
|
||||
def export_xlsx(
|
||||
path: str = typer.Argument("exports/forecast.xlsx", help="Путь для .xlsx файла"),
|
||||
) -> None:
|
||||
"""Экспорт модели в Excel"""
|
||||
model = _load_model()
|
||||
sync = ExcelSync()
|
||||
try:
|
||||
sync.export_model(model, path)
|
||||
console.print(f"[green]OK[/green] Модель экспортирована в {path}")
|
||||
except Exception as e:
|
||||
console.print(f"[red]Ошибка экспорта: {e}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@app.command()
|
||||
def analyze(
|
||||
months: int = typer.Option(12, "--months", "-m", help="Количество месяцев для анализа"),
|
||||
) -> None:
|
||||
"""AI-анализ финансовой модели"""
|
||||
model = _load_model()
|
||||
assistant = AssistantService(model)
|
||||
result = assistant.analyze(months)
|
||||
|
||||
console.print("[bold]Промпт для AI:[/bold]")
|
||||
console.print(result["prompt"][:500] + "...\n")
|
||||
|
||||
console.print("[bold]Сводка:[/bold]")
|
||||
s = result["summary"]
|
||||
console.print(f"Баланс: ${s['total_balance']:.2f}")
|
||||
console.print(f"Доход: ${s['total_income']:.2f}")
|
||||
console.print(f"Расход: ${s['total_expenses']:.2f}")
|
||||
console.print(
|
||||
"\n[yellow]AI-ответ: заглушка. Подключите реальный API в ai/assistant.py[/yellow]"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
Binary file not shown.
+36
-19
@@ -1,31 +1,48 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_currency": "RUB",
|
||||
"accounts": [
|
||||
{
|
||||
"id": "633c38bd-acdf-4e40-b7ef-64188e3a741d",
|
||||
"name": "Основной",
|
||||
"id": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"name": "Основной счёт",
|
||||
"currency": "RUB",
|
||||
"balance": "50000.0"
|
||||
"balance": 20000.0
|
||||
}
|
||||
],
|
||||
"transactions": [],
|
||||
"recurring": [],
|
||||
"assets": [
|
||||
"recurring": [
|
||||
{
|
||||
"id": "d15f81dd-8235-4f93-8452-ba0db359d843",
|
||||
"name": "Акции",
|
||||
"value": "100000.0",
|
||||
"growth_rate": "8.0"
|
||||
"id": "550e8400-e29b-41d4-a716-446655440010",
|
||||
"start_date": "2026-07-01",
|
||||
"end_date": "",
|
||||
"frequency": "monthly",
|
||||
"amount": 30000.0,
|
||||
"category": "Зарплата"
|
||||
},
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440020",
|
||||
"start_date": "2026-07-01",
|
||||
"end_date": "",
|
||||
"frequency": "monthly",
|
||||
"amount": -500.0,
|
||||
"category": "VDS"
|
||||
},
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440021",
|
||||
"start_date": "2026-07-01",
|
||||
"end_date": "",
|
||||
"frequency": "monthly",
|
||||
"amount": -300.0,
|
||||
"category": "Шампунь"
|
||||
},
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440022",
|
||||
"start_date": "2026-07-01",
|
||||
"end_date": "",
|
||||
"frequency": "monthly",
|
||||
"amount": -1500.0,
|
||||
"category": "Токены AI"
|
||||
}
|
||||
],
|
||||
"assets": [],
|
||||
"liabilities": [],
|
||||
"scenarios": [],
|
||||
"exchange_rates": [
|
||||
{
|
||||
"from_currency": "USD",
|
||||
"to_currency": "RUB",
|
||||
"rate": "80"
|
||||
}
|
||||
]
|
||||
"scenarios": []
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
from domain.account import Account
|
||||
from domain.asset import Asset
|
||||
from domain.currency import CURRENCY_SYMBOLS, CurrencyConverter, CurrencyError, ExchangeRate
|
||||
from domain.liability import Liability
|
||||
from domain.model import FinancialModel
|
||||
from domain.recurring import RecurringCashflow
|
||||
from domain.scenario import ForecastScenario
|
||||
from domain.transaction import Transaction
|
||||
|
||||
__all__ = [
|
||||
"Account",
|
||||
"Transaction",
|
||||
"RecurringCashflow",
|
||||
"Asset",
|
||||
"Liability",
|
||||
"ForecastScenario",
|
||||
"FinancialModel",
|
||||
"ExchangeRate",
|
||||
"CurrencyConverter",
|
||||
"CurrencyError",
|
||||
"CURRENCY_SYMBOLS",
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class Account(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
currency: str = "USD"
|
||||
balance: Decimal = Field(default=Decimal("0"))
|
||||
|
||||
@field_validator("balance")
|
||||
@classmethod
|
||||
def _balance_non_negative(cls, v: Decimal) -> Decimal:
|
||||
if v < 0:
|
||||
raise ValueError("balance must be non-negative")
|
||||
return v
|
||||
@@ -1,11 +0,0 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Asset(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
value: Decimal = Field(default=Decimal("0"))
|
||||
growth_rate: Decimal = Field(default=Decimal("0"))
|
||||
@@ -1,83 +0,0 @@
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
CURRENCY_SYMBOLS = {
|
||||
"RUB": "₽",
|
||||
"USD": "$",
|
||||
"EUR": "€",
|
||||
"GBP": "£",
|
||||
"CNY": "¥",
|
||||
"JPY": "¥",
|
||||
"KZT": "₸",
|
||||
"UAH": "₴",
|
||||
}
|
||||
|
||||
|
||||
class ExchangeRate(BaseModel):
|
||||
from_currency: str = "USD"
|
||||
to_currency: str = "RUB"
|
||||
rate: Decimal = Field(default=Decimal("80"))
|
||||
|
||||
@field_validator("rate")
|
||||
@classmethod
|
||||
def _rate_positive(cls, v: Decimal) -> Decimal:
|
||||
if v <= 0:
|
||||
raise ValueError("rate must be positive")
|
||||
return v
|
||||
|
||||
|
||||
DEFAULT_RATES: list[ExchangeRate] = [
|
||||
ExchangeRate(from_currency="USD", to_currency="RUB", rate=Decimal("80")),
|
||||
]
|
||||
|
||||
|
||||
class CurrencyError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CurrencyConverter:
|
||||
def __init__(self, rates: list[ExchangeRate] | None = None):
|
||||
self._rates: dict[tuple[str, str], Decimal] = {}
|
||||
if rates:
|
||||
for r in rates:
|
||||
self.set_rate(r.from_currency, r.to_currency, r.rate)
|
||||
|
||||
def set_rate(
|
||||
self,
|
||||
from_currency: str,
|
||||
to_currency: str,
|
||||
rate: Decimal | float | int | str,
|
||||
) -> None:
|
||||
d = Decimal(str(rate)) if not isinstance(rate, Decimal) else rate
|
||||
if d <= 0:
|
||||
raise CurrencyError(f"Rate must be positive: {d}")
|
||||
self._rates[(from_currency, to_currency)] = d
|
||||
self._rates[(to_currency, from_currency)] = Decimal("1") / d
|
||||
|
||||
def get_rate(self, from_currency: str, to_currency: str) -> Decimal:
|
||||
if from_currency == to_currency:
|
||||
return Decimal("1")
|
||||
try:
|
||||
return self._rates[(from_currency, to_currency)]
|
||||
except KeyError:
|
||||
raise CurrencyError(f"No exchange rate: {from_currency} → {to_currency}")
|
||||
|
||||
def convert(
|
||||
self,
|
||||
amount: Decimal | float | int | str,
|
||||
from_currency: str,
|
||||
to_currency: str,
|
||||
) -> Decimal:
|
||||
a = Decimal(str(amount)) if not isinstance(amount, Decimal) else amount
|
||||
if from_currency == to_currency:
|
||||
return a
|
||||
rate = self.get_rate(from_currency, to_currency)
|
||||
return (a * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||
|
||||
def get_symbol(self, currency: str) -> str:
|
||||
return CURRENCY_SYMBOLS.get(currency, currency)
|
||||
|
||||
@classmethod
|
||||
def with_defaults(cls) -> "CurrencyConverter":
|
||||
return cls(DEFAULT_RATES)
|
||||
@@ -1,19 +0,0 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class Liability(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
name: str = ""
|
||||
balance: Decimal = Field(default=Decimal("0"))
|
||||
interest: Decimal = Field(default=Decimal("0"))
|
||||
payment: Decimal = Field(default=Decimal("0"))
|
||||
|
||||
@field_validator("interest", "payment")
|
||||
@classmethod
|
||||
def _non_negative(cls, v: Decimal) -> Decimal:
|
||||
if v < 0:
|
||||
raise ValueError("must be non-negative")
|
||||
return v
|
||||
@@ -1,71 +0,0 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from domain.account import Account
|
||||
from domain.asset import Asset
|
||||
from domain.currency import DEFAULT_RATES, ExchangeRate
|
||||
from domain.liability import Liability
|
||||
from domain.recurring import RecurringCashflow
|
||||
from domain.scenario import ForecastScenario
|
||||
from domain.transaction import Transaction
|
||||
|
||||
|
||||
class FinancialModel(BaseModel):
|
||||
"""Корневая модель финансового плана.
|
||||
|
||||
Сериализация (save/load) вынесена в `application.repositories.ModelRepository` —
|
||||
JsonFileRepository и ExcelRepository. Сам класс хранит только данные.
|
||||
"""
|
||||
|
||||
SCHEMA_VERSION: int = 1 # NB: не Field — это class-level metadata, не pydantic field
|
||||
|
||||
base_currency: str = "RUB"
|
||||
accounts: list[Account] = Field(default_factory=list)
|
||||
transactions: list[Transaction] = Field(default_factory=list)
|
||||
recurring: list[RecurringCashflow] = Field(default_factory=list)
|
||||
assets: list[Asset] = Field(default_factory=list)
|
||||
liabilities: list[Liability] = Field(default_factory=list)
|
||||
scenarios: list[ForecastScenario] = Field(default_factory=list)
|
||||
exchange_rates: list[ExchangeRate] = Field(
|
||||
default_factory=lambda: [r.model_copy() for r in DEFAULT_RATES]
|
||||
)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Сериализация в dict с version и UUID-as-str (для JSON)."""
|
||||
return {
|
||||
"version": self.SCHEMA_VERSION,
|
||||
"base_currency": self.base_currency,
|
||||
"accounts": [a.model_dump(mode="json") for a in self.accounts],
|
||||
"transactions": [t.model_dump(mode="json") for t in self.transactions],
|
||||
"recurring": [r.model_dump(mode="json") for r in self.recurring],
|
||||
"assets": [a.model_dump(mode="json") for a in self.assets],
|
||||
"liabilities": [li.model_dump(mode="json") for li in self.liabilities],
|
||||
"scenarios": [s.model_dump(mode="json") for s in self.scenarios],
|
||||
"exchange_rates": [e.model_dump(mode="json") for e in self.exchange_rates],
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "FinancialModel":
|
||||
version = data.get("version", 0)
|
||||
if version == 0:
|
||||
return cls._from_legacy(data)
|
||||
if version == 1:
|
||||
return cls._from_v1(data)
|
||||
raise ValueError(f"Unsupported FinancialModel version: {version}")
|
||||
|
||||
@classmethod
|
||||
def _from_v1(cls, data: dict) -> "FinancialModel":
|
||||
return cls(
|
||||
base_currency=data.get("base_currency", "RUB"),
|
||||
accounts=[Account.model_validate(a) for a in data.get("accounts", [])],
|
||||
transactions=[Transaction.model_validate(t) for t in data.get("transactions", [])],
|
||||
recurring=[RecurringCashflow.model_validate(r) for r in data.get("recurring", [])],
|
||||
assets=[Asset.model_validate(a) for a in data.get("assets", [])],
|
||||
liabilities=[Liability.model_validate(li) for li in data.get("liabilities", [])],
|
||||
scenarios=[ForecastScenario.model_validate(s) for s in data.get("scenarios", [])],
|
||||
exchange_rates=[ExchangeRate.model_validate(r) for r in data.get("exchange_rates", [])],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _from_legacy(cls, data: dict) -> "FinancialModel":
|
||||
# Legacy: файлы без version. Структура совпадает с v1.
|
||||
return cls._from_v1(data)
|
||||
@@ -1,27 +0,0 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class RecurringCashflow(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
start_date: str = ""
|
||||
end_date: str = ""
|
||||
frequency: str = "monthly"
|
||||
amount: Decimal = Field(default=Decimal("0"))
|
||||
category: str = ""
|
||||
|
||||
@field_validator("frequency")
|
||||
@classmethod
|
||||
def _frequency_known(cls, v: str) -> str:
|
||||
if v not in {"daily", "weekly", "monthly", "yearly"}:
|
||||
raise ValueError(f"unknown frequency: {v}")
|
||||
return v
|
||||
|
||||
@field_validator("amount")
|
||||
@classmethod
|
||||
def _amount_nonzero(cls, v: Decimal) -> Decimal:
|
||||
if v == 0:
|
||||
raise ValueError("amount must be non-zero")
|
||||
return v
|
||||
@@ -1,20 +0,0 @@
|
||||
from decimal import Decimal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class ForecastScenario(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
name: str = "baseline"
|
||||
income_multiplier: Decimal = Field(default=Decimal("1"))
|
||||
expense_multiplier: Decimal = Field(default=Decimal("1"))
|
||||
growth_multiplier: Decimal = Field(default=Decimal("1"))
|
||||
description: str = ""
|
||||
|
||||
@field_validator("income_multiplier", "expense_multiplier", "growth_multiplier")
|
||||
@classmethod
|
||||
def _non_negative(cls, v: Decimal) -> Decimal:
|
||||
if v < 0:
|
||||
raise ValueError("multiplier must be non-negative")
|
||||
return v
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user