protobuf.mod
Идентичность модуля, roots, прямые и транзитивные Git-зависимости.
user graph selects common v1.3.0 and weather v2.1.0. Numerically, v1.3.0 satisfies both common minimums; dependency resolution does not prove schema compatibility. Run easyp breaking separately for that check.
-1. **Explicit Version Bounds**: Every requirement in `protobuf.mod` specifies an explicit baseline version (e.g., `github.com/acme/weather v1.2.0`). This version is treated as a *minimum requirement*, not a range constraint.
-2. **Maximum of Minimums**: When multiple modules in a dependency graph request different minimum versions of the same dependency, MVS selects the **maximum** of those requested minimum versions.
-3. **High-Water Mark Determinism**: The resulting selected version is guaranteed to satisfy all minimum requirements without requiring complex backtracking or unexpected automatic major upgrades.
+If user pins a SHA, the selected common v1.3.0 tag must point to that exact commit. A v1.2.0 tag at that SHA is insufficient when the maximum requirement is v1.3.0. If user's common requirement has no version, weather's semantic minimum determines the selection.
----
+## Module and descriptor boundaries
-## 2. Step-by-Step Diamond Dependency Graph Resolution
-
-A classic challenge in module dependency management is the "Diamond Dependency" pattern. Consider a scenario where a primary module `user` depends directly on both `common` and `weather`, while `weather` itself depends transitively on an updated version of `common`.
-
-### Graph Structure
-
-```text
- +-------------------+
- | proto/user | (Root Module)
- +---------+---------+
- |
- +-------------+-------------+
- | |
- v v
-+---------------------+ +---------------------+
-| github.com/acme/ | | github.com/acme/ |
-| common v1.2.0 | | weather v2.1.0 |
-+---------------------+ +----------+----------+
- |
- v
- +---------------------+
- | github.com/acme/ |
- | common v1.3.0 |
- +---------------------+
-```
-
-### Step-by-Step MVS Traversal
-
-protobuf.mod and protobuf.lock. For example, proto/user can select common v1.3.0 while proto/order selects common v2.0.0 in an independent graph.
----
+Independent graphs do not guarantee that their combined generation output is compatible:
-## 3. `protobuf.mod` DSL Directives
+| Output | Validation |
+| --- | --- |
+| --descriptor_set_out | Merges compatible graphs; conflicting definitions by import path or symbol are errors |
+| --descriptor_set_out_dir | Independent set per project/module pair; graphs are not merged |
+| Plugin output | Identical shared files are deduplicated; different contents at one path or Go packages sharing a directory are errors |
-The `protobuf.mod` file resides in the root directory of a Protobuf module. It is a tool-neutral specification focused exclusively on dependency declaration.
+Managed options remain part of compatibility checks. Different dependency versions can have compatible descriptors, while different consumer settings can make them incompatible. --include_imports affects exported contents only; the full graph is always validated. Plugin import generation is separately controlled by with_imports, default false.
-```protobuf
-// proto/user/protobuf.mod
+## Manifest and local replacements
+~~~text
module github.com/acme/user
-
-roots (
- proto
-)
-
+roots proto
require (
- github.com/googleapis/googleapis v1.5.0
- github.com/acme/weather v1.2.3
- github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect
+ github.com/acme/common v1.2.0
+ github.com/acme/weather v2.1.0
)
-
-// Local debug override
replace github.com/acme/weather => ../weather-fork
-```
+~~~
-### Directive Reference
+roots is relative to the manifest directory and defaults to .. The get and mod commands find the nearest ancestor manifest within the workspace. Transitive requirements are recorded with // indirect.
-- **`module`**: Declares the canonical module identity (URL/path). Optional when the Git URL matches repository layout.
-- **`roots`**: Defines the inner directory root containing `.proto` schema files (defaults to `.`). This ensures imports resolve cleanly without requiring prefix manipulation.
-- **`require`**: Declares direct and indirect module dependencies with explicit Semantic Version tags.
- - **`// indirect`**: Appended automatically by `easyp mod tidy` for transitive dependencies not directly imported by the root module's `.proto` files.
-- **`replace`**: Overrides a module dependency with a local file path (`../weather-fork`) or an alternative Git repository/version. Useful for local development and debugging.
+A relative replace target is resolved from its owning protobuf.mod; an absolute target is used directly. Generation and linting support local replacements. get, mod tidy, mod update, and mod vendor reject them: remove replacements before these commands create or use a reproducible Git lock. This is command validation, not a CI rule rejecting commits.
-v1.2.3 of a module in proto/user uses tag proto/user/v1.2.3.
----
+## Locks and immutable published versions
-## 4. Hermetic `protobuf.lock` Mechanism
+protobuf.lock records the source, selected tag or SHA, exact commit, and content hash. It is created by get, mod tidy, and mod update. mod download uses exact locked commits. The example below illustrates the format, not actual repository data.
-The `protobuf.lock` file is an auto-generated artifact created and maintained by EasyP commands (`easyp mod tidy` and `easyp mod update`).
-
-```yaml
-# protobuf.lock - GENERATED FILE, DO NOT EDIT MANUALLY
+~~~yaml
version: 1
modules:
- - source: github.com/googleapis/googleapis
- version: v1.5.0
- commit: 8f3a1c94b2e10a84e
- hash: h1:a9F8zK...
- - source: github.com/acme/weather
- version: v1.2.3
- commit: 51d2e071c89f33b11
- hash: h1:x7B3mL...
- - source: github.com/grpc-ecosystem/grpc-gateway
- version: v2.19.0
- commit: c4f88aa91024e12c4
- hash: h1:p0Q1wK...
-```
-
-### Guaranteed Hermetic Builds
-
-1. **Strict Locking**: CI pipelines execute `easyp mod download` against `protobuf.lock`. Neither network fluctuations nor registry state can change the downloaded schema versions.
-2. **Digest Verification**: The `hash` attribute validates content integrity against cache tampering or force-pushed Git tags.
-3. **Explicit Lifecycle**: `protobuf.lock` is only updated via explicit developer execution of `easyp mod tidy` or `easyp mod update`.
+ - source: github.com/acme/common
+ version: v1.3.0
+ commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+~~~
----
+During tidy, get, and update, a fetched previously locked SemVer must match its recorded commit and hash. A mismatch raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock, including for transitive requirements and warm caches. A new version may be selected; unconstrained versionless requirements still refresh to HEAD, while explicit SHAs stay pinned.
-## 5. Architectural Comparison
+mod download can retrieve the old commit after a tag moves if that commit remains available. The Go dirhash.Hash1 digest covers Git-tracked regular files with repository-relative paths. Both newly downloaded and installed cached files are verified.
-| Feature / Model | EasyP MVS | Go Modules (MVS) | Cargo / Rust (PubGrub SAT) | Buf v2 (Workspace SVS) |
-| --- | --- | --- | --- | --- |
-| **Algorithm** | Minimal Version Selection | Minimal Version Selection | SAT Solver (PubGrub) | Workspace Single Version |
-| **Selection Rule** | `max(minimums)` | `max(minimums)` | Complex SemVer Ranges (`^1.2.3`) | Global Single Version |
-| **Dependency Scope** | Per-module | Per-module | Per-crate | Entire Workspace |
-| **Multiple Versions in Binary** | Forbidden (FQN collision) | Allowed across major versions | Allowed across major versions | Forbidden |
-| **Lockfile** | `protobuf.lock` | `go.sum` | `Cargo.lock` | `buf.lock` |
-| **Local Override** | `replace` directive | `replace` directive | `[patch]` / `path` | Local workspace module |
+## Git object reuse
-### Why MVS Fits Protobuf Schemas Best
+A shared object store is used per remote. Known exact commits can be reused without remote access. The first attempt fetches the requested commit at depth one. If a server rejects a historical SHA, EasyP fetches advertised reachable history and still requires the original commit; HEAD is never substituted. A cold fetch is therefore not always shallow. Tag lookups are refreshed separately so cache reuse cannot hide republishing.
-Protobuf schemas enforce strict package name and message Fully Qualified Name (FQN) uniqueness within a compilation unit. Unlike Rust (where Cargo can rename crates under the hood) or Go (where `v2` uses a distinct import path), compiling two versions of `user.v1.User` into the same protoc descriptor set causes immediate FQN collision errors.
+Reproducibility depends on pinned commits remaining available and hashes matching. Breaking checks use each revision's own manifests and locks; the baseline is read from an isolated Git snapshot rather than the current working tree.
-EasyP's per-module MVS provides the exact balance required for Protobuf: deterministic single-version resolution within each module graph, paired with complete version independence between separate service modules.
+See [protobuf.mod](/docs/reference/protobuf-mod), [protobuf.lock](/docs/reference/protobuf-lock), and [generation](/docs/cli/generator) for details.
diff --git a/content/docs/architecture/mvs-dependency-resolution.ru.mdx b/content/docs/architecture/mvs-dependency-resolution.ru.mdx
index 6d39556..9572e4d 100644
--- a/content/docs/architecture/mvs-dependency-resolution.ru.mdx
+++ b/content/docs/architecture/mvs-dependency-resolution.ru.mdx
@@ -1,175 +1,89 @@
---
-title: "Резолюция зависимостей MVS"
-description: "Подробный разбор алгоритма Minimal Version Selection (MVS), разрешения ромбовидных зависимостей (diamond dependency), спецификации protobuf.mod и герметичного lock-файла protobuf.lock в EasyP."
+title: "Разрешение зависимостей MVS"
+description: "Выбор SemVer, совместимые ограничения по коммитам и воспроизводимые Git-зависимости в EasyP."
---
-В качестве основного алгоритма разрешения зависимостей для Protocol Buffer модулей EasyP использует **Minimal Version Selection (MVS)**. Разработанный Рассом Коксом (Russ Cox) для модулей Go, MVS отличается от традиционных пакетных менеджеров (таких как Cargo или npm) тем, что выбирает *минимальную* (самую старую из удовлетворяющих) явно объявленную версию, вместо сложного поиска компромиссов через SAT-солверы или автоматического обновления до `latest`.
+EasyP разрешает зависимости отдельно для каждого protobuf-модуля. Для требований SemVer применяется **Minimal Version Selection (MVS)**: выбирается максимальная из запрошенных минимальных версий. Точные Git-коммиты и требования без версии имеют отдельные правила; SHA не получает искусственный порядок SemVer.
-В данном документе подробно рассматриваются алгоритм MVS, его поведение при разрешении ромбовидных зависимостей (diamond dependencies), DSL файла `protobuf.mod`, устройство `protobuf.lock` и сравнение с альтернативными моделями.
+## Правила выбора
----
-
-## 1. Концепция Minimal Version Selection (MVS)
+| Требования к одному модулю | Результат |
+| --- | --- |
+| Несколько SemVer-минимумов | Максимум запрошенных минимумов |
+| Один явный полный SHA | Точный коммит |
+| Выбранный SemVer и SHA того же коммита | Совместимы; тег сохраняется в lock для SemVer-ограничения |
+| Разные явные SHA или выбранный тег на другом коммите | Ошибка конфликта |
+| Без версии вместе с SemVer или SHA | Требование без версии не добавляет ограничения |
+| Только требования без версии | Tidy использует прежний lock или HEAD без lock; update освежает HEAD |
-Традиционные алгоритмы разрешения зависимостей (например, PubGrub в Cargo или стратегия Max Version в npm) рассматривают выбор версий как задачу удовлетворения ограничений (CSP), решаемую с помощью NP-полных SAT-солверов или агрессивного подтягивания свежих версий. В отличие от них, MVS в EasyP ориентирован на предсказуемость, детерминированность и независимость от состояния удалённых реестров.
+Коммит нельзя считать «новее» минимальной версии по дате или истории Git. Совместимость SemVer/SHA проверяется по точному коммиту выбранного тега. Если более сильное ограничение заменяет предварительный HEAD, его рёбра зависимостей пересобираются; ошибки и зависимости отброшенного HEAD не остаются в выбранном графе. Циклические неустойчивые ограничения без версии отклоняются.
-### Почему EasyP выбирает MVS
+## Ромбовидная зависимость
-| Проблема при работе с Proto | Подход Buf v2 / Традиционный | Подход EasyP MVS |
-| --- | --- | --- |
-| **Рассинхрон версий («diamond»)** | Резолюция на весь workspace целиком: единая версия пакета на всех потребителей, конфликты между командами разруливаются вручную. | Per-module (помодульная) резолюция. Каждый модуль резолвит свои зависимости независимо. |
-| **Зависимость от состояния реестра** | Стратегия `latest` или изменения в реестре могут неявно изменить результат повторной сборки. | Детерминированный выбор `max(запрошенных минимумов)`. Без SAT-солвера и обращения к реестру при наличии lock. |
-| **Коллизии Proto-схем** | Несколько мажорных/минорных версий в одном proto-root ломают уникальность FQN. | Ровно одна версия каждой зависимости в графе модуля, строго зафиксированная в `protobuf.lock`. |
+~~~text
+user
+├── common v1.2.0
+└── weather v2.1.0
+ └── common v1.3.0
+~~~
-### Базовые принципы алгоритма
+Граф user выбирает common v1.3.0 и weather v2.1.0. Численно v1.3.0 удовлетворяет обоим минимумам common; разрешение версий само по себе не доказывает совместимость схем. Для этого отдельно запускают easyp breaking.
-1. **Явные нижние границы версий**: Каждая зависимость в `protobuf.mod` указывает конкретную базовую версию (например, `github.com/acme/weather v1.2.0`). Эта версия рассматривается как *минимально необходимая requirement*, а не диапазоновое ограничение.
-2. **Максимум из минимумов**: Если несколько модулей в графе требуют разные минимальные версии одной и той же зависимости, MVS выбирает **максимальную** из запрошенных минимальных версий.
-3. **Детерминизм High-Water Mark**: Выбранная версия гарантированно удовлетворяет всем объявленным минимальным требованиям без возвратов (backtracking) и неожиданных мажорных обновлений.
+Если user закрепляет SHA, выбранный тег common v1.3.0 должен указывать именно на него. Самого наличия тега v1.2.0 на этом SHA недостаточно, если максимум требований — v1.3.0. Если требование user к common не содержит версии, минимум weather определяет выбор.
----
+## Границы модулей и дескрипторов
-## 2. Пошаговый разбор разрешения ромбовидных зависимостей (Diamond Dependency)
-
-Классическая проблема управления зависимостями — ромбовидная зависимость. Рассмотрим случай, когда корневой модуль `user` напрямую зависит от `common` и `weather`, а `weather` транзитивно требует более новую версию `common`.
-
-### Структура графа
-
-```text
- +-------------------+
- | proto/user | (Корневой модуль)
- +---------+---------+
- |
- +-------------+-------------+
- | |
- v v
-+---------------------+ +---------------------+
-| github.com/acme/ | | github.com/acme/ |
-| common v1.2.0 | | weather v2.1.0 |
-+---------------------+ +----------+----------+
- |
- v
- +---------------------+
- | github.com/acme/ |
- | common v1.3.0 |
- +---------------------+
-```
-
-### Пошаговый алгоритм MVS
-
-protobuf.mod и protobuf.lock. Например, proto/user может выбрать common v1.3.0, а proto/order — common v2.0.0 в независимых графах.
----
+При генерации независимость графов не гарантирует совместимость объединённого результата:
-## 3. Директивы DSL `protobuf.mod`
+| Вывод | Проверка |
+| --- | --- |
+| --descriptor_set_out | Объединяет совместимые графы; конфликт определения по import path или символов — ошибка |
+| --descriptor_set_out_dir | Отдельный набор для каждой пары проект/модуль; графы не объединяются |
+| Результаты плагинов | Одинаковые общие файлы объединяются; разное содержимое по одному пути или разные Go-пакеты в одном каталоге — ошибка |
-Файл `protobuf.mod` располагается в корне proto-модуля и является tool-neutral спецификацией, сфокусированной только на объявлении зависимостей.
+Managed-опции сохраняются при проверке совместимости. Разные версии зависимостей могут иметь совместимые дескрипторы, а разные настройки потребителей — сделать их несовместимыми. --include_imports меняет только содержимое экспорта; полный граф проверяется в любом случае. Генерация импортов плагином отдельно управляется with_imports, по умолчанию false.
-```protobuf
-// proto/user/protobuf.mod
+## Манифест и локальные замены
+~~~text
module github.com/acme/user
-
-roots (
- proto
-)
-
+roots proto
require (
- github.com/googleapis/googleapis v1.5.0
- github.com/acme/weather v1.2.3
- github.com/grpc-ecosystem/grpc-gateway v2.19.0 // indirect
+ github.com/acme/common v1.2.0
+ github.com/acme/weather v2.1.0
)
-
-// Локальная отладка зависимости
replace github.com/acme/weather => ../weather-fork
-```
+~~~
-### Справочник директив
+roots считается от каталога манифеста и по умолчанию равен .. Команды get и mod находят ближайший манифест в предках в пределах workspace. Транзитивные требования записываются с // indirect.
-- **`module`**: Объявляет канонический идентификатор (URL/путь) модуля.
-- **`roots`**: Задаёт корневую поддиректорию с `.proto` файлами внутри репозитория (по умолчанию `.`). Это позволяет корректно резолвить импорты без срезания путей вручную.
-- **`require`**: Прямые и транзитивные зависимости с явными фиксациями SemVer версий.
- - **`// indirect`**: Автоматически дописывается командой `easyp mod tidy` для транзитивных зависимостей, не импортируемых напрямую `.proto` файлами модуля.
-- **`replace`**: Переопределяет источник зависимости локальным путем (`../weather-fork`) или другим URL/версией. Используется для локальной отладки.
+Относительная цель replace считается от содержащего её protobuf.mod, абсолютная используется напрямую. Генерация и линтинг поддерживают локальные замены. get, mod tidy, mod update и mod vendor отклоняют их: уберите замены перед созданием или использованием воспроизводимого Git lock этими командами. Это проверка команд, а не запрет коммитов со стороны CI.
-v1.2.3 модуля в proto/user использует тег proto/user/v1.2.3.
----
+## Lock и неизменность опубликованных версий
-## 4. Механизм герметичной фиксации `protobuf.lock`
+protobuf.lock записывает источник, выбранный тег или SHA, точный коммит и хеш содержимого. Его создают get, mod tidy и mod update. mod download использует точные коммиты из lock. Пример ниже показывает формат, а не реальные данные репозитория.
-Файл `protobuf.lock` генерируется и обновляется командами `easyp mod tidy` и `easyp mod update`.
-
-```yaml
-# protobuf.lock - СГЕНЕРИРОВАННЫЙ ФАЙЛ, НЕ РЕДАКТИРОВАТЬ РУКАМИ
+~~~yaml
version: 1
modules:
- - source: github.com/googleapis/googleapis
- version: v1.5.0
- commit: 8f3a1c94b2e10a84e
- hash: h1:a9F8zK...
- - source: github.com/acme/weather
- version: v1.2.3
- commit: 51d2e071c89f33b11
- hash: h1:x7B3mL...
- - source: github.com/grpc-ecosystem/grpc-gateway
- version: v2.19.0
- commit: c4f88aa91024e12c4
- hash: h1:p0Q1wK...
-```
-
-### Гарантии герметичности сборки
-
-1. **Строгая фиксация**: Сборка в CI выполняется через `easyp mod download` строго по `protobuf.lock`. Состояние кэшей и удалённых реестров не влияет на результат.
-2. **Контроль целостности**: Поле `hash` проверяет совпадение содержимого, защищая от подмены Git-тегов или кэша.
-3. **Предсказуемый жизненный цикл**: `protobuf.lock` изменяется только при явном вызове `easyp mod tidy` или `easyp mod update`.
+ - source: github.com/acme/common
+ version: v1.3.0
+ commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+~~~
----
+При tidy, get и update повторно полученный ранее зафиксированный SemVer должен совпасть с записанными коммитом и хешем. Несовпадение вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock, в том числе для транзитивных требований и прогретого кеша. Новая версия может быть выбрана; неограниченные требования без версии по-прежнему обновляются до HEAD, явные SHA сохраняются.
-## 5. Сравнительный анализ архитектур
+mod download может получить старый коммит после переноса тега, если коммит остаётся доступным. Хеш Go dirhash.Hash1 охватывает обычные файлы, отслеживаемые Git, с путями относительно репозитория. Проверка выполняется и для новых загрузок, и для установленных файлов кеша.
-| Модель | EasyP MVS | Go Modules (MVS) | Cargo / Rust (PubGrub SAT) | Buf v2 (Workspace SVS) |
-| --- | --- | --- | --- | --- |
-| **Алгоритм** | Minimal Version Selection | Minimal Version Selection | SAT Solver (PubGrub) | Workspace Single Version |
-| **Правило выбора** | `max(минимумов)` | `max(минимумов)` | Сложные SemVer диапазоны (`^1.2.3`) | Единая версия на весь workspace |
-| **Скоуп резолюции** | Per-module | Per-module | Per-crate | Весь Workspace |
-| **Несколько версий в сборке** | Запрещено (коллизия FQN) | Разрешено для разных major версий | Разрешено для разных major версий | Запрещено |
-| **Lock-файл** | `protobuf.lock` | `go.sum` | `Cargo.lock` | `buf.lock` |
-| **Локальный оверрайд** | Директива `replace` | Директива `replace` | `[patch]` / `path` | Локальный workspace модуль |
+## Повторное использование Git-объектов
-### Почему MVS идеально подходит для Protobuf
+Для каждого remote используется общее хранилище объектов. Известный точный коммит повторно используется без обращения к remote. Первая попытка — загрузка нужного коммита с глубиной один. Если сервер запрещает исторический SHA, EasyP получает доступную историю объявленных ссылок и всё равно требует исходный коммит; HEAD вместо него не подставляется. Поэтому холодная загрузка не всегда остаётся shallow. Проверки тегов обновляются отдельно, чтобы кеш не скрывал перепубликацию.
-Схемы Protobuf требуют строгой уникальности имён пакетов и полных имён сообщений (Fully Qualified Name, FQN) в рамках единицы компиляции. В отличие от Rust (где Cargo может переименовать crate) или Go (где `v2` имеет другой путь импорта), компиляция двух разных версий одного proto-файла в единый descriptor set приводит к немедленным ошибкам коллизии FQN.
+Воспроизводимость зависит от доступности зафиксированных коммитов и совпадения хешей. При breaking-проверке каждая ревизия использует собственные манифесты и lock; база берётся из изолированного Git-снимка, а не из текущего рабочего дерева.
-MVS в EasyP предоставляет идеальный баланс для Protobuf: детерминированный выбор единой версии внутри графа каждого модуля и полную независимость версий между отдельными сервисами.
+Подробности: [protobuf.mod](/ru/docs/reference/protobuf-mod), [protobuf.lock](/ru/docs/reference/protobuf-lock) и [генерация](/ru/docs/cli/generator).
diff --git a/content/docs/ci-cd/github-actions.mdx b/content/docs/ci-cd/github-actions.mdx
index 52bbe57..2b348b8 100644
--- a/content/docs/ci-cd/github-actions.mdx
+++ b/content/docs/ci-cd/github-actions.mdx
@@ -1,5 +1,117 @@
---
-title: "Github Actions"
+title: "GitHub Actions"
+description: "Verify v1 dependency locks, lint schemas, compare a Git baseline, and check generated output in CI."
---
-## Work in progress
+Run dependency verification, linting, breaking checks, and generation as separate steps so failures identify the stage that needs attention.
+
+## Prerequisites and Toolchain
+
+This example assumes a root protobuf.mod and committed protobuf.lock, a root easyp.yaml, schemas in proto, and a root easyp.gen.yaml writing to tracked files under gen.
+
+The workflow uses a prepared self-hosted Linux runner with the custom label easyp-v1. Assign that label only after provisioning your chosen v1-capable EasyP binary and required local plugins on PATH. For a hosted runner, supply your project's pinned toolchain setup before the EasyP steps. The example does not assume a particular published v1 release artifact.
+
+Local and bundled plugins cannot use a YAML version pin; their versions are controlled by the installed executables and EasyP binary. Remote plugins require a separate pinned semantic version in easyp.gen.yaml.
+
+## Pull Request Workflow
+
+~~~yaml
+name: protobuf-ci
+
+on:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ verify:
+ runs-on: [self-hosted, linux, x64, easyp-v1]
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Verify toolchain
+ run: easyp --version
+
+ - name: Verify locked dependencies
+ run: easyp mod download
+
+ - name: Lint schemas
+ run: easyp lint --path proto
+
+ - name: Check compatibility
+ env:
+ BASE_REF: ${{ github.event.pull_request.base.sha }}
+ run: easyp breaking --path proto --against "$BASE_REF"
+
+ - name: Generate code
+ run: easyp generate --project .
+
+ - name: Check committed generated files
+ run: |
+ git diff --exit-code -- gen
+ test -z "$(git ls-files --others --exclude-standard -- gen)"
+~~~
+
+The final step detects tracked changes and new untracked files under gen. Adapt the paths for your project; ignored generated files are outside this check. Also run your normal consumer tests after generation.
+
+## Lint and Breaking Policies
+
+A simple root easyp.yaml is:
+
+~~~yaml
+version: v1
+linters:
+ default: STANDARD
+breaking:
+ baseline: git:main
+ categories: [FILE]
+ ignore_unstable: false
+ ignore: [proto/experimental]
+~~~
+
+The workflow's explicit --against overrides this baseline with the PR base SHA. Use a ref directly, without git-ref= or git: in the flag. Branches, lightweight and annotated tags, full SHAs, and locally resolvable Git revisions are supported; the required refs and objects must exist locally. A bare branch name wins over an identically named tag.
+
+For a release comparison, select an existing release tag explicitly:
+
+~~~bash
+easyp breaking --path proto --against refs/tags/v1.2.0
+~~~
+
+Choose the intended previous release rather than assuming tag creation order defines compatibility history. Each revision uses its own module manifests, locks, and dependencies, so a breaking check can fetch dependencies beyond those needed by the current checkout.
+
+FILE is the only supported additional category. ignore_unstable works for the supported package suffixes. Ignore paths are relative to the policy file defining the breaking section: here proto/experimental is relative to the root policy. Nested sections replace whole sections; extends explicitly loads a section base from a local file or an existing locked module.
+
+## Selecting Generation Projects
+
+With backend and frontend generator files, use:
+
+~~~bash
+easyp generate --project ./backend --project ./frontend
+~~~
+
+Use easyp generate --all for explicit recursive selection. A plain easyp generate selects the nearest enclosing generator file. --project and --all cannot be combined.
+
+To split generation into matrix jobs, set the matrix to project directories and pass the selected directory to --project. Each job needs the relevant plugins and output checks; language names alone do not select a generation configuration.
+
+## Dependency Cache and Private Sources
+
+Dependencies belong in protobuf.mod, with resolved commits and hashes in protobuf.lock. easyp mod download verifies that lock without updating it. Do dependency updates in a reviewed change before the verification job.
+
+EasyP storage defaults to ~/.easyp and can be relocated with EASYPPATH. If you cache it, include the OS, EasyP toolchain version, and relevant lockfile hashes in the cache key. A restored cache is an optimization; dependency verification still runs.
+
+For private dependencies, provision the Git authentication required by your sources before the dependency step. Keep credentials in the runner's approved secret mechanism and out of logs. A local replacement does not eliminate downloads unless the entire dependency graph is local or already verified in cache; remote plugins still need the network. tidy and update reject active local replacements and are not read-only verification commands.
+
+## Troubleshooting
+
+| Symptom | Check |
+| --- | --- |
+| Baseline cannot be resolved | Fetch the intended ref and its objects; use full history or an explicit fetch. |
+| Unknown policy field or rule | Match configuration to the installed v1 binary and supported schema. |
+| Plugin is missing or output differs | Verify the executable selected from PATH and the pinned toolchain. |
+| Dependency verification fails | Check the committed manifest, lock, source access, and reported hash mismatch. |
+| Generated-output check fails | Regenerate with the same project selection and toolchain, review the diff, and commit intended changes. |
+
+For diagnostics, record easyp --version, the failing command, and the relevant Git ref. See [breaking checks in CI](/docs/guides/breaking-checks-ci) and [build reproducibility](/docs/guides/reproducibility).
diff --git a/content/docs/ci-cd/github-actions.ru.mdx b/content/docs/ci-cd/github-actions.ru.mdx
index 8b06ce9..9e78664 100644
--- a/content/docs/ci-cd/github-actions.ru.mdx
+++ b/content/docs/ci-cd/github-actions.ru.mdx
@@ -1,413 +1,117 @@
---
title: "GitHub Actions"
+description: "Проверка lock-файлов v1, линтинг схем, сравнение с Git-базой и контроль сгенерированного кода в CI."
---
-Полное руководство по интеграции EasyP в конвейеры GitHub Actions для линтинга, проверки несовместимых изменений, генерации кода и автоматизации релизов.
+Запускайте проверку зависимостей, линтинг, breaking-проверки и генерацию отдельными шагами: так ошибка укажет на этап, требующий внимания.
-## Зачем использовать EasyP в CI
+## Предварительные требования и инструменты
-Встраивание EasyP в GitHub Actions даёт:
+Пример предполагает корневые protobuf.mod и закоммиченный protobuf.lock, корневой easyp.yaml, схемы в proto и корневой easyp.gen.yaml, записывающий отслеживаемые файлы в gen.
-- Единообразие правил линтинга и генерации между разработчиками.
-- Автоматическое выявление несовместимых изменений (breaking changes) до мержа.
-- Гарантию, что сгенерированный код не «устарел» относительно .proto.
-- Возможность централизованной проверки зависимостей и версии конфигурации.
+Workflow использует подготовленный self-hosted Linux runner с пользовательской меткой easyp-v1. Назначайте её после подготовки выбранного бинарника EasyP с поддержкой v1 и необходимых локальных плагинов в PATH. Для hosted runner добавьте принятую в проекте установку фиксированных версий инструментов до шагов EasyP. Пример не предполагает существования конкретного опубликованного артефакта релиза v1.
-## Предварительные требования
+Локальные и встроенные плагины не принимают фиксацию через YAML-поле version: их версии определяются установленными исполняемыми файлами и бинарником EasyP. Удалённым плагинам нужна отдельная фиксированная семантическая version в easyp.gen.yaml.
-1. Репозиторий содержит файл конфигурации `easyp.yaml` (или находится в корне, если запускается без `--cfg`).
-2. Установлены / определены зависимости в секции `deps` (если нужны внешние импорты).
-3. Для приватных Git-репозиториев настроен доступ (SSH key / deploy key / токен).
-4. В workflow есть шаги по установке Go (если EasyP поставляется через `go install`) или заранее подготовленный бинарь.
+## Workflow для Pull Request
-## Базовый пример (быстрый старт)
-
-Минимальный workflow для проверки линта и несовместимых изменений при открытия Pull Request:
-
-```yaml
-name: easyp-ci
+~~~yaml
+name: protobuf-ci
on:
pull_request:
- paths:
- - '**/*.proto'
- - 'easyp.yaml'
-
-jobs:
- lint-and-breaking:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Go
- uses: actions/setup-go@v5
- with:
- go-version: '1.22'
-
- - name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
-
- - name: Verify EasyP version
- run: |
- which easyp
- easyp --version
-
- - name: Lint
- run: easyp lint
-
- - name: Breaking changes check (against main)
- run: easyp breaking --against git-ref=origin/main
-```
-
-## Установка EasyP
-
-Варианты:
-
-1. Через `go install` (как в примере выше).
-2. Использование заранее собранного бинаря (артефакт релиза).
-
-```yaml
-- name: Download EasyP binary
- run: |
- curl -sL https://github.com/easyp-tech/easyp/releases/download/v1.0.0/easyp_linux_amd64 -o /usr/local/bin/easyp
- chmod +x /usr/local/bin/easyp
-```
-
-## Кэширование
-
-Для ускорения повторных сборок можно кэшировать:
-
-- Go модульный кеш (если используете генерацию с плагинами Go).
-- Внешние зависимые Git-клонирования (папки `vendor` или содержимое `deps` при использовании `easyp mod download` / `easyp mod update`).
-- Сгенерированный код (если он тяжёлый, но чаще генерируется заново).
-
-Пример кэширования Go:
-
-```yaml
-- name: Cache Go build
- uses: actions/cache@v4
- with:
- path: |
- ~/go/pkg/mod
- ~/.cache/go-build
- key: go-${{ runner.os }}-${{ hashFiles('**/go.sum') }}
- restore-keys: |
- go-${{ runner.os }}-
-```
-
-Пример кэширования каталога зависимостей EasyP (если вы используете локальный vendor-подход):
-
-```yaml
-- name: Cache proto deps
- uses: actions/cache@v4
- with:
- path: .easyp/deps
- key: deps-${{ runner.os }}-${{ hashFiles('easyp.yaml') }}
- restore-keys: |
- deps-${{ runner.os }}-
-```
-
-(Создайте `.easyp/deps` как целевой каталог, если ваша стратегия скачивания такова.)
-
-## Линтинг
-
-Команда:
-
-```bash
-easyp lint
-```
-
-Рекомендуется:
-
-- В PR: всегда запускать.
-- На main: можно запускать для верификации перед релизом.
-
-Расширенный пример с выводом подробностей и игнорированием комментариев (если включено в конфиг):
-
-```yaml
-- name: Lint proto files
- run: |
- set -e
- easyp lint -v
-```
-
-## Проверка несовместимых изменений (Breaking Changes)
-
-EasyP может сравнивать текущее состояние против ветки / коммита / тега.
-
-Примеры:
-
-```bash
-# Сравнить против origin/main
-easyp breaking --against git-ref=origin/main
-
-# Сравнить против тега релиза
-easyp breaking --against git-ref=v1.5.2
-
-# Игнорировать определённые правила (если у вас настроено в easyp.yaml)
-easyp breaking
-```
-
-Workflow шаг:
-
-```yaml
-- name: Breaking changes check
- run: easyp breaking --against git-ref=origin/main
-```
-
-Если нужно «мягко» пропустить (например, выводить предупреждения, но не падать билд):
-
-```yaml
-- name: Breaking changes (soft)
- run: |
- if ! easyp breaking --against git-ref=origin/main; then
- echo "::warning title=Breaking Changes Detected::Обнаружены потенциально несовместимые изменения"
- fi
-```
-
-## Генерация кода
-
-Обычно для генерации:
-```bash
-easyp generate
-```
+permissions:
+ contents: read
-Если нужно явно указать конфиг:
-
-```bash
-easyp --cfg easyp.yaml generate
-```
-
-Пример шага:
-
-```yaml
-- name: Generate code
- run: |
- easyp generate
- git status --short
-```
-
-Можно добавить проверку «не осталось ли не закоммиченных изменений» (гарантия, что сгенерированный код актуален):
-
-```yaml
-- name: Ensure generated code is up-to-date
- run: |
- easyp generate
- if [ -n "$(git status --porcelain)" ]; then
- echo "Generated code is outdated. Please commit changes."
- git diff --name-only
- exit 1
- fi
-```
-
-## Матрица (Matrix strategy)
-
-Если у вас несколько вариантов конфигураций или разных языков генерации (через плагины), можно использовать matrix:
-
-```yaml
jobs:
- generate:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- lang: [go, python]
+ verify:
+ runs-on: [self-hosted, linux, x64, easyp-v1]
steps:
- uses: actions/checkout@v4
-
- - name: Setup Go (only for go)
- if: matrix.lang == 'go'
- uses: actions/setup-go@v5
with:
- go-version: '1.22'
-
- - name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
-
- - name: Generate
- run: |
- if [ "${{ matrix.lang }}" = "go" ]; then
- easyp generate
- elif [ "${{ matrix.lang }}" = "python" ]; then
- easyp generate --plugin python
- fi
-```
-
-## Работа с приватными репозиториями (deps)
-
-Если вы указываете приватные Git-пакеты в секции `deps`:
-
-1. Настройте deploy key или используйте `GIT_SSH_COMMAND` с токеном.
-2. Добавьте known_hosts (либо установите `StrictHostKeyChecking=no` для внутренних систем, но осознанно).
-
-Пример:
-
-```yaml
-- name: Prepare SSH
- run: |
- mkdir -p ~/.ssh
- echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan github.com >> ~/.ssh/known_hosts
+ fetch-depth: 0
-- name: Update deps
- run: easyp mod update
-```
+ - name: Verify toolchain
+ run: easyp --version
-## Оптимизация времени сборки
+ - name: Verify locked dependencies
+ run: easyp mod download
-- Используйте кэш для Go / deps.
-- Запускайте линт/брейкинг только если изменились `.proto` или `easyp.yaml` (paths фильтр).
-- Разделяйте workflow: быстрый линт в PR, тяжелая генерация в push на main.
-- Выносите генерацию OpenAPI / gRPC-Gateway в отдельный job (параллелизм).
+ - name: Lint schemas
+ run: easyp lint --path proto
-## Продвинутый workflow (многостадийный)
+ - name: Check compatibility
+ env:
+ BASE_REF: ${{ github.event.pull_request.base.sha }}
+ run: easyp breaking --path proto --against "$BASE_REF"
-```yaml
-name: easyp-pipeline
+ - name: Generate code
+ run: easyp generate --project .
-on:
- pull_request:
- paths:
- - '**/*.proto'
- - 'easyp.yaml'
- push:
- branches:
- - main
-
-jobs:
- validate:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-go@v5
- with:
- go-version: '1.22'
-
- - name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
-
- - name: Lint
- run: easyp lint
-
- - name: Breaking check (against main)
- if: github.event_name == 'pull_request'
- run: easyp breaking --against git-ref=origin/main
-
- generate:
- needs: validate
- if: github.event_name == 'push'
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-go@v5
- with:
- go-version: '1.22'
- - name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
- - name: Generate Code
- run: easyp generate
- - name: Check diffs
+ - name: Check committed generated files
run: |
- if [ -n "$(git status --porcelain)" ]; then
- echo "Generated files changed after generate step."
- git diff --name-only
- exit 1
- fi
-```
+ git diff --exit-code -- gen
+ test -z "$(git ls-files --others --exclude-standard -- gen)"
+~~~
-## Автоматизация релиза (пример)
+Последний шаг обнаруживает изменения отслеживаемых файлов и новые неотслеживаемые файлы в gen. Адаптируйте пути под проект; игнорируемые сгенерированные файлы эта проверка не охватывает. После генерации также запускайте обычные тесты потребителей.
-Можно добавить workflow, который по тегу создаёт релиз и валидирует proto:
+## Политики линтинга и совместимости
-```yaml
-name: release-verify
+Простой корневой easyp.yaml:
-on:
- push:
- tags:
- - 'v*.*.*'
+~~~yaml
+version: v1
+linters:
+ default: STANDARD
+breaking:
+ baseline: git:main
+ categories: [FILE]
+ ignore_unstable: false
+ ignore: [proto/experimental]
+~~~
-jobs:
- release-check:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-go@v5
- with:
- go-version: '1.22'
+Явный --against из workflow заменяет эту базу SHA базового коммита PR. Передавайте ссылку напрямую, без git-ref= и git: во флаге. Поддерживаются ветки, лёгкие и аннотированные теги, полные SHA и разрешимые локально Git-ревизии; необходимые ссылки и объекты должны присутствовать локально. Короткое имя ветки приоритетнее одноимённого тега.
- - name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
+Для сравнения релиза явно выберите существующий тег:
- - name: Lint
- run: easyp lint
+~~~bash
+easyp breaking --path proto --against refs/tags/v1.2.0
+~~~
- - name: Breaking vs previous tag
- run: |
- PREV_TAG=$(git tag --sort=-creatordate | grep -v "${GITHUB_REF_NAME}" | head -n1 || true)
- if [ -n "$PREV_TAG" ]; then
- echo "Comparing against $PREV_TAG"
- easyp breaking --against git-ref=$PREV_TAG
- else
- echo "No previous tag, skipping breaking check"
- fi
-
- - name: Generate to ensure consistency
- run: easyp generate
-```
-
-## Отладка
+Выбирайте нужный предыдущий релиз явно: порядок создания тегов не обязательно задаёт историю совместимости. Каждая ревизия использует свои манифесты модулей, lock-файлы и зависимости, поэтому breaking-проверка может загрузить зависимости, которые не нужны текущему checkout.
-Если нужно больше логов:
+FILE — единственная поддерживаемая дополнительная категория. ignore_unstable работает для поддерживаемых суффиксов пакетов. Пути исключений отсчитываются от файла политики с секцией breaking: здесь proto/experimental задан относительно корневой политики. Вложенные секции заменяют секции целиком; extends явно подключает базу секции из локального файла или существующего закреплённого модуля.
-```bash
-easyp lint -v
-easyp breaking -v --against git-ref=origin/main
-easyp generate -v
-```
+## Выбор проектов генерации
-Добавьте вывод окружения для диагностики:
+Для файлов генератора бэкенда и фронтенда используйте:
-```yaml
-- name: Debug environment
- run: |
- env | sort
- easyp --version
-```
+~~~bash
+easyp generate --project ./backend --project ./frontend
+~~~
-## Переменные окружения (примерно)
+Для явного рекурсивного выбора используйте easyp generate --all. Обычный easyp generate выбирает ближайший вышестоящий файл генератора. Сочетать --project и --all нельзя.
-| Переменная | Назначение |
-|------------|-----------|
-| `EASYP_CFG` | Путь к файлу конфигурации, если он не в корне репозитория |
-| `GIT_SSH_COMMAND` | Кастомная команда SSH (частные репозитории) |
-| `GOFLAGS` | Можно выставить `-mod=readonly` для Go генерации |
+Чтобы разделить генерацию на matrix jobs, задайте в матрице каталоги проектов и передавайте выбранный каталог в --project. Каждой job нужны соответствующие плагины и проверки вывода; одни имена языков не выбирают конфигурацию генерации.
-(Используйте только те, что действительно нужны вашему проекту.)
+## Кеш зависимостей и приватные источники
-## Частые ошибки
+Зависимости задаются в protobuf.mod, выбранные коммиты и хеши — в protobuf.lock. easyp mod download проверяет lock, не обновляя его. Обновляйте зависимости в отдельном проверяемом изменении до проверочной job.
-| Симптом | Причина | Решение |
-|---------|---------|---------|
-| Линт падает на неизвестных правилах | Правила указаны в `easyp.yaml`, но версия EasyP их не поддерживает | Обновить EasyP (`go install ...@latest`) |
-| `breaking` сравнение ничего не находит | Неверный `--against` (нет fetch удалённой ветки) | Добавить шаг `git fetch --all --tags` |
-| Сгенерированный код в PR отличается от main | Отсутствует проверка генерации в CI | Добавить шаг «Ensure generated code is up-to-date» |
-| Приватные deps не скачиваются | Нет SSH ключа или токена | Настроить secrets + шаг подготовки SSH |
-| Долгое выполнение | Отсутствует кеш | Добавить кэширование модулей и deps |
+По умолчанию хранилище EasyP находится в ~/.easyp; его можно перенести через EASYPPATH. Если кешируете его, включайте в ключ кеша ОС, версию инструментов EasyP и хеши нужных lock-файлов. Восстановленный кеш — оптимизация, проверка зависимостей всё равно выполняется.
-## Рекомендации по поддержке
+До шага зависимостей настройте Git-аутентификацию, необходимую приватным источникам. Храните учётные данные в принятом для runner механизме секретов и не выводите их в логи. Локальная замена не устраняет загрузки, если весь граф зависимостей не локальный и не находится в проверенном кеше; удалённым плагинам всё ещё нужна сеть. tidy и update отклоняют активные локальные замены и не являются проверками только для чтения.
-- Заготовить шаблон workflow и копировать между сервисами (DRY).
-- Включить `paths` фильтры, чтобы не тратить минуты на нерелевантные изменения.
-- Проверять `easyp.yaml` при изменениях отдельно — можно запускать «конфигурационный тест» (например, `easyp lint` без файлов, чтобы убедиться, что конфиг валиден).
-- При появлении новых правил линтера обновляйте конфиг и фиксируйте ошибки сразу в одной ветке.
+## Отладка
----
+| Симптом | Что проверить |
+| --- | --- |
+| База не разрешается | Получите нужную ссылку и объекты через полную историю или явный fetch. |
+| Неизвестное поле политики или правило | Согласуйте конфигурацию с установленным бинарником v1 и поддерживаемой схемой. |
+| Плагин отсутствует или вывод отличается | Проверьте исполняемый файл, выбранный из PATH, и фиксированные версии инструментов. |
+| Проверка зависимостей падает | Проверьте закоммиченные манифест и lock, доступ к источникам и сообщение о несовпадении хеша. |
+| Проверка сгенерированных файлов падает | Повторите генерацию с теми же проектами и инструментами, проверьте diff и закоммитьте нужные изменения. |
-Готово: вы можете расширять разделы генерации, добавлять OpenAPI / grpc-gateway / validate плагины, матрицы по языкам и интегрировать тесты поверх сгенерированного кода, если требуется.
+Для диагностики сохраняйте easyp --version, упавшую команду и нужную Git-ссылку. См. [breaking-проверки в CI](/ru/docs/guides/breaking-checks-ci) и [воспроизводимость сборок](/ru/docs/guides/reproducibility).
diff --git a/content/docs/ci-cd/gitlab.mdx b/content/docs/ci-cd/gitlab.mdx
index c6d7849..077b2f8 100644
--- a/content/docs/ci-cd/gitlab.mdx
+++ b/content/docs/ci-cd/gitlab.mdx
@@ -1,5 +1,28 @@
---
-title: "Gitlab"
+title: "GitLab CI"
---
-## Work in progress
+Set EASYP_CI_IMAGE to a pinned image containing a reviewed EasyP v1 build, Git and the required plugins. Commit configs and the lock. This example has one module and a root generation config; in a monorepo run module commands per module and explicitly select generation projects.
+
+~~~yaml
+image: $EASYP_CI_IMAGE
+
+variables:
+ GIT_DEPTH: "0"
+
+stages: [validate]
+
+contracts:
+ stage: validate
+ script:
+ - easyp validate-config
+ - easyp mod download
+ - easyp lint
+ - git fetch origin +refs/heads/main:refs/remotes/origin/main
+ - easyp breaking --against refs/remotes/origin/main
+ - easyp generate
+ - git diff --exit-code
+ - test -z "$(git status --porcelain --untracked-files=normal -- gen)"
+~~~
+
+Adjust main and gen to the project baseline and output directory. The last assertion catches newly generated untracked files. Do not mask breaking failures with || echo. Configure private Git access through the runner; do not put credentials into EasyP YAML.
diff --git a/content/docs/ci-cd/gitlab.ru.mdx b/content/docs/ci-cd/gitlab.ru.mdx
index b4295b8..3880e7e 100644
--- a/content/docs/ci-cd/gitlab.ru.mdx
+++ b/content/docs/ci-cd/gitlab.ru.mdx
@@ -2,60 +2,27 @@
title: "GitLab CI"
---
-## В процессе разработки
+Для примера ниже задайте EASYP_CI_IMAGE: закреплённый образ с проверенной сборкой EasyP v1, Git и нужными плагинами. Конфиги и lock должны быть закоммичены. Здесь показан один модуль с generation-конфигом в корне; в монорепозитории команды модулей запускаются для каждого модуля, а генерация выбирается явно.
-Документация по интеграции EasyP с GitLab CI находится в процессе подготовки.
-Планируемые разделы:
-
-- Быстрый старт (пример `.gitlab-ci.yml` для линтинга и проверки несовместимых изменений)
-- Кэширование зависимостей и ускорение сборок
-- Генерация кода и проверка актуальности артефактов
-- Работа с приватными Git-репозиториями в `deps`
-- Матрицы (parallel jobs) для разных языков и плагинов
-- Автоматизация релизов по тегам
-
-Если вам нужен пример прямо сейчас, базовый минимальный вариант может выглядеть так:
-
-```yaml
-stages:
- - validate
- - generate
+~~~yaml
+image: $EASYP_CI_IMAGE
variables:
- GO_VERSION: "1.22"
+ GIT_DEPTH: "0"
+
+stages: [validate]
-validate:
+contracts:
stage: validate
- image: golang:${GO_VERSION}
- before_script:
- - go install github.com/easyp-tech/easyp/cmd/easyp@latest
- - echo "EasyP version:"
- - easyp --version
- # При необходимости: git fetch --all --tags
script:
+ - easyp validate-config
+ - easyp mod download
- easyp lint
- - easyp breaking --against git-ref=origin/main
- only:
- changes:
- - "**/*.proto"
- - "easyp.yaml"
-
-generate:
- stage: generate
- image: golang:${GO_VERSION}
- before_script:
- - go install github.com/easyp-tech/easyp/cmd/easyp@latest
- script:
+ - git fetch origin +refs/heads/main:refs/remotes/origin/main
+ - easyp breaking --against refs/remotes/origin/main
- easyp generate
- - |
- if [ -n "$(git status --porcelain)" ]; then
- echo "Сгенерированный код не актуален. Закоммитьте изменения локально."
- git diff --name-only
- exit 1
- fi
- only:
- - main
-
-```
+ - git diff --exit-code
+ - test -z "$(git status --porcelain --untracked-files=normal -- gen)"
+~~~
-Дополнительные рекомендации будут добавлены позже.
+Замените main и gen на baseline и каталог результатов проекта. Последняя проверка учитывает новые неотслеживаемые generated-файлы. Не маскируйте ошибку breaking через || echo. Доступ к приватным Git-источникам настраивается средствами runner; секреты не записываются в YAML-конфиги EasyP.
diff --git a/content/docs/cli/breaking-changes/index.mdx b/content/docs/cli/breaking-changes/index.mdx
index 00d09a3..07aabdf 100644
--- a/content/docs/cli/breaking-changes/index.mdx
+++ b/content/docs/cli/breaking-changes/index.mdx
@@ -1,453 +1,71 @@
---
title: "Breaking Changes Detection"
+description: "Compare protobuf schemas with a Git baseline and revision-local dependencies in EasyP v1."
---
-[[toc]]
+easyp breaking compares selected current .proto files with a Git baseline and reports incompatible changes.
-EasyP's breaking changes detection helps you maintain backward compatibility in your protobuf APIs by automatically identifying changes that could break existing clients. This is crucial for maintaining stable APIs in production environments.
-
-## Overview
-
-The breaking changes checker compares your current protobuf files against a previous version (typically from another Git branch) and identifies modifications that could cause compatibility issues for existing clients.
-
-### Key Features
-
-- **Git-based Comparison**: Compare against any Git reference (branch, tag, or commit)
-- **Comprehensive Analysis**: Checks services, messages, enums, fields, and imports
-- **Selective Ignore**: Skip specific directories from breaking change analysis
-- **Detailed Reports**: Clear error messages with file locations and line numbers
-
-## How It Works
-
-The breaking changes detector follows this process:
-
-1. **Checkout Comparison Branch**: Retrieves proto files from the specified Git reference
-2. **Parse Both Versions**: Analyzes current and previous proto file structures
-3. **Compare Entities**: Systematically checks all protobuf elements for breaking changes
-4. **Generate Report**: Produces detailed issue reports with locations and descriptions
-
-## Detection Level
-
-EasyP implements **WIRE+ level** breaking change detection:
-- ✅ **Full wire format compatibility** - ensures old and new versions can exchange data
-- ✅ **Element deletion detection** - catches deleted services, messages, fields, etc.
-- ✅ **Type safety** - detects incompatible type changes
-- ❌ **Field/method renames** - currently not detected (planned for future releases)
-- ❌ **File-level changes** - package moves, file options not checked yet
-
-This provides strong compatibility guarantees while being less strict than some tools that check generated code compatibility.
-
-## Configuration
-
-Configure breaking changes detection in your `easyp.yaml`:
-
-```yaml
-breaking:
- # Git reference to compare against (branch, tag, or commit hash)
- against_git_ref: "main"
-
- # Directories to ignore during breaking changes analysis
- ignore:
- - "experimental"
- - "internal/proto"
- - "vendor"
-```
-
-### Configuration Options
-
-| Option | Description | Default | Required |
-|--------|-------------|---------|----------|
-| `against_git_ref` | Git reference to compare against | `"master"` | No |
-| `ignore` | List of directories to exclude from analysis | `[]` | No |
-
-## Usage
-
-### Basic Usage
-
-Compare current changes against the main branch:
-
-```bash
-easyp breaking --against main
-```
-
-### Using Configuration File
-
-With a custom configuration file:
-
-```bash
-easyp --cfg my-config.yaml breaking
-```
-
-### Override Git Reference
-
-Override the configured branch:
-
-```bash
-easyp breaking --against feature/new-api
-```
-
-## Detection Level
-
-EasyP currently implements **WIRE+ level** breaking change detection, which provides comprehensive wire format compatibility plus some generated code protections:
-
-### Comparison with Buf Categories
-
-| Check Type | Buf WIRE | Buf WIRE_JSON | Buf FILE | EasyP Current |
-|------------|----------|---------------|----------|---------------|
-| **Element Deletions** |
-| Service deletion | ❌ | ❌ | ✅ | ✅ |
-| RPC method deletion | ❌ | ❌ | ✅ | ✅ |
-| Message deletion | ❌ | ❌ | ✅ | ✅ |
-| Field deletion (by number) | ✅ | ✅ | ✅ | ✅ |
-| Enum deletion | ❌ | ❌ | ✅ | ✅ |
-| Enum value deletion | ✅ | ✅ | ✅ | ✅ |
-| OneOf deletion | ❌ | ❌ | ✅ | ✅ |
-| Import deletion | ❌ | ❌ | ✅ | ✅ |
-| **Type Changes** |
-| Field type change | ✅ | ✅ | ✅ | ✅ |
-| RPC request/response type | ✅ | ✅ | ✅ | ✅ |
-| Optional/required changes | ✅ | ✅ | ✅ | ✅ |
-| **Naming (Generated Code)** |
-| Field rename (same number) | ❌ | ✅ | ✅ | ❌ |
-| Enum value rename | ❌ | ✅ | ✅ | ✅ |
-| **File Structure** |
-| Package change | ✅ | ✅ | ✅ | ❌ |
-| File options (go_package, etc) | ❌ | ❌ | ✅ | ❌ |
-| Moving types between files | ❌ | ❌ | ✅ | ❌ |
-
-### What This Means
-
-**✅ EasyP WILL detect:**
-- All wire format breaking changes
-- Deletion of services, methods, messages, fields
-- Type changes that break serialization
-- Enum value renames (same number, different name)
-
-**❌ EasyP will NOT detect:**
-- Field renames (same number, different name)
-- Package name changes
-- File option changes (go_package, java_package, etc.)
-- Moving types between files in the same package
-
-## Breaking Change Rules
-
-EasyP detects the following types of breaking changes:
-
-### Comparison with Other Tools
-
-| Detection Level | Description | EasyP Support |
-|----------------|-------------|---------------|
-| **WIRE** | Wire format compatibility only | ✅ **Full support** |
-| **WIRE+** | Wire + element deletion detection | ✅ **Current level** |
-| **FILE** | Generated code compatibility | ❌ Partial (planned) |
-## Breaking Change Rules
-
-EasyP detects the following categories of breaking changes. Each rule has detailed documentation with examples:
-
-### 🚨 Service and RPC Changes
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [SERVICE_NO_DELETE](./rules/service-no-delete.md) | Services cannot be deleted | ✅ Implemented |
-| [RPC_NO_DELETE](./rules/rpc-no-delete.md) | RPC methods cannot be deleted | ✅ Implemented |
-| [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md) | RPC request types cannot be changed | ✅ Implemented |
-| [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) | RPC response types cannot be changed | ✅ Implemented |
-
-### 📦 Message and Field Changes
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [MESSAGE_NO_DELETE](./rules/message-no-delete.md) | Messages cannot be deleted | ✅ Implemented |
-| [FIELD_NO_DELETE](./rules/field-no-delete.md) | Fields cannot be deleted | ✅ Implemented |
-| [FIELD_SAME_TYPE](./rules/field-same-type.md) | Field types cannot be changed | ✅ Implemented |
-| [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) | Field optionality (optional/required) cannot be changed | ✅ Implemented |
-
-### 🔢 Enum Changes
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [ENUM_NO_DELETE](./rules/enum-no-delete.md) | Enums cannot be deleted | ✅ Implemented |
-| [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md) | Enum values cannot be deleted | ✅ Implemented |
-| [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) | Enum value names cannot be changed | ✅ Implemented |
-
-### 🔗 OneOf Changes
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [ONEOF_NO_DELETE](./rules/oneof-no-delete.md) | OneOf fields cannot be deleted | ✅ Implemented |
-| [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md) | Fields within oneofs cannot be deleted | ✅ Implemented |
-| [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) | OneOf field types cannot be changed | ✅ Implemented |
-
-### 📥 Import Changes
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [IMPORT_NO_DELETE](./rules/import-no-delete.md) | Import statements cannot be removed | ✅ Implemented |
-
-## Not Currently Detected
-
-The following changes are **NOT detected** by EasyP (but may break generated code):
-
-| Change Type | Example | Impact |
-|-------------|---------|---------|
-| Field renaming | `string name = 1` → `string full_name = 1` | Generated code breaks |
-| Package changes | `package v1` → `package v2` | Import paths change |
-| File options | `option go_package = "old"` → `option go_package = "new"` | Generated code location |
-| Moving between files | Message moved to different .proto file | Import dependencies |
-
-## Detailed Rules Documentation
-
-For comprehensive examples and migration strategies, see the individual rule documentation:
-
-- **Service Changes**: [SERVICE_NO_DELETE](./rules/service-no-delete.md), [RPC_NO_DELETE](./rules/rpc-no-delete.md), [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md), [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md)
-- **Message Changes**: [MESSAGE_NO_DELETE](./rules/message-no-delete.md), [FIELD_NO_DELETE](./rules/field-no-delete.md), [FIELD_SAME_TYPE](./rules/field-same-type.md), [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md)
-- **Enum Changes**: [ENUM_NO_DELETE](./rules/enum-no-delete.md), [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md), [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md)
-- **OneOf Changes**: [ONEOF_NO_DELETE](./rules/oneof-no-delete.md), [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md), [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md)
-- **Import Changes**: [IMPORT_NO_DELETE](./rules/import-no-delete.md)
-
-Each rule includes:
-- ❌ **Bad examples** with actual breaking changes
-- ✅ **Good alternatives** showing safe approaches
-- 🔧 **Migration strategies** for handling necessary changes
-- 📋 **Real error messages** from EasyP
-
-## Quick Examples
-
-### ✅ Safe Changes (Always Allowed)
-```proto
-// Adding new elements is always safe
-message User {
- string name = 1;
- string email = 2;
- string phone = 3; // ✅ New field - safe
-}
-
-service UserService {
- rpc GetUser(GetUserRequest) returns (GetUserResponse);
- rpc GetUserProfile(GetUserRequest) returns (UserProfile); // ✅ New RPC - safe
-}
-
-enum Status {
- STATUS_UNSPECIFIED = 0;
- STATUS_ACTIVE = 1;
- STATUS_PENDING = 2; // ✅ New enum value - safe
-}
-```
-
-### ❌ Breaking Changes (Always Detected)
-```proto
-// Deletions and type changes break compatibility
-message User {
- string name = 1;
- // ❌ Deleted field - BREAKING
-}
-
-service UserService {
- // ❌ Deleted RPC method - BREAKING
- rpc GetUser(GetUserRequestV2) returns (GetUserResponse); // ❌ Changed request type - BREAKING
-}
-```
-
-### Scenario 3: Breaking Changes (Currently Not Detected)
-
-```proto
-// 🟡 Breaks generated code but passes EasyP checks
-message User {
- string user_name = 1; // Renamed from "name"
- string user_email = 2; // Renamed from "email"
-}
-
-service UserService {
- rpc GetUserProfile(GetUserRequest) returns (GetUserResponse); // Renamed from GetUser
-}
-```
-
-## Output Format
-
-### Text Format (Default)
-
-```
-services.proto:45:1: Previously present RPC "DeleteUser" on service "UserService" was deleted. (BREAKING_CHECK)
-messages.proto:15:3: Previously present field "2" with name "email" on message "User" was deleted. (BREAKING_CHECK)
-```
-
-### JSON Format
-
-```bash
-easyp --format json breaking --against main
-```
-
-```json
-{
- "path": "services.proto",
- "position": {
- "line": 45,
- "column": 1
- },
- "source_name": "",
- "message": "Previously present RPC \"DeleteUser\" on service \"UserService\" was deleted.",
- "rule_name": "BREAKING_CHECK"
-}
-```
-
-## Best Practices
-
-### 1. Regular Checks
-Run breaking change detection in your CI/CD pipeline:
-
-```yaml
-# GitHub Actions example
-- name: Check for breaking changes
- run: easyp breaking --against origin/main
-```
-
-### 2. Branch Protection
-Use breaking change checks to protect important branches:
-
-```yaml
-# Only allow PRs that don't introduce breaking changes
-if: github.event_name == 'pull_request'
-run: |
- easyp breaking --against origin/main
- if [ $? -eq 1 ]; then
- echo "Breaking changes detected!"
- exit 1
- fi
-```
-
-### 3. Versioning Strategy
-When breaking changes are necessary:
-
-- Create a new package version (e.g., `myservice.v2`)
-- Maintain the old version during migration period
-- Use deprecation notices in the old version
-
-### 4. Ignore Patterns
-Use ignore patterns wisely:
-
-```yaml
-breaking:
- ignore:
- - "experimental/**" # Experimental APIs
- - "internal/**" # Internal-only APIs
- - "**/testing/**" # Test utilities
-```
-
-## Common Issues and Solutions
-
-### Issue: "Repository does not exist"
-**Solution**: Ensure you're running the command in a Git repository with the specified branch available.
-
-### Issue: "Cannot find git ref"
-**Solution**: Verify the branch/tag name exists and is accessible:
-```bash
-git branch -a # List all branches
-git tag # List all tags
-```
-
-### Issue: False Positives in Generated Code
-**Solution**: Add generated directories to ignore list:
-```yaml
+~~~yaml
+version: v1
breaking:
- ignore:
- - "generated/**"
- - "**/pb/**"
-```
+ baseline: git:main
+ categories: [FILE]
+ ignore_unstable: true
+ ignore: [experimental]
+~~~
-### Issue: Large Number of Changes
-**Solution**: For major refactoring, consider:
-1. Creating a new API version
-2. Implementing changes incrementally
-3. Using feature flags for gradual rollout
+~~~bash
+easyp breaking --path proto --against main
+easyp --format json breaking --path proto
+~~~
-## Integration Examples
+## Select a baseline and files
-### CI/CD Pipeline Integration
+Precedence is explicit --against, then breaking.baseline, then master. Even explicit --against master overrides configuration. An empty or whitespace-only flag is an error; a missing explicit Git baseline never falls back to the configured one.
-#### GitHub Actions
+The baseline can name a local branch, a lightweight or annotated tag, a full commit SHA, or another locally resolvable Git revision such as HEAD. Required refs and objects must already be present in the checkout. A bare branch name takes precedence over an identically named tag; use refs/tags/v1.2.0 to select the tag explicitly. In YAML use git:refs/tags/v1.2.0; for the CLI pass --against refs/tags/v1.2.0 without a git: or git-ref= prefix.
-```yaml
-name: API Compatibility Check
+--path selects a file or directory relative to the scan root; --root changes that root from the policy directory. Checked file identities remain repository-relative. breaking.ignore excludes directories; vendored sources are excluded from targets.
-on:
- pull_request:
- branches: [ main ]
+Directory and file symlinks select their canonical repository paths, including a deleted suffix beneath an existing directory. Selecting an alias does not skip changes visible through the original path. Targets outside the repository are rejected.
-jobs:
- breaking-changes:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0 # Fetch full history
-
- - name: Install EasyP
- run: |
- curl -sSfL https://raw.githubusercontent.com/easyp-tech/easyp/main/install.sh | sh
-
- - name: Check for breaking changes
- run: |
- ./bin/easyp breaking --against origin/main
-```
+breaking.ignore paths are relative to the file supplying the effective breaking section, not the Git root or --root. For example, ignore: [generated] in api/easyp.yaml excludes api/generated, including when that section is inherited. Entries must be nonempty local relative paths; absolute paths and paths escaping the policy directory or repository are rejected.
-#### GitLab CI
+Policies come from current configuration. Each nearest defined breaking section applies as a whole; nested policies may select different baselines. Repeated identical findings are emitted once.
-```yaml
-breaking-changes:
- stage: test
- image: easyp/lint:latest
- script:
- - git fetch origin main
- - easyp breaking --against origin/main
- rules:
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
-```
+## Revision-local contexts
-### Pre-commit Hook
+Each selected module is compared separately. Current and baseline revisions use their own module roots, protobuf.mod, protobuf.lock, and dependencies. Baseline sources, manifests, and locks are read from an isolated Git snapshot. The caller's checkout, manifest, and lock are unchanged; the verified dependency cache may be populated. Temporary snapshots are removed after use.
-```bash
-#!/bin/sh
-# .git/hooks/pre-push
+Buf source filters and replacement metadata also belong to their respective revisions. Current files or filters never substitute for missing historical metadata. During consumer checks, reached replacement sources supply imports; they become policy targets only when explicitly selected. Unused replacements cannot exclude consumer targets.
-protected_branch='main'
-current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
+Baseline-only files and deleted modules remain checkable, including through --path. Dependency findings use the policy of the selected files. A policy can also run without a module manifest.
-if [ $current_branch = $protected_branch ]; then
- echo "Running breaking changes check..."
- easyp breaking --against HEAD~1
- if [ $? -eq 1 ]; then
- echo "❌ Breaking changes detected. Push rejected."
- exit 1
- fi
- echo "✅ No breaking changes detected."
-fi
-```
+Local replacements inside the repository use the contents of the corresponding revision; absolute paths inside the repository are mapped into the baseline snapshot. External local replacements are rejected because they have no recoverable historical identity. Use a locked dependency for a reproducible baseline.
-## Troubleshooting
+## Categories and unstable packages
-### Debug Mode
-Enable debug logging for detailed information:
+breaking.categories selects descriptor-based profiles: FILE, PACKAGE, WIRE_JSON, or WIRE. Omitted or empty categories select FILE. Multiple profiles apply their union without duplicate diagnostics.
-```bash
-easyp --debug breaking --against main
-```
+| Change | FILE | PACKAGE | WIRE_JSON | WIRE |
+|---|---|---|---|---|
+| Move a declaration within its package, preserving options | Reject | Allow | Allow | Allow |
+| Rename a field, even with its old JSON name retained | Reject | Reject | Reject | Allow |
+| Change int32 to int64 | Reject | Reject | Reject | Allow |
+| Change int32 to uint32 | Reject | Reject | Allow | Allow |
+| Change string to bytes | Reject | Reject | Reject | Allow |
+| Change bytes to string or int32 to sint32 | Reject | Reject | Reject | Reject |
+| Delete a non-required field | Reject | Reject | Reserve number and name | Reserve number |
+| Add/remove a required field or change a real oneof | Reject | Reject | Reject | Reject |
+| Add explicit optional presence | Reject | Reject | Allow | Allow |
+| Convert repeated entry messages to a compatible map | Reject | Reject | Reject | Allow |
-### Manual Comparison
-For complex cases, you can manually inspect the comparison:
+A map is encoded as repeated entry messages; repeated scalar values are not compatible merely because their type equals the map value type. Existing reserved names and number ranges cannot be released in any profile. Enum aliases are checked by name/number pairs for source/JSON and by retained numbers for WIRE. RPC/service removal, request/response identity, streaming, idempotency, and actual default-value changes remain checked. Source profiles additionally check supported file/field code-generation options, enum openness, declaration and extension ranges. WIRE_JSON also checks JSON format capability.
-```bash
-# Compare specific files
-git show main:path/to/file.proto > old_version.proto
-easyp lint old_version.proto # Validate old version
-easyp lint current_file.proto # Validate current version
-```
+Current and baseline sources are compiled separately using their own imports and pinned revisions. Diagnostics retain source coordinates and repository-relative paths; consumer managed options are not applied. Profiles work with section-scoped extends, ignores, local overlays and frozen verification. No source, manifest, lock or plugin output is written by breaking.
-### Performance Optimization
-For large repositories:
+The precise implemented rule catalog is internal/config/breaking_profiles.go. This feature does not claim full rule-for-rule Buf equivalence. It checks standard descriptor properties and supported effective Edition features, not arbitrary application-defined option semantics or external generated-code behavior. Unsupported syntax/editions are rejected by the pinned compiler instead of being declared compatible.
-```bash
-# Limit scope to specific paths
-easyp breaking --against main --path api/
-```
+breaking.ignore_unstable defaults to false. When true, it excludes packages on both sides whose final component matches vNtest..., vNalpha, vNbeta, vNpMalpha, or vNpMbeta. N and M are positive numbers without leading zeros; alpha/beta may have a similarly positive sequence number, and test may have any suffix. For example, acme.v1beta1 is skipped, while acme.v1beta1.service and acme.v0alpha1 are not. Stable packages and their references to unstable types remain checked; source reading and import resolution precede filtering.
-The breaking changes detection in EasyP provides a robust foundation for maintaining API compatibility while allowing your protobuf schemas to evolve safely over time.
+breaking.extends loads a local or locked-module policy. Its baseline and ignore paths apply in the consuming repository; local fields override inherited values. The old breaking_check.against_git_ref key is not accepted by the v1 CLI. See the [policy reference](/docs/reference/easyp-yaml) for all fields.
diff --git a/content/docs/cli/breaking-changes/index.ru.mdx b/content/docs/cli/breaking-changes/index.ru.mdx
index 915e8b7..0765706 100644
--- a/content/docs/cli/breaking-changes/index.ru.mdx
+++ b/content/docs/cli/breaking-changes/index.ru.mdx
@@ -1,441 +1,71 @@
---
-title: "Обнаружение несовместимых изменений (Breaking Changes Detection)"
+title: "Проверка несовместимых изменений"
+description: "Сравнение protobuf-схем с Git-базой и зависимостями каждой ревизии в EasyP v1."
---
-[[toc]]
+easyp breaking сравнивает выбранные текущие .proto с Git-базой и выводит несовместимые изменения.
-Механизм EasyP для обнаружения несовместимых (breaking) изменений помогает поддерживать обратную совместимость ваших protobuf API, автоматически выявляя изменения, способные сломать существующих клиентов. Это критично для стабильных API в продакшене.
-
-## Обзор
-
-Проверка несовместимых изменений сравнивает текущий набор protobuf‑файлов с предыдущей версией (обычно из другой Git ветки) и фиксирует модификации, которые могут вызвать проблемы совместимости для уже работающих клиентов.
-
-### Ключевые возможности
-
-- **Сравнение через Git**: Сопоставление с любой Git‑ссылкой (ветка, тег, commit)
-- **Комплексный анализ**: Проверка сервисов, сообщений, enum'ов, полей и import'ов
-- **Выборочное игнорирование**: Пропуск указанных директорий из анализа
-- **Детализированные отчёты**: Понятные ошибки с именами файлов, строками и позициями
-
-## Как работает
-
-Детектор breaking changes выполняет следующие шаги:
-
-1. **Получение ветки сравнения**: Забирает proto-файлы из указанной Git‑ссылки
-2. **Парсинг обеих версий**: Анализирует структуру текущих и предыдущих файлов
-3. **Сравнение сущностей**: Последовательно проверяет все элементы protobuf на breaking изменения
-4. **Формирование отчёта**: Генерирует подробные записи об ошибках с локациями и описаниями
-
-## Уровень проверки
-
-EasyP реализует уровень проверки **WIRE+**:
-- ✅ **Полная совместимость по wire‑формату** — старые и новые версии могут обмениваться данными
-- ✅ **Обнаружение удалений элементов** — сервисы, сообщения, поля и т.п.
-- ✅ **Безопасность типов** — выявляет несовместимые изменения типов
-- ❌ **Переименования полей/методов** — пока не детектируются (в планах)
-- ❌ **Изменения на уровне файлов** — переносы пакетов, file options ещё не проверяются
-
-Это даёт сильные гарантии совместимости и меньше ограничений, чем инструменты, требующие совместимости сгенерированного кода.
-
-## Конфигурация
-
-Настройка в `easyp.yaml`:
-
-```yaml
+~~~yaml
+version: v1
breaking:
- # Git reference для сравнения (branch, tag или commit hash)
- against_git_ref: "main"
-
- # Директории, игнорируемые в анализе breaking changes
- ignore:
- - "experimental"
- - "internal/proto"
- - "vendor"
-```
-
-### Параметры конфигурации
-
-| Option | Description | Default | Required |
-|--------|-------------|---------|----------|
-| `against_git_ref` | Git‑ссылка для сравнения | `"master"` | No |
-| `ignore` | Список директорий для исключения из анализа | `[]` | No |
-
-## Использование
-
-### Базовый пример
-
-Сравнение текущих изменений с веткой main:
-
-```bash
-easyp breaking --against main
-```
-
-### Использование файла конфигурации
-
-```bash
-easyp --cfg my-config.yaml breaking
-```
-
-### Переопределение Git‑ссылки
-
-```bash
-easyp breaking --against feature/new-api
-```
-
-## Уровень проверки
-
-EasyP сейчас работает на уровне **WIRE+**, обеспечивая совместимость wire‑формата плюс защиту от удалений и изменения критичных типов.
-
-### Сравнение с категориями Buf
-
-| Check Type | Buf WIRE | Buf WIRE_JSON | Buf FILE | EasyP Current |
-|------------|----------|---------------|----------|---------------|
-| **Element Deletions** |
-| Service deletion | ❌ | ❌ | ✅ | ✅ |
-| RPC method deletion | ❌ | ❌ | ✅ | ✅ |
-| Message deletion | ❌ | ❌ | ✅ | ✅ |
-| Field deletion (by number) | ✅ | ✅ | ✅ | ✅ |
-| Enum deletion | ❌ | ❌ | ✅ | ✅ |
-| Enum value deletion | ✅ | ✅ | ✅ | ✅ |
-| OneOf deletion | ❌ | ❌ | ✅ | ✅ |
-| Import deletion | ❌ | ❌ | ✅ | ✅ |
-| **Type Changes** |
-| Field type change | ✅ | ✅ | ✅ | ✅ |
-| RPC request/response type | ✅ | ✅ | ✅ | ✅ |
-| Optional/required changes | ✅ | ✅ | ✅ | ✅ |
-| **Naming (Generated Code)** |
-| Field rename (same number) | ❌ | ✅ | ✅ | ❌ |
-| Enum value rename | ❌ | ✅ | ✅ | ✅ |
-| **File Structure** |
-| Package change | ✅ | ✅ | ✅ | ❌ |
-| File options (go_package, etc) | ❌ | ❌ | ✅ | ❌ |
-| Moving types between files | ❌ | ❌ | ✅ | ❌ |
-
-### Что это означает
-
-**✅ EasyP обнаружит:**
-- Все breaking изменения wire‑формата
-- Удаления сервисов, методов, сообщений, полей
-- Изменения типов, ломающие сериализацию
-- Переименования enum‑значений (при сохранении номера)
-
-**❌ EasyP НЕ обнаружит:**
-- Переименование полей (с тем же номером)
-- Изменение package
-- File options (go_package, java_package, и т.п.)
-- Перемещение типов между файлами в одном package
-
-## Правила Breaking Changes
-
-EasyP обнаруживает следующие типы breaking изменений:
-
-### Сравнение уровней
-
-| Detection Level | Description | EasyP Support |
-|----------------|-------------|---------------|
-| **WIRE** | Совместимость только по wire‑формату | ✅ **Full support** |
-| **WIRE+** | Wire + обнаружение удалений | ✅ **Current level** |
-| **FILE** | Совместимость сгенерированного кода | ❌ Partial (planned) |
-
-## Категории правил
-
-Каждая категория имеет свою документацию с примерами:
-
-### 🚨 Изменения Service и RPC
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [SERVICE_NO_DELETE](./rules/service-no-delete.md) | Services cannot be deleted | ✅ Implemented |
-| [RPC_NO_DELETE](./rules/rpc-no-delete.md) | RPC methods cannot be deleted | ✅ Implemented |
-| [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md) | RPC request types cannot be changed | ✅ Implemented |
-| [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md) | RPC response types cannot be changed | ✅ Implemented |
-
-### 📦 Изменения Message и Field
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [MESSAGE_NO_DELETE](./rules/message-no-delete.md) | Messages cannot be deleted | ✅ Implemented |
-| [FIELD_NO_DELETE](./rules/field-no-delete.md) | Fields cannot be deleted | ✅ Implemented |
-| [FIELD_SAME_TYPE](./rules/field-same-type.md) | Field types cannot be changed | ✅ Implemented |
-| [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md) | Field optionality (optional/required) cannot be changed | ✅ Implemented |
-
-### 🔢 Изменения Enum
+ baseline: git:main
+ categories: [FILE]
+ ignore_unstable: true
+ ignore: [experimental]
+~~~
-| Rule | Description | Status |
-|------|-------------|---------|
-| [ENUM_NO_DELETE](./rules/enum-no-delete.md) | Enums cannot be deleted | ✅ Implemented |
-| [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md) | Enum values cannot be deleted | ✅ Implemented |
-| [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md) | Enum value names cannot be changed | ✅ Implemented |
-
-### 🔗 Изменения OneOf
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [ONEOF_NO_DELETE](./rules/oneof-no-delete.md) | OneOf fields cannot be deleted | ✅ Implemented |
-| [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md) | Fields within oneofs cannot be deleted | ✅ Implemented |
-| [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md) | OneOf field types cannot be changed | ✅ Implemented |
-
-### 📥 Изменения Import
-
-| Rule | Description | Status |
-|------|-------------|---------|
-| [IMPORT_NO_DELETE](./rules/import-no-delete.md) | Import statements cannot be removed | ✅ Implemented |
-
-## Не обнаруживается сейчас
-
-Изменения ниже **НЕ детектируются** EasyP (могут ломать сгенерированный код):
-
-| Change Type | Example | Impact |
-|-------------|---------|--------|
-| Field renaming | `string name = 1` → `string full_name = 1` | Ломает код |
-| Package changes | `package v1` → `package v2` | Меняются пути импорта |
-| File options | `option go_package = "old"` → `option go_package = "new"` | Меняется расположение кода |
-| Moving between files | Message перемещено в другой .proto | Зависимости import'ов |
-
-## Документация правил
-
-См. подробные файлы правил для примеров и стратегий миграции:
-
-- Service: [SERVICE_NO_DELETE](./rules/service-no-delete.md), [RPC_NO_DELETE](./rules/rpc-no-delete.md), [RPC_SAME_REQUEST_TYPE](./rules/rpc-same-request-type.md), [RPC_SAME_RESPONSE_TYPE](./rules/rpc-same-response-type.md)
-- Message: [MESSAGE_NO_DELETE](./rules/message-no-delete.md), [FIELD_NO_DELETE](./rules/field-no-delete.md), [FIELD_SAME_TYPE](./rules/field-same-type.md), [FIELD_SAME_CARDINALITY](./rules/field-same-cardinality.md)
-- Enum: [ENUM_NO_DELETE](./rules/enum-no-delete.md), [ENUM_VALUE_NO_DELETE](./rules/enum-value-no-delete.md), [ENUM_VALUE_SAME_NAME](./rules/enum-value-same-name.md)
-- OneOf: [ONEOF_NO_DELETE](./rules/oneof-no-delete.md), [ONEOF_FIELD_NO_DELETE](./rules/oneof-field-no-delete.md), [ONEOF_FIELD_SAME_TYPE](./rules/oneof-field-same-type.md)
-- Import: [IMPORT_NO_DELETE](./rules/import-no-delete.md)
-
-Каждое правило содержит:
-- ❌ Плохие примеры (breaking)
-- ✅ Безопасные альтернативы
-- 🔧 Стратегии миграции
-- 📋 Реальные сообщения ошибок из EasyP
-
-## Быстрые примеры
-
-### ✅ Безопасные изменения (разрешены всегда)
-```proto
-// Добавление новых элементов — безопасно
-message User {
- string name = 1;
- string email = 2;
- string phone = 3; // ✅ Новое поле
-}
-
-service UserService {
- rpc GetUser(GetUserRequest) returns (GetUserResponse);
- rpc GetUserProfile(GetUserRequest) returns (UserProfile); // ✅ Новый RPC
-}
-
-enum Status {
- STATUS_UNSPECIFIED = 0;
- STATUS_ACTIVE = 1;
- STATUS_PENDING = 2; // ✅ Новое enum значение
-}
-```
-
-### ❌ Несовместимые изменения (обнаруживаются всегда)
-```proto
-// Удаления и смена типов ломают совместимость
-message User {
- string name = 1;
- // ❌ Удалённое поле
-}
-
-service UserService {
- // ❌ Удалённый RPC метод
- rpc GetUser(GetUserRequestV2) returns (GetUserResponse); // ❌ Изменён тип запроса
-}
-```
-
-### Сценарий: Изменения пока не детектируются
-
-```proto
-// 🟡 Ломает сгенерированный код, но проходит проверки EasyP
-message User {
- string user_name = 1; // Переименовано с "name"
- string user_email = 2; // Переименовано с "email"
-}
-
-service UserService {
- rpc GetUserProfile(GetUserRequest) returns (GetUserResponse); // Переименовано с GetUser
-}
-```
-
-## Формат вывода
-
-### Текстовый формат (по умолчанию)
-
-```
-services.proto:45:1: Previously present RPC "DeleteUser" on service "UserService" was deleted. (BREAKING_CHECK)
-messages.proto:15:3: Previously present field "2" with name "email" on message "User" was deleted. (BREAKING_CHECK)
-```
-
-### JSON формат
-
-```bash
-easyp --format json breaking --against main
-```
-
-```json
-{
- "path": "services.proto",
- "position": {
- "line": 45,
- "column": 1
- },
- "source_name": "",
- "message": "Previously present RPC \"DeleteUser\" on service \"UserService\" was deleted.",
- "rule_name": "BREAKING_CHECK"
-}
-```
-
-## Best Practices
-
-### 1. Регулярный запуск
-Добавьте проверку несовместимых изменений в CI/CD:
-
-```yaml
-- name: Check for breaking changes
- run: easyp breaking --against origin/main
-```
-
-### 2. Защита веток
-Блокируйте слияния с breaking изменениями:
-
-```yaml
-if: github.event_name == 'pull_request'
-run: |
- easyp breaking --against origin/main
- if [ $? -eq 1 ]; then
- echo "Breaking changes detected!"
- exit 1
- fi
-```
-
-### 3. Стратегия версионирования
-При необходимости breaking изменений:
-- Создайте новую версию пакета (`myservice.v2`)
-- Поддерживайте старую версию в период миграции
-- Добавляйте уведомления о деприкации
-
-### 4. Игнорирование путей
-Используйте ignore осознанно:
-
-```yaml
-breaking:
- ignore:
- - "experimental/**"
- - "internal/**"
- - "**/testing/**"
-```
-
-## Частые проблемы
-
-### Проблема: "Repository does not exist"
-Решение: Выполняйте команду внутри Git репозитория с нужной веткой.
-
-### Проблема: "Cannot find git ref"
-Решение: Проверьте наличие ссылки:
-```bash
-git branch -a
-git tag
-```
-
-### Проблема: Ложные срабатывания на сгенерированный код
-Решение: Исключите директории генерации:
-```yaml
-breaking:
- ignore:
- - "generated/**"
- - "**/pb/**"
-```
+~~~bash
+easyp breaking --path proto --against main
+easyp --format json breaking --path proto
+~~~
-### Проблема: Очень много изменений
-Решение:
-1. Создайте новую версию API
-2. Вносите изменения постепенно
-3. Используйте feature flags
+## Выбор базы и файлов
-## Примеры интеграции
+Приоритет: явный --against, затем breaking.baseline, затем master. Даже явный --against master перекрывает конфигурацию. Пустое или пробельное значение флага — ошибка; отсутствующая явная Git-база не заменяется конфигурационной.
-### GitHub Actions
+База может указывать на локальную ветку, лёгкий или аннотированный тег, полный SHA коммита или другую разрешимую локально Git-ревизию, например HEAD. Нужные ссылки и объекты должны уже присутствовать в checkout. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0. В YAML задавайте git:refs/tags/v1.2.0, а в CLI — --against refs/tags/v1.2.0 без префикса git: или git-ref=.
-```yaml
-name: API Compatibility Check
+--path выбирает файл или каталог относительно корня проверки; --root меняет этот корень с каталога политики. Идентичность проверяемых файлов остаётся относительно Git-репозитория. breaking.ignore исключает каталоги; вендорные исходники не становятся целями проверки.
-on:
- pull_request:
- branches: [ main ]
+Symlink на каталог или файл выбирает канонический путь внутри репозитория, в том числе удалённый суффикс под существующим каталогом. Выбор ссылки не пропускает изменения, видимые по исходному пути. Цели за пределами репозитория отклоняются.
-jobs:
- breaking-changes:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- - name: Install EasyP
- run: |
- curl -sSfL https://raw.githubusercontent.com/easyp-tech/easyp/main/install.sh | sh
- - name: Check for breaking changes
- run: |
- ./bin/easyp breaking --against origin/main
-```
+Пути breaking.ignore отсчитываются от файла, задающего эффективную секцию breaking, а не от корня Git или --root. Например, ignore: [generated] в api/easyp.yaml исключает api/generated, в том числе при наследовании этой секции. Допустимы непустые локальные относительные пути; абсолютные пути и выход за каталог политики или репозиторий отклоняются.
-### GitLab CI
+Политики берутся из текущей конфигурации. Ближайшая определённая секция breaking применяется целиком; вложенные политики могут выбирать разные базы. Повторяющиеся одинаковые замечания выводятся один раз.
-```yaml
-breaking-changes:
- stage: test
- image: easyp/lint:latest
- script:
- - git fetch origin main
- - easyp breaking --against origin/main
- rules:
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
-```
+## Контекст каждой ревизии
-### Pre-commit / pre-push hook
+Каждый выбранный модуль сравнивается отдельно. Текущая ревизия и база используют собственные корни модулей, protobuf.mod, protobuf.lock и зависимости. Исходники, манифесты и lock базы читаются из изолированного Git-снимка. Рабочее дерево, манифест и lock пользователя не меняются; проверенный кеш зависимостей может пополняться. Временные снимки удаляются после проверки.
-```bash
-#!/bin/sh
-# .git/hooks/pre-push
+Фильтры Buf и метаданные замен также берутся из соответствующей ревизии. Текущие файлы и фильтры не подставляются вместо отсутствующих исторических метаданных. При проверке потребителя достижимые исходники замен предоставляют импорты; собственная политика проверяется при явном выборе замены. Неиспользуемые замены не исключают цели потребителя.
-protected_branch='main'
-current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
+Файлы, существующие только в базе, и удалённые модули остаются доступными для проверки, в том числе через --path. Политика выбранных файлов определяет и политику замечаний о зависимостях. Проверка возможна и без манифеста модуля.
-if [ $current_branch = $protected_branch ]; then
- echo "Running breaking changes check..."
- easyp breaking --against HEAD~1
- if [ $? -eq 1 ]; then
- echo "❌ Breaking changes detected. Push rejected."
- exit 1
- fi
- echo "✅ No breaking changes detected."
-fi
-```
+Локальная замена внутри репозитория использует содержимое соответствующей ревизии; абсолютный путь внутри репозитория отображается в снимок базы. Внешняя локальная замена отклоняется: у неё нет восстановимой исторической идентичности. Для воспроизводимой базы используйте зафиксированную зависимость.
-## Troubleshooting
+## Категории и нестабильные пакеты
-### Режим отладки
-Включите debug‑логирование:
+breaking.categories выбирает профили сравнения скомпилированных дескрипторов: FILE, PACKAGE, WIRE_JSON или WIRE. Отсутствующий или пустой список выбирает FILE. Несколько профилей применяются совместно без повторения одинаковых диагностик.
-```bash
-easyp --debug breaking --against main
-```
+| Изменение | FILE | PACKAGE | WIRE_JSON | WIRE |
+|---|---|---|---|---|
+| Перенос объявления внутри пакета с сохранением options | Ошибка | Допустимо | Допустимо | Допустимо |
+| Переименование поля, даже при сохранённом JSON-имени | Ошибка | Ошибка | Ошибка | Допустимо |
+| int32 → int64 | Ошибка | Ошибка | Ошибка | Допустимо |
+| int32 → uint32 | Ошибка | Ошибка | Допустимо | Допустимо |
+| string → bytes | Ошибка | Ошибка | Ошибка | Допустимо |
+| bytes → string или int32 → sint32 | Ошибка | Ошибка | Ошибка | Ошибка |
+| Удаление необязательного поля | Ошибка | Ошибка | Зарезервировать номер и имя | Зарезервировать номер |
+| Добавление/удаление required или изменение настоящего oneof | Ошибка | Ошибка | Ошибка | Ошибка |
+| Добавление явной optional-presence | Ошибка | Ошибка | Допустимо | Допустимо |
+| Повторяемые entry-сообщения → совместимый map | Ошибка | Ошибка | Ошибка | Допустимо |
-### Ручное сравнение
-Для сложных случаев:
+Map кодируется повторяемыми entry-сообщениями: повторяемый scalar не становится совместимым с map только из-за совпадения типа значения. Существующие резервные имена и диапазоны номеров нельзя освобождать ни в одном профиле. Alias-значения enum проверяются по парам имя/номер для source/JSON и сохранённым номерам для WIRE. Проверяются удаления RPC/сервисов, типы запросов/ответов, streaming, idempotency и фактические значения по умолчанию. Source-профили дополнительно проверяют поддержанные file/field options генераторов, открытость enum, объявления и диапазоны extension. WIRE_JSON также проверяет возможность JSON-представления.
-```bash
-git show main:path/to/file.proto > old_version.proto
-easyp lint old_version.proto
-easyp lint current_file.proto
-```
+Текущие исходники и baseline компилируются отдельно, со своими импортами и закреплёнными ревизиями. Диагностика сохраняет координаты исходника и путь относительно репозитория; consumer managed-options не применяются. Профили работают с extends, исключениями, локальными заменами и frozen-проверкой. Команда breaking не записывает исходники, manifest, lock или результат плагинов.
-### Оптимизация производительности
-Ограничьте область:
+Точный реализованный каталог правил находится в internal/config/breaking_profiles.go. Полная эквивалентность всем правилам Buf не заявляется. Проверяются стандартные свойства дескрипторов и поддержанные эффективные Edition features, а не произвольный смысл пользовательских options или поведение внешнего сгенерированного кода. Неподдерживаемый синтаксис/Edition отклоняется закреплённым компилятором, а не признаётся совместимым.
-```bash
-easyp breaking --against main --path api/
-```
+breaking.ignore_unstable по умолчанию равен false. При true на обеих сторонах сравнения исключаются пакеты, последний компонент имени которых соответствует vNtest..., vNalpha, vNbeta, vNpMalpha или vNpMbeta. N и M — положительные числа без ведущего нуля; после alpha/beta допустим такой же положительный номер, после test — любой суффикс. Например, acme.v1beta1 пропускается, а acme.v1beta1.service и acme.v0alpha1 — нет. Стабильные пакеты и их ссылки на нестабильные типы всё ещё проверяются; чтение исходников и разрешение импортов происходят до фильтрации.
-Механизм обнаружения несовместимых изменений в EasyP обеспечивает надёжную основу для безопасной эволюции protobuf‑схем при сохранении совместимости API.
+breaking.extends загружает локальную политику или базу из закреплённого модуля. Baseline и ignore применяются в репозитории потребителя; локальные поля приоритетнее базы. Старый ключ breaking_check.against_git_ref CLI v1 не принимает. Все поля описаны в [справочнике политики](/ru/docs/reference/easyp-yaml).
diff --git a/content/docs/cli/configuration.mdx b/content/docs/cli/configuration.mdx
index fec2196..f1baf08 100644
--- a/content/docs/cli/configuration.mdx
+++ b/content/docs/cli/configuration.mdx
@@ -1,932 +1,140 @@
---
-title: "EasyP Configuration Reference"
+title: "EasyP v1 Pilot Configuration"
+description: "The files and CLI commands used by the EasyP v1 pilot."
---
-EasyP can be configured through CLI flags, environment variables, and configuration files. This guide covers all configuration options available in EasyP.
+The v1 pilot separates module dependencies, generation, and lint and breaking policies:
-## CLI Flags
+| File | Purpose |
+|------|---------|
+| [protobuf.mod](/docs/reference/protobuf-mod) | Module identity, source roots, requirements, and local replacements |
+| [protobuf.lock](/docs/reference/protobuf-lock) | Resolved Git commits and content hashes; generated by easyp mod tidy |
+| [easyp.gen.yaml](/docs/reference/easyp-gen-yaml) | Modules to generate, plugins, outputs, and managed options |
+| [easyp.yaml](/docs/reference/easyp-yaml) | Lint and breaking policies |
-### Global Flags
+The CLI commands use the v1 files directly. They do not fall back to the older EasyP generation, lint, breaking, or module-management configuration. A Git dependency can still use older EasyP or Buf configuration: the dependency reader extracts its requirements and proto roots for import resolution.
-Available for all commands:
+For guided v0 migration, run easyp migrate in a terminal. Explicit --interactive starts the wizard with supplied values; --interactive=false disables it. Supplying --module without requesting the wizard preserves the original preview. See [v0 migration](/docs/migration/easyp-v0).
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--cfg` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` |
-| `--config` | | `EASYP_CFG` | Alias for `--cfg` | `easyp.yaml` |
-| `--debug` | `-d` | `EASYP_DEBUG` | Enable debug mode | `false` |
-| `--format` | `-f` | `EASYP_FORMAT` | Output format for commands that support multiple formats (`text`/`json`) | command-specific default |
+## Typical workflow
-**Examples:**
-```bash
-# Use custom config file
-easyp --cfg production.easyp.yaml lint
-
-# Enable debug logging
-easyp --debug lint
-
-# Short form
-easyp -c custom.yaml -d lint
-```
-
-### Command-Specific Flags
-
-**Lint command:**
-```bash
-easyp lint [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--path` | `-p` | | Directory path to lint | `.` |
-| `--root` | `-r` | | Base directory for file search | Current working directory |
-| `--format` | `-f` | `EASYP_FORMAT` | Uses global format flag (`text`/`json`) | Inherits global default |
-
-**Examples:**
-```bash
-# Lint specific directory
-easyp lint --path proto/
-
-# Lint from subdirectory with proper import resolution
-easyp lint --root src/IPC/Contracts --path .
-
-# JSON output format
-easyp --format json lint # global flag
-
-# Combined flags
-easyp -f json lint -p proto/
-```
-
-**Generate command:**
-```bash
-easyp generate [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--path` | `-p` | `EASYP_ROOT_GENERATE_PATH` | Directory path with proto files to generate | `.` |
-| `--root` | `-r` | | Base directory for file search | Current working directory |
-
-**Examples:**
-```bash
-# Generate from specific path
-easyp generate --path api/
-
-# Generate from subdirectory with proper import resolution
-easyp generate --root src/IPC/Contracts --path .
-
-# Using environment variable
-EASYP_ROOT_GENERATE_PATH=proto/ easyp generate
-```
-
-**Breaking command:**
-```bash
-easyp breaking [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--against` | | | Git ref to compare against | `master` |
-| `--path` | `-p` | | Directory path to check | `.` |
-| `--format` | `-f` | `EASYP_FORMAT` | Uses global format flag (`text`/`json`) | Inherits global default |
-
-**Examples:**
-```bash
-# Check against main branch
-easyp breaking --against main
-
-# Check specific directory against develop branch
-easyp breaking --against develop --path proto/
-
-# JSON output
-easyp --format json breaking --against main # global flag
-```
-
-**Init command:**
-```bash
-easyp init [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--dir` | `-d` | `EASYP_INIT_DIR` | Directory to initialize | `.` |
-
-**Examples:**
-```bash
-# Initialize current directory
-easyp init
-
-# Initialize specific directory
-easyp init --dir proto-project/
-```
-
-`easyp init` is interactive:
-- If `buf.yml`/`buf.yaml` exists in the target directory root, it asks whether to migrate from Buf.
-- If `easyp.yaml` already exists, it asks for overwrite confirmation.
-
-**Validate-config command:**
-```bash
-easyp validate-config [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--config` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` |
-| `--format` (global) | `-f` | `EASYP_FORMAT` | Output format for commands that support multiple formats (`json` or `text`) | command-specific (`json` for `validate-config`) |
-
-**Examples:**
-```bash
-# Validate default config with JSON output (exit 0 when no errors)
-easyp validate-config
-
-# Validate a different file with text output (global --format)
-easyp --format text validate-config --config example.easyp.yaml
-```
-
-**Package management commands:**
-
-#### `easyp mod download`
-Downloads dependencies based on lock file priority:
-
-1. **If `easyp.lock` exists** - downloads exact versions from lock file
-2. **If `easyp.lock` is missing** - downloads versions from `easyp.yaml` and creates `easyp.lock`
-
-```bash
-# Download exact versions (recommended for production)
+~~~bash
+easyp init --module github.com/acme/contracts
+easyp mod tidy
easyp mod download
-```
-
-#### `easyp mod update`
-Always downloads dependencies from `easyp.yaml`, ignoring existing lock file:
-
-1. **Ignores `easyp.lock`** completely
-2. **Downloads versions from `easyp.yaml`**
-3. **Creates/updates `easyp.lock`** with new versions
-
-```bash
-# Update dependencies and lock file
-easyp mod update
-```
-
-#### `easyp mod vendor`
-Copies proto files from dependencies to local `vendor/` directory (similar to `go mod vendor`).
-
-```bash
-# Create local vendor directory with dependencies
-easyp mod vendor
-```
-
-No additional flags. Uses global `--cfg` flag for configuration.
-
-## Environment Variables
-
-EasyP supports environment variables for configuration:
-
-| Variable | Description | Default |
-|----------|-------------|---------|
-| `EASYP_CFG` | Path to configuration file | `easyp.yaml` |
-| `EASYP_DEBUG` | Enable debug logging | `false` |
-| `EASYPPATH` | Cache and modules storage directory | `$HOME/.easyp` |
-| `EASYP_FORMAT` | Output format for supported commands (`text`/`json`). If not set, each command uses its own default. | command-specific default |
-| `EASYP_ROOT_GENERATE_PATH` | Root path for generate command | `.` |
-| `EASYP_INIT_DIR` | Directory for init command | `.` |
-
-**Examples:**
-```bash
-# Custom cache directory
-export EASYPPATH=/tmp/easyp-cache
-easyp mod download
-
-# Debug mode via environment
-export EASYP_DEBUG=true
-easyp lint
-
-# Custom config file
-export EASYP_CFG=config/easyp.yaml
easyp generate
-```
-
-## Configuration File
-
-The `easyp.yaml` file is the main configuration file for EasyP, defining how your proto files are linted, generated, and managed. This file is typically placed at the root of your project alongside your proto files.
-
-### File Structure Overview
-
-```
-.
-├── easyp.yaml
-├── easyp.lock
-├── proto/
-│ ├── user/
-│ │ └── user.proto
-│ └── order/
-│ └── order.proto
-└── vendor/
-```
-
-### Configuration Format
-
-EasyP supports both YAML and JSON configuration formats:
-
-#### YAML Format (Recommended)
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
-deps:
- - github.com/googleapis/googleapis@v1.0.0
-generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
-breaking:
- ignore:
- - proto/experimental/
- against_git_ref: main
-```
-
-#### JSON Format
-```json
-{
- "lint": {
- "use": ["BASIC", "COMMENT_SERVICE"]
- },
- "deps": [
- "github.com/googleapis/googleapis@v1.0.0"
- ],
- "generate": {
- "inputs": [
- {"directory": "proto"}
- ],
- "plugins": [
- {
- "name": "go",
- "out": ".",
- "opts": {
- "paths": "source_relative"
- }
- }
- ]
- },
- "breaking": {
- "ignore": ["proto/experimental/"],
- "against_git_ref": "main"
- }
-}
-```
-
-### Environment Variables in Configuration
-
-EasyP supports environment variable expansion directly in the `easyp.yaml` configuration file. This allows you to use environment variables for dynamic configuration values.
-
-**Example with all supported features:**
-```yaml
-deps:
- # Basic expansion: ${VAR} - expands to the value of VAR
- - ${GOOGLEAPIS_REPO}@${GOOGLEAPIS_VERSION}
-
- # Default value: ${VAR:-default} - uses default if VAR is unset or empty
- - ${GNOSTIC_REPO:-github.com/google/gnostic}@${GNOSTIC_VERSION:-v0.7.0}
+easyp lint --path proto
+easyp breaking --path proto --against main
+~~~
-generate:
- inputs:
- # Default value if INPUT_DIR is not set
- - directory: ${INPUT_DIR:-proto}
- plugins:
- - name: go
- # Basic expansion
- out: ${OUTPUT_DIR}
- opts:
- # Default value
- module: ${MODULE_NAME:-github.com/example/project}
- timeout: ${TIMEOUT:-30}
-
- # Escaping: $$ becomes literal $, $${VAR} becomes literal ${VAR}
- path: "${BASE_DIR}/$${TEMP}/file" # Result: "/tmp/${TEMP}/file" (if BASE_DIR=/tmp)
- literal: "$$" # Result: "$"
-```
-
-**Supported syntax:**
-- `${VAR}` - expands to the value of `VAR`
-- `${VAR:-default}` - uses `default` if `VAR` is unset or empty
-- `${VAR:=default}` - uses `default` if `VAR` is unset or empty
-- `${VAR-default}` - uses `default` if `VAR` is unset (empty string is kept)
-- `$${VAR}` or `$$VAR` - escapes to literal `${VAR}` or `$VAR`
-- `$$` - escapes to literal `$`
-
-**Note:** Environment variables are expanded before YAML parsing, so any `${STRING}` pattern will be processed. Use `$$` to escape dollar signs when you need literal values.
-
-## Configuration Fields
-
-### `version`
-
-**Optional (legacy compatibility).** This field is accepted for backward compatibility and can be omitted in new configs.
-
-**Type:** `string`
-**Default:** omitted
-**Recommendation:** if you keep it, use `v1alpha`
-
-```yaml
-# Optional compatibility field (can be omitted)
-version: v1alpha
-```
-
-The runtime behavior does not depend on this field.
-
-### `lint`
-
-**Optional.** Configures proto file linting rules and behavior.
-
-**Type:** `object`
-**Default:** Empty (no linting rules applied)
-
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
- ignore:
- - vendor/
- - proto/legacy/
- except:
- - COMMENT_FIELD
- allow_comment_ignores: true
- ignore_only:
- COMMENT_SERVICE:
- - proto/experimental/
-```
-
-#### `lint.use`
-
-**Optional.** Specifies which linter rules or rule categories to apply.
-
-**Type:** `[]string`
-**Default:** `[]` (no rules)
-
-**Available categories:**
-- `MINIMAL` - Essential package consistency checks
-- `BASIC` - Naming conventions and common patterns
-- `DEFAULT` - Additional recommended rules
-- `COMMENTS` - Comment requirements
-- `UNARY_RPC` - Streaming RPC restrictions
-
-**Individual rules:** Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`)
-
-```yaml
-lint:
- use:
- - MINIMAL # Use all minimal rules
- - BASIC # Use all basic rules
- - COMMENT_SERVICE # Require service comments
- - ENUM_PASCAL_CASE # Specific rule
-```
-
-**Rule Categories:**
-
-**MINIMAL:**
-- `DIRECTORY_SAME_PACKAGE`
-- `PACKAGE_DEFINED`
-- `PACKAGE_DIRECTORY_MATCH`
-- `PACKAGE_SAME_DIRECTORY`
-
-**BASIC:**
-- `ENUM_FIRST_VALUE_ZERO`
-- `ENUM_NO_ALLOW_ALIAS`
-- `ENUM_PASCAL_CASE`
-- `ENUM_VALUE_UPPER_SNAKE_CASE`
-- `FIELD_LOWER_SNAKE_CASE`
-- `IMPORT_NO_PUBLIC`
-- `IMPORT_NO_WEAK`
-- `IMPORT_USED`
-- `MESSAGE_PASCAL_CASE`
-- `ONEOF_LOWER_SNAKE_CASE`
-- `PACKAGE_LOWER_SNAKE_CASE`
-- `PACKAGE_SAME_CSHARP_NAMESPACE`
-- `PACKAGE_SAME_GO_PACKAGE`
-- `PACKAGE_SAME_JAVA_MULTIPLE_FILES`
-- `PACKAGE_SAME_JAVA_PACKAGE`
-- `PACKAGE_SAME_PHP_NAMESPACE`
-- `PACKAGE_SAME_RUBY_PACKAGE`
-- `PACKAGE_SAME_SWIFT_PREFIX`
-- `RPC_PASCAL_CASE`
-- `SERVICE_PASCAL_CASE`
-
-**DEFAULT:**
-- `ENUM_VALUE_PREFIX`
-- `ENUM_ZERO_VALUE_SUFFIX`
-- `FILE_LOWER_SNAKE_CASE`
-- `RPC_REQUEST_RESPONSE_UNIQUE`
-- `RPC_REQUEST_STANDARD_NAME`
-- `RPC_RESPONSE_STANDARD_NAME`
-- `PACKAGE_VERSION_SUFFIX`
-- `SERVICE_SUFFIX`
-
-**COMMENTS:**
-- `COMMENT_ENUM`
-- `COMMENT_ENUM_VALUE`
-- `COMMENT_FIELD`
-- `COMMENT_MESSAGE`
-- `COMMENT_ONEOF`
-- `COMMENT_RPC`
-- `COMMENT_SERVICE`
-
-**UNARY_RPC:**
-- `RPC_NO_CLIENT_STREAMING`
-- `RPC_NO_SERVER_STREAMING`
-
-#### `lint.enum_zero_value_suffix`
-
-**Optional.** Specifies the required suffix for enum zero values.
-
-**Type:** `string`
-**Default:** `""` (no suffix required)
-**Common values:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"`
-
-```yaml
-lint:
- enum_zero_value_suffix: "UNSPECIFIED"
-```
-
-This enforces enum zero values like:
-```proto
-enum Status {
- STATUS_UNSPECIFIED = 0; // Required suffix
- STATUS_ACTIVE = 1;
- STATUS_INACTIVE = 2;
-}
-```
-
-#### `lint.service_suffix`
-
-**Optional.** Specifies the required suffix for service names.
-
-**Type:** `string`
-**Default:** `""` (no suffix required)
-**Common values:** `"Service"`, `"API"`, `"Svc"`
-
-```yaml
-lint:
- service_suffix: "Service"
-```
-
-This enforces service names like:
-```proto
-service UserService { // Required "Service" suffix
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `lint.ignore`
-
-**Optional.** Directories or files to exclude from all linting rules.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-lint:
- ignore:
- - vendor/
- - proto/legacy/
- - testdata/
- - "**/*_test.proto"
-```
-
-Paths are relative to the `easyp.yaml` file location. Supports glob patterns.
-
-#### `lint.except`
-
-**Optional.** Disables specific rules globally across the entire project.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-lint:
- except:
- - COMMENT_FIELD
- - COMMENT_MESSAGE
- - SERVICE_SUFFIX
-```
-
-#### `lint.allow_comment_ignores`
-
-**Optional.** Enables inline comment-based rule ignoring within proto files.
-
-**Type:** `boolean`
-**Default:** `false`
-
-```yaml
-lint:
- allow_comment_ignores: true
-```
-
-When enabled, allows comments like:
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-service LegacyAPI {
- // nolint:COMMENT_RPC
- rpc GetData(...) returns (...);
-}
-```
+Without replacements, mod tidy writes the lock, mod download installs pinned commits, and mod update refreshes requirements within their current major versions and updates the lock. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace).
-#### `lint.ignore_only`
+## Explicit frozen mode
-**Optional.** Disables specific rules only for certain files or directories.
+Use --frozen for builds that must use the committed dependency graph. It defaults to false and is never inferred from CI=true. Every selected native module whose dependency graph is used needs both protobuf.mod and protobuf.lock, including an empty lock when there are no dependencies. An explicit workspace-relative generate.modules path uses the selected module's manifest and lock, so a directory containing only easyp.gen.yaml needs no separate pair. Dependency identity selectors still require the consumer manifest and lock. The manifest-free source fallback described below applies only without frozen mode.
-**Type:** `map[string][]string`
-**Default:** `{}`
+~~~bash
+easyp --frozen generate
+easyp lint --frozen --path proto
+easyp breaking --frozen --against main
+easyp mod --frozen download
+easyp mod vendor --frozen
+~~~
-```yaml
-lint:
- ignore_only:
- COMMENT_SERVICE:
- - proto/legacy/
- - vendor/
- SERVICE_SUFFIX:
- - proto/external/
-```
+The flag is accepted globally before the command; locally on generate, lint, breaking, ls-files, get, init, and migrate; and on mod or any of its four subcommands. A true value at any parent or command level enables it. A child --frozen=false cannot cancel a parent's true value.
-**Key:** Rule name or category
-**Value:** Array of file paths or directories
+Frozen rejects every root replace, even unused entries, before accessing replacement paths or fetching dependencies. It checks direct and transitive requirements against the lock and verifies cached content. It never resolves versions, looks up dependency HEAD/tags, or writes either manifest or lock. Missing or stale locks cause an error. Exact locked commits may still be fetched into the cache: frozen is not offline.
-### `deps`
+mod tidy, get, mod update, init, and migrate refuse frozen execution; migration preview and interactive mode are also refused. Prepare the files outside frozen mode. Generation checks every selected graph before any plugin runs. Lint keeps effective policy scoping; breaking uses the baseline revision's own manifest and lock. Local-only ls-files --include-imports=false still validates the frozen graph. See the [package manager](/docs/cli/package-manager#frozen-builds) for the full dependency contract.
-**Optional.** Lists external proto dependencies to download and manage.
+## Command flags
-**Type:** `[]string`
-**Default:** `[]`
+| Command | Relevant flags |
+|---------|----------------|
+| generate | --project (repeatable), --all, --workspace, --descriptor_set_out, --descriptor_set_out_dir, --include_imports |
+| lint | --path (-p), --root (-r) |
+| breaking | --path (-p), --root (-r), --against |
+| init | --dir (-d), --module |
+| validate-config | --config (alias of --cfg), --format |
+| mod download/tidy/vendor/update | --frozen |
+| ls-files | --include-imports (default true), --format (json or text) |
+| schema-gen | --out-dir (default schemas) |
-#### Dependency Format
+The global flags are --cfg (alias --config, default easyp.yaml), --debug (-d), --format (-f, text or json), and --frozen. EASYP_CFG, EASYP_DEBUG, and EASYP_FORMAT set their respective defaults. The module cache uses EASYPPATH or $HOME/.easyp.
-Dependencies follow the format: `$GIT_LINK@$VERSION`
+By default, generate selects the closest easyp.gen.yaml in the current directory or a workspace ancestor. Repeat --project for multiple explicit consumers. --all separately opts into recursive selection below the invocation directory and is mutually exclusive with --project. --workspace sets the boundary for module paths and inheritance; by default this is the nearest Git repository or enclosing EasyP files. Modules and roots come from protobuf.mod; generate.packages selects exact protobuf package names across the selected modules. The generate --path and generate --root flags are unavailable.
-**Components:**
-- `$GIT_LINK` - Git repository URL (GitHub, GitLab, etc.)
-- `$VERSION` - Git tag or full commit hash (optional)
+--descriptor_set_out merges compatible graphs into one file; --descriptor_set_out_dir produces an independent file per project/module pair. The flags are mutually exclusive and destinations are invocation-relative. --include_imports defaults to false and affects exports only. plugins[].with_imports also defaults to false but separately enables imported code generation for an individual plugin. options.go.package_prefix changes Go only; full managed mode requires explicit generate.managed.enabled: true.
-**Format variations:**
-- `owner/repo` - Latest commit from default branch
-- `owner/repo@v1.0.0` - Specific git tag
-- `owner/repo@47b927cbb41c4fdea1292baf` - Full commit hash
-- `github.com/owner/repo@version` - Full URL with version
-- `gitlab.com/group/repo@tag` - GitLab repository
+lint and breaking read the v1 easyp.yaml. They use the nearest module's declared roots and locked or local dependency roots for imports. A policy may exist without a protobuf.mod; in that case the commands use the scanned files and built-in imports.
-```yaml
-deps:
- # Latest commit from default branch
- - googleapis/googleapis
-
- # Specific tag (recommended for production)
- - googleapis/googleapis@v1.0.0
-
- # Full commit hash (most precise)
- - googleapis/googleapis@47b927cbb41c4fdea1292bafadb8976f
-
- # Different Git hosting
- - gitlab.com/acme/proto@v2.1.0
-```
+generate and ls-files also work without protobuf.mod when there are no module dependencies: the current project directory is treated as the source root.
-**Note:** If `@$VERSION` is omitted, EasyP downloads the latest commit from the repository's default branch.
+EasyP expands environment variables in easyp.yaml and easyp.gen.yaml before parsing or validation. ${NAME} uses the variable value, ${NAME:-default} supplies a fallback, and $${NAME} leaves a literal ${NAME}. An unset variable without a fallback becomes an empty string. YAML comments are ignored during expansion. protobuf.mod and protobuf.lock do not use this substitution.
-### `generate`
+For breaking, explicit --against overrides breaking.baseline, followed by the default master. Each revision uses its own roots, manifests, and locks; the baseline comes from an isolated Git snapshot. Policies come from current configuration and sections are inherited as a whole. The additional category FILE is supported; package-related and other categories are reserved and rejected. breaking.ignore_unstable defaults to false; its exact unstable suffix forms are in the [reference](/docs/reference/easyp-yaml#unstable-packages).
-**Optional.** Configures code generation from proto files.
+issues.exclude-rules.path is relative to the file supplying the issues section and supports *, ?, [], and complete ** segments. Literal directories cover their subtree. An empty rule {} explicitly ignores all files. linters.allow_comment_ignores defaults to true per policy. linters.extends and breaking.extends load section-scoped bases from bounded local paths or existing locked modules; see [shared policies](/docs/guides/organization-lint-style).
-**Type:** `object`
-**Default:** `{}`
+validate-config recursively checks every easyp.yaml, easyp.gen.yaml, protobuf.mod, and protobuf.lock below the current directory. Pass --cfg <file> to check one file or --cfg <directory> to scan another directory. JSON errors identify the file; YAML structure errors also include line and column. Invalid lock versions, incomplete entries, and malformed hashes are reported as validation errors.
-```yaml
-generate:
- inputs:
- - directory: "proto"
- - git_repo:
- url: "github.com/acme/common@v1.0.0"
- sub_directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
- - name: go-grpc
- out: .
- opts:
- paths: source_relative
- require_unimplemented_servers: false
-```
-
-#### `generate.inputs`
-
-**Required when `generate` is set.** Specifies sources of proto files for generation.
-
-**Type:** `[]object` (minimum 1 item)
-**Default:** not set
-
-```yaml
-generate:
- inputs:
- # Local directory
- - directory: "proto"
-
- # Local directory with advanced options
- - directory:
- path: "api/proto"
- root: "."
-
- # Remote git repository
- - git_repo:
- url: "github.com/acme/common@v1.0.0"
- sub_directory: "proto"
- root: "."
-```
-
-**Directory input fields:**
-- `directory` (string or object) - Local directory path
-- `directory.path` (string) - Directory path
-- `directory.root` (string) - Root path for import resolution (default: ".")
-
-**Git repository input fields:**
-- `git_repo.url` (string) - Repository URL with optional version
-- `git_repo.sub_directory` (string) - Subdirectory within the repository
-- `git_repo.root` (string) - Root path used for import resolution
-
-#### `generate.plugins`
-
-**Required when `generate` is set.** Configures protoc plugins for code generation.
-
-**Type:** `[]object` (minimum 1 item)
-**Default:** not set
-
-```yaml
-generate:
- plugins:
- # Local plugin
- - name: go
- out: .
- opts:
- paths: source_relative
-
- # Remote plugin
- - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0"
- out: gen/go
- opts:
- paths: source_relative
-
- # Plugin with import dependencies
- - name: grpc-gateway
- out: .
- with_imports: true
- opts:
- paths: source_relative
-```
-
-**Plugin fields:**
-- `name` (string, optional) - Plugin name (omit `protoc-gen-` prefix)
-- `remote` (string, optional) - Remote plugin URL for execution
-- `path` (string, optional) - Path to plugin executable file
-- `command` ([]string, optional) - Command to execute plugin
-- `out` (string, optional) - Output directory for generated files; defaults to the resolved generate root
-- `opts` (map[string](string | number | boolean | array<string | number | boolean>), optional) - Plugin-specific options; each key can be a single scalar value or an array of scalar values
-- `with_imports` (boolean, optional) - Include imported dependencies
-
-Plugin source is `one-of`: exactly one of `name`, `remote`, `path`, or `command` must be set.
-
-**Common plugin options:**
-```yaml
-# Go plugin options
-opts:
- paths: source_relative # Generate files relative to input
- module: github.com/acme/api # Go module path
-
-# gRPC Gateway options
-opts:
- paths: source_relative
- grpc_api_configuration: api.yaml # gRPC API configuration
-
-# OpenAPI v2 options
-opts:
- simple_operation_ids: true # Use simple operation IDs
- generate_unbound_methods: false # Skip unbound methods
-
-# ts-proto options with repeated key values
-opts:
- env: node
- outputServices:
- - grpc-js
- - generic-definitions
-```
-
-When an `opts` value is a list, EasyP serializes it as repeated plugin params, e.g. `outputServices=grpc-js,outputServices=generic-definitions`.
-
-### `breaking`
-
-**Optional.** Configures backward compatibility checking.
-
-**Type:** `object`
-**Default:** `{}`
-
-```yaml
-breaking:
- ignore:
- - proto/experimental/
- - proto/internal/
- against_git_ref: main
-```
-
-#### `breaking.ignore`
-
-**Optional.** Directories or files to exclude from breaking change detection.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-breaking:
- ignore:
- - proto/experimental/
- - proto/alpha/
- - testdata/
-```
-
-#### `breaking.against_git_ref`
-
-**Optional.** Git reference (branch, tag, or commit) to compare against for breaking changes.
+~~~bash
+easyp validate-config
+easyp validate-config --cfg ./services --format json
+easyp validate-config --cfg ./services/api/easyp.gen.yaml
+~~~
-**Type:** `string`
-**Default:** `""` (falls back to CLI `--against` default: `master`)
+mod vendor verifies the locked Git dependencies and copies their .proto files into easyp_vendor using their import paths. It replaces a previous vendor tree only after all files have been copied successfully. Duplicate import paths are errors. With local replace directives it copies the effective local and verified remote graph without changing the published lock.
-```yaml
-breaking:
- against_git_ref: main
-```
+ls-files lists local .proto files from protobuf.mod roots. By default it also includes reachable imports from dependencies and bundled well-known protos, resolving dependencies through the v1 lock or local replacements. Use --include-imports=false to list only local files; outside frozen mode this skips dependency resolution. JSON output contains files, roots, and any import errors.
-Can be overridden by the `--against` CLI flag.
+schema-gen --out-dir schemas writes separate JSON Schemas for easyp.yaml, easyp.gen.yaml, and protobuf.lock, each with a -v1.schema.json filename and an unversioned alias. protobuf.mod is a text manifest, so validate it with validate-config instead. CLI validation also checks semantic rules beyond the JSON Schemas.
+The exported github.com/easyp-tech/easyp/mcp/easypconfig package registers easyp_config_describe through easypconfig.RegisterTool(server). The tool describes easyp.yaml, easyp.gen.yaml, protobuf.lock and protobuf.mod. YAML references use the same JSON Schemas as schema-gen; the text manifest returns grammar instead of a fabricated YAML/JSON Schema.
+~~~json
+{"file":"protobuf.mod","path":"require[].version"}
+~~~
-## Configuration Examples
+~~~json
+{"file":"protobuf.lock","path":"modules[0].commit"}
+~~~
-### Minimal Configuration
+file is an exact format selector, not a path to read. Output includes format; YAML examples retain yaml, while manifest examples contain format: text and text. The grammar object describes text directives and block rules. All detail flags default to true; include_schema=false suppresses either the YAML schema or text grammar. examples_limit defaults to 10 and must be 1–50; invalid bounds are errors. The reference does not read project files, access the network, execute plugins or expand variables. Sample commit/hash values are synthetic, not verified repository contents.
-```yaml
-lint:
- use:
- - MINIMAL
-```
+## Minimal files
-### Development Configuration
+~~~text
+module github.com/acme/contracts
+roots proto
+require github.com/acme/shared v1.2.0
+~~~
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
- allow_comment_ignores: true
- ignore:
- - vendor/
- - testdata/
-deps:
- - github.com/googleapis/googleapis@v1.0.0
-generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
- - name: go-grpc
- out: .
- opts:
- paths: source_relative
-```
-
-### Production Configuration
-
-```yaml
-lint:
- use:
- - MINIMAL
- - BASIC
- - DEFAULT
- - COMMENTS
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
- ignore:
- - vendor/
- except: []
- allow_comment_ignores: false
-deps:
- - github.com/googleapis/googleapis@v1.56.0
- - github.com/grpc-ecosystem/grpc-gateway@v2.18.0
+~~~yaml
+# easyp.gen.yaml
+version: v1
generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- module: github.com/acme/api/gen/go
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
- - name: grpc-gateway
- out: gen/go
- opts:
- paths: source_relative
- - name: openapiv2
- out: gen/openapi
- opts:
- simple_operation_ids: true
+ modules: [github.com/acme/contracts]
+plugins:
+ - name: go
+ out: ./gen/go
+~~~
+
+~~~yaml
+# easyp.yaml
+version: v1
+linters:
+ default: STANDARD
breaking:
- ignore:
- - proto/experimental/
- against_git_ref: main
-```
-
-### Multi-Service Configuration
-
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
- service_suffix: "Service"
- ignore_only:
- COMMENT_FIELD:
- - proto/internal/
- SERVICE_SUFFIX:
- - proto/legacy/
-deps:
- - github.com/googleapis/googleapis@v1.0.0
- - github.com/acme/common-proto@v2.1.0
-generate:
- inputs:
- - directory: "proto/public"
- - directory: "proto/internal"
- - git_repo:
- url: "github.com/acme/shared-proto@v1.0.0"
- sub_directory: "proto"
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- - name: grpc-gateway
- out: gen/go
- opts:
- paths: source_relative
- - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0"
- out: gen/go
- opts:
- paths: source_relative
-breaking:
- ignore:
- - proto/internal/
- - proto/experimental/
- against_git_ref: develop
-```
-
-## Configuration Validation
-
-EasyP validates configuration files on startup and provides helpful error messages:
-
-```bash
-# Invalid rule name
-Error: invalid rule: INVALID_RULE_NAME
-
-# Missing required field in generate section
-Error: required field "plugins" is missing (path: generate.plugins)
-
-# Invalid dependency format
-Error: invalid dependency format: invalid-repo-url
-```
+ baseline: git:main
+~~~
-Use `easyp --debug` for detailed validation information.
+For the exact fields and current limits, use the linked reference pages above.
-## Migration from Buf
+## Errors and noninteractive use
-EasyP is fully compatible with Buf configurations. To migrate:
+ls-files prints its complete JSON or text result, then exits with a nonzero status when import traversal reported an error. A JSON errors array is not a successful build. --include-imports=false deliberately lists only local files; it is not an import-integrity check.
-1. Place `buf.yaml` or `buf.yml` in the project root
-2. Run `easyp init` and confirm migration when prompted
-3. Update `deps` format if using BSR modules
-4. Review migrated lint/breaking settings and adjust as needed
+init never opens a hidden controlling terminal behind redirected input or output. Supply --module when no identity can be read locally. An origin-based identity comes from the declared Git remote URL, before transport-only insteadOf rewriting. Overwriting a different existing configuration requires terminal confirmation; piped answers are not accepted.
-Most Buf configurations work without changes in EasyP.
+Policy syntax and supported setting names are checked by execution as well as validate-config. A nonempty breaking baseline must have the git: prefix. Lint groups checked files by effective policy and module while preserving per-file exclusions and diagnostic order.
diff --git a/content/docs/cli/configuration.ru.mdx b/content/docs/cli/configuration.ru.mdx
index 12d158c..9020cca 100644
--- a/content/docs/cli/configuration.ru.mdx
+++ b/content/docs/cli/configuration.ru.mdx
@@ -1,932 +1,140 @@
---
-title: "EasyP Configuration Reference"
+title: "Конфигурация EasyP v1 Pilot"
+description: "Файлы и команды CLI пилотной версии EasyP v1."
---
-EasyP can be configured through CLI flags, environment variables, and configuration files. This guide covers all configuration options available in EasyP.
+В пилотной версии v1 зависимости, генерация и правила проверки находятся в разных файлах:
-## CLI Flags
+| Файл | Назначение |
+|------|------------|
+| [protobuf.mod](/ru/docs/reference/protobuf-mod) | Имя модуля, корни исходников, зависимости и локальные замены |
+| [protobuf.lock](/ru/docs/reference/protobuf-lock) | Зафиксированные Git-коммиты и хеши содержимого; создаётся командой easyp mod tidy |
+| [easyp.gen.yaml](/ru/docs/reference/easyp-gen-yaml) | Модули для генерации, плагины, выходные каталоги и managed mode |
+| [easyp.yaml](/ru/docs/reference/easyp-yaml) | Правила линтинга и проверки совместимости |
-### Global Flags
+Команды CLI читают формат v1 напрямую и не переходят на старую логику генерации, линтинга, проверки совместимости или управления модулями. Зависимость в Git при этом может использовать старый формат EasyP или Buf: адаптер извлекает её требования и корни .proto для разрешения импортов.
-Available for all commands:
+Для интерактивного перехода с v0 выполните easyp migrate в терминале. Явный --interactive включает мастер с уже заданными параметрами, --interactive=false отключает его. Вызов с --module без включения мастера сохраняет прежний предварительный просмотр. См. [миграцию v0](/ru/docs/migration/easyp-v0).
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--cfg` | `-c` | `EASYP_CFG` | Configuration file path | `easyp.yaml` |
-| `--config` | | `EASYP_CFG` | Alias for `--cfg` | `easyp.yaml` |
-| `--debug` | `-d` | `EASYP_DEBUG` | Enable debug mode | `false` |
-| `--format` | `-f` | `EASYP_FORMAT` | Формат вывода для команд с поддержкой нескольких форматов (`text`/`json`) | значение по умолчанию зависит от команды |
+## Обычный порядок работы
-**Examples:**
-```bash
-# Use custom config file
-easyp --cfg production.easyp.yaml lint
-
-# Enable debug logging
-easyp --debug lint
-
-# Short form
-easyp -c custom.yaml -d lint
-```
-
-### Command-Specific Flags
-
-**Lint command:**
-```bash
-easyp lint [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--path` | `-p` | | Directory path to lint | `.` |
-| `--root` | `-r` | | Базовая директория для поиска файлов | Текущая рабочая директория |
-| `--format` | `-f` | `EASYP_FORMAT` | Использует глобальный флаг формата (`text`/`json`) | Использует глобальное значение по умолчанию |
-
-**Examples:**
-```bash
-# Lint specific directory
-easyp lint --path proto/
-
-# Lint из поддиректории с правильным разрешением импортов
-easyp lint --root src/IPC/Contracts --path .
-
-# JSON output format
-easyp --format json lint # глобальный флаг
-
-# Combined flags
-easyp -f json lint -p proto/
-```
-
-**Generate command:**
-```bash
-easyp generate [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--path` | `-p` | `EASYP_ROOT_GENERATE_PATH` | Путь к директории с proto файлами для генерации | `.` |
-| `--root` | `-r` | | Базовая директория для поиска файлов | Текущая рабочая директория |
-
-**Examples:**
-```bash
-# Generate from specific path
-easyp generate --path api/
-
-# Generate из поддиректории с правильным разрешением импортов
-easyp generate --root src/IPC/Contracts --path .
-
-# Using environment variable
-EASYP_ROOT_GENERATE_PATH=proto/ easyp generate
-```
-
-**Breaking command:**
-```bash
-easyp breaking [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--against` | | | Git ref to compare against | `master` |
-| `--path` | `-p` | | Directory path to check | `.` |
-| `--format` | `-f` | `EASYP_FORMAT` | Использует глобальный флаг формата (`text`/`json`) | Использует глобальное значение по умолчанию |
-
-**Examples:**
-```bash
-# Check against main branch
-easyp breaking --against main
-
-# Check specific directory against develop branch
-easyp breaking --against develop --path proto/
-
-# JSON output
-easyp --format json breaking --against main # глобальный флаг
-```
-
-**Init command:**
-```bash
-easyp init [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--dir` | `-d` | `EASYP_INIT_DIR` | Directory to initialize | `.` |
-
-**Examples:**
-```bash
-# Initialize current directory
-easyp init
-
-# Initialize specific directory
-easyp init --dir proto-project/
-```
-
-`easyp init` работает интерактивно:
-- Если в корне целевой директории есть `buf.yml`/`buf.yaml`, команда предложит миграцию из Buf.
-- Если `easyp.yaml` уже существует, команда запросит подтверждение на перезапись.
-
-**Validate-config command:**
-```bash
-easyp validate-config [flags]
-```
-
-| Flag | Short | Environment | Description | Default |
-|------|-------|-------------|-------------|---------|
-| `--config` | `-c` | `EASYP_CFG` | Путь до файла конфигурации | `easyp.yaml` |
-| `--format` (global) | `-f` | `EASYP_FORMAT` | Глобальный формат вывода для команд с несколькими форматами (`json` или `text`) | зависит от команды (`json` для `validate-config`) |
-
-**Examples:**
-```bash
-# Проверить конфиг по умолчанию с JSON выводом (статус 0 если ошибок нет)
-easyp validate-config
-
-# Проверить другой файл и вывести в текстовом формате (глобальный --format)
-easyp --format text validate-config --config example.easyp.yaml
-```
-
-**Package management commands:**
-
-#### `easyp mod download`
-Downloads dependencies based on lock file priority:
-
-1. **If `easyp.lock` exists** - downloads exact versions from lock file
-2. **If `easyp.lock` is missing** - downloads versions from `easyp.yaml` and creates `easyp.lock`
-
-```bash
-# Download exact versions (recommended for production)
+~~~bash
+easyp init --module github.com/acme/contracts
+easyp mod tidy
easyp mod download
-```
-
-#### `easyp mod update`
-Always downloads dependencies from `easyp.yaml`, ignoring existing lock file:
-
-1. **Ignores `easyp.lock`** completely
-2. **Downloads versions from `easyp.yaml`**
-3. **Creates/updates `easyp.lock`** with new versions
-
-```bash
-# Update dependencies and lock file
-easyp mod update
-```
-
-#### `easyp mod vendor`
-Copies proto files from dependencies to local `vendor/` directory (similar to `go mod vendor`).
-
-```bash
-# Create local vendor directory with dependencies
-easyp mod vendor
-```
-
-No additional flags. Uses global `--cfg` flag for configuration.
-
-## Environment Variables
-
-EasyP supports environment variables for configuration:
-
-| Variable | Description | Default |
-|----------|-------------|---------|
-| `EASYP_CFG` | Path to configuration file | `easyp.yaml` |
-| `EASYP_DEBUG` | Enable debug logging | `false` |
-| `EASYPPATH` | Cache and modules storage directory | `$HOME/.easyp` |
-| `EASYP_FORMAT` | Формат вывода для поддерживаемых команд (`text`/`json`). Если не указан, каждая команда использует своё значение по умолчанию. | значение по умолчанию зависит от команды |
-| `EASYP_ROOT_GENERATE_PATH` | Root path for generate command | `.` |
-| `EASYP_INIT_DIR` | Directory for init command | `.` |
-
-**Examples:**
-```bash
-# Custom cache directory
-export EASYPPATH=/tmp/easyp-cache
-easyp mod download
-
-# Debug mode via environment
-export EASYP_DEBUG=true
-easyp lint
-
-# Custom config file
-export EASYP_CFG=config/easyp.yaml
easyp generate
-```
-
-## Configuration File
-
-The `easyp.yaml` file is the main configuration file for EasyP, defining how your proto files are linted, generated, and managed. This file is typically placed at the root of your project alongside your proto files.
-
-### File Structure Overview
-
-```
-.
-├── easyp.yaml
-├── easyp.lock
-├── proto/
-│ ├── user/
-│ │ └── user.proto
-│ └── order/
-│ └── order.proto
-└── vendor/
-```
-
-### Configuration Format
-
-EasyP supports both YAML and JSON configuration formats:
-
-#### YAML Format (Recommended)
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
-deps:
- - github.com/googleapis/googleapis@v1.0.0
-generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
-breaking:
- ignore:
- - proto/experimental/
- against_git_ref: main
-```
-
-#### JSON Format
-```json
-{
- "lint": {
- "use": ["BASIC", "COMMENT_SERVICE"]
- },
- "deps": [
- "github.com/googleapis/googleapis@v1.0.0"
- ],
- "generate": {
- "inputs": [
- {"directory": "proto"}
- ],
- "plugins": [
- {
- "name": "go",
- "out": ".",
- "opts": {
- "paths": "source_relative"
- }
- }
- ]
- },
- "breaking": {
- "ignore": ["proto/experimental/"],
- "against_git_ref": "main"
- }
-}
-```
-
-### Переменные окружения в конфигурации
-
-EasyP поддерживает расширение переменных окружения непосредственно в файле конфигурации `easyp.yaml`. Это позволяет использовать переменные окружения для динамических значений конфигурации.
-
-**Пример со всеми поддерживаемыми возможностями:**
-```yaml
-deps:
- # Базовое расширение: ${VAR} - расширяется в значение переменной VAR
- - ${GOOGLEAPIS_REPO}@${GOOGLEAPIS_VERSION}
-
- # Значение по умолчанию: ${VAR:-default} - использует default, если VAR не установлена или пустая
- - ${GNOSTIC_REPO:-github.com/google/gnostic}@${GNOSTIC_VERSION:-v0.7.0}
+easyp lint --path proto
+easyp breaking --path proto --against main
+~~~
-generate:
- inputs:
- # Значение по умолчанию, если INPUT_DIR не установлена
- - directory: ${INPUT_DIR:-proto}
- plugins:
- - name: go
- # Базовое расширение
- out: ${OUTPUT_DIR}
- opts:
- # Значение по умолчанию
- module: ${MODULE_NAME:-github.com/example/project}
- timeout: ${TIMEOUT:-30}
-
- # Экранирование: $$ становится буквальным $, $${VAR} становится буквальным ${VAR}
- path: "${BASE_DIR}/$${TEMP}/file" # Результат: "/tmp/${TEMP}/file" (если BASE_DIR=/tmp)
- literal: "$$" # Результат: "$"
-```
-
-**Поддерживаемый синтаксис:**
-- `${VAR}` - расширяется в значение переменной `VAR`
-- `${VAR:-default}` - использует `default`, если `VAR` не установлена или пустая
-- `${VAR:=default}` - использует `default`, если `VAR` не установлена или пустая
-- `${VAR-default}` - использует `default`, если `VAR` не установлена (пустая строка сохраняется)
-- `$${VAR}` или `$$VAR` - экранирует в буквальную строку `${VAR}` или `$VAR`
-- `$$` - экранирует в буквальный символ `$`
-
-**Примечание:** Переменные окружения расширяются до парсинга YAML, поэтому любой паттерн `${STRING}` будет обработан. Используйте `$$` для экранирования символов доллара, когда нужны буквальные значения.
-
-## Configuration Fields
-
-### `version`
-
-**Опционально (legacy-совместимость).** Поле поддерживается для обратной совместимости и может быть опущено в новых конфигурациях.
-
-**Type:** `string`
-**Default:** не задано
-**Рекомендация:** если сохраняете поле, используйте `v1alpha`
-
-```yaml
-# Опциональное поле для совместимости (можно опустить)
-version: v1alpha
-```
-
-На поведение рантайма это поле не влияет.
-
-### `lint`
-
-**Optional.** Configures proto file linting rules and behavior.
-
-**Type:** `object`
-**Default:** Empty (no linting rules applied)
-
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
- ignore:
- - vendor/
- - proto/legacy/
- except:
- - COMMENT_FIELD
- allow_comment_ignores: true
- ignore_only:
- COMMENT_SERVICE:
- - proto/experimental/
-```
-
-#### `lint.use`
-
-**Optional.** Specifies which linter rules or rule categories to apply.
-
-**Type:** `[]string`
-**Default:** `[]` (no rules)
-
-**Available categories:**
-- `MINIMAL` - Essential package consistency checks
-- `BASIC` - Naming conventions and common patterns
-- `DEFAULT` - Additional recommended rules
-- `COMMENTS` - Comment requirements
-- `UNARY_RPC` - Streaming RPC restrictions
-
-**Individual rules:** Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`)
-
-```yaml
-lint:
- use:
- - MINIMAL # Use all minimal rules
- - BASIC # Use all basic rules
- - COMMENT_SERVICE # Require service comments
- - ENUM_PASCAL_CASE # Specific rule
-```
-
-**Rule Categories:**
-
-**MINIMAL:**
-- `DIRECTORY_SAME_PACKAGE`
-- `PACKAGE_DEFINED`
-- `PACKAGE_DIRECTORY_MATCH`
-- `PACKAGE_SAME_DIRECTORY`
-
-**BASIC:**
-- `ENUM_FIRST_VALUE_ZERO`
-- `ENUM_NO_ALLOW_ALIAS`
-- `ENUM_PASCAL_CASE`
-- `ENUM_VALUE_UPPER_SNAKE_CASE`
-- `FIELD_LOWER_SNAKE_CASE`
-- `IMPORT_NO_PUBLIC`
-- `IMPORT_NO_WEAK`
-- `IMPORT_USED`
-- `MESSAGE_PASCAL_CASE`
-- `ONEOF_LOWER_SNAKE_CASE`
-- `PACKAGE_LOWER_SNAKE_CASE`
-- `PACKAGE_SAME_CSHARP_NAMESPACE`
-- `PACKAGE_SAME_GO_PACKAGE`
-- `PACKAGE_SAME_JAVA_MULTIPLE_FILES`
-- `PACKAGE_SAME_JAVA_PACKAGE`
-- `PACKAGE_SAME_PHP_NAMESPACE`
-- `PACKAGE_SAME_RUBY_PACKAGE`
-- `PACKAGE_SAME_SWIFT_PREFIX`
-- `RPC_PASCAL_CASE`
-- `SERVICE_PASCAL_CASE`
-
-**DEFAULT:**
-- `ENUM_VALUE_PREFIX`
-- `ENUM_ZERO_VALUE_SUFFIX`
-- `FILE_LOWER_SNAKE_CASE`
-- `RPC_REQUEST_RESPONSE_UNIQUE`
-- `RPC_REQUEST_STANDARD_NAME`
-- `RPC_RESPONSE_STANDARD_NAME`
-- `PACKAGE_VERSION_SUFFIX`
-- `SERVICE_SUFFIX`
-
-**COMMENTS:**
-- `COMMENT_ENUM`
-- `COMMENT_ENUM_VALUE`
-- `COMMENT_FIELD`
-- `COMMENT_MESSAGE`
-- `COMMENT_ONEOF`
-- `COMMENT_RPC`
-- `COMMENT_SERVICE`
-
-**UNARY_RPC:**
-- `RPC_NO_CLIENT_STREAMING`
-- `RPC_NO_SERVER_STREAMING`
-
-#### `lint.enum_zero_value_suffix`
-
-**Optional.** Specifies the required suffix for enum zero values.
-
-**Type:** `string`
-**Default:** `""` (no suffix required)
-**Common values:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"`
-
-```yaml
-lint:
- enum_zero_value_suffix: "UNSPECIFIED"
-```
-
-This enforces enum zero values like:
-```proto
-enum Status {
- STATUS_UNSPECIFIED = 0; // Required suffix
- STATUS_ACTIVE = 1;
- STATUS_INACTIVE = 2;
-}
-```
-
-#### `lint.service_suffix`
-
-**Optional.** Specifies the required suffix for service names.
-
-**Type:** `string`
-**Default:** `""` (no suffix required)
-**Common values:** `"Service"`, `"API"`, `"Svc"`
-
-```yaml
-lint:
- service_suffix: "Service"
-```
-
-This enforces service names like:
-```proto
-service UserService { // Required "Service" suffix
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `lint.ignore`
-
-**Optional.** Directories or files to exclude from all linting rules.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-lint:
- ignore:
- - vendor/
- - proto/legacy/
- - testdata/
- - "**/*_test.proto"
-```
-
-Paths are relative to the `easyp.yaml` file location. Supports glob patterns.
-
-#### `lint.except`
-
-**Optional.** Disables specific rules globally across the entire project.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-lint:
- except:
- - COMMENT_FIELD
- - COMMENT_MESSAGE
- - SERVICE_SUFFIX
-```
-
-#### `lint.allow_comment_ignores`
-
-**Optional.** Enables inline comment-based rule ignoring within proto files.
-
-**Type:** `boolean`
-**Default:** `false`
-
-```yaml
-lint:
- allow_comment_ignores: true
-```
-
-When enabled, allows comments like:
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-service LegacyAPI {
- // nolint:COMMENT_RPC
- rpc GetData(...) returns (...);
-}
-```
+Без замен mod tidy записывает lock, mod download устанавливает зафиксированные коммиты, а mod update обновляет требования в пределах текущей мажорной версии и lock. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace).
-#### `lint.ignore_only`
+## Явный режим frozen
-**Optional.** Disables specific rules only for certain files or directories.
+Используйте --frozen, когда сборка должна опираться на сохранённый граф зависимостей. По умолчанию флаг выключен; CI=true его не включает. Каждому выбранному native-модулю, чей граф зависимостей используется, нужны protobuf.mod и protobuf.lock, в том числе пустой lock при отсутствии зависимостей. Явный путь от workspace в generate.modules использует манифест и lock выбранного модуля; каталогу только с easyp.gen.yaml отдельная пара не нужна. Выбор зависимости по идентификатору по-прежнему требует манифест и lock потребителя. Описанный ниже запуск исходников без манифеста доступен только без frozen.
-**Type:** `map[string][]string`
-**Default:** `{}`
+~~~bash
+easyp --frozen generate
+easyp lint --frozen --path proto
+easyp breaking --frozen --against main
+easyp mod --frozen download
+easyp mod vendor --frozen
+~~~
-```yaml
-lint:
- ignore_only:
- COMMENT_SERVICE:
- - proto/legacy/
- - vendor/
- SERVICE_SUFFIX:
- - proto/external/
-```
+Флаг принимается глобально перед командой; локально у generate, lint, breaking, ls-files, get, init и migrate; у родительской команды mod и каждой из четырёх её подкоманд. Значение true на любом уровне включает режим. Дочерний --frozen=false не отменяет true у родителя.
-**Key:** Rule name or category
-**Value:** Array of file paths or directories
+Frozen отклоняет все корневые replace, даже неиспользуемые, до обращения к путям замен или скачивания зависимостей. Проверяются прямые и транзитивные требования относительно lock и содержимое кеша. Режим не разрешает версии заново, не ищет HEAD/теги зависимостей и не записывает манифест или lock. Отсутствующий или устаревший lock вызывает ошибку. Точные коммиты из lock могут загружаться в кеш: frozen не означает автономную работу без сети.
-### `deps`
+mod tidy, get, mod update, init и migrate отклоняют запуск в frozen; предварительный просмотр и интерактивная миграция тоже запрещены. Подготовьте файлы вне frozen. Генерация проверяет все выбранные графы до запуска любого плагина. Lint сохраняет действующую область политик; breaking использует собственные манифест и lock базовой ревизии. Даже ls-files --include-imports=false проверяет frozen-граф. Подробнее — в [менеджере пакетов](/ru/docs/cli/package-manager).
-**Optional.** Lists external proto dependencies to download and manage.
+## Флаги команд
-**Type:** `[]string`
-**Default:** `[]`
+| Команда | Основные флаги |
+|---------|----------------|
+| generate | --project (повторяемый), --all, --workspace, --descriptor_set_out, --descriptor_set_out_dir, --include_imports |
+| lint | --path (-p), --root (-r) |
+| breaking | --path (-p), --root (-r), --against |
+| init | --dir (-d), --module |
+| validate-config | --config (псевдоним --cfg), --format |
+| mod download/tidy/vendor/update | --frozen |
+| ls-files | --include-imports (по умолчанию true), --format (json или text) |
+| schema-gen | --out-dir (по умолчанию schemas) |
-#### Dependency Format
+Общие флаги: --cfg (псевдоним --config, по умолчанию easyp.yaml), --debug (-d), --format (-f, text или json) и --frozen. Переменные EASYP_CFG, EASYP_DEBUG и EASYP_FORMAT задают значения по умолчанию. Кеш модулей находится в EASYPPATH или $HOME/.easyp.
-Dependencies follow the format: `$GIT_LINK@$VERSION`
+По умолчанию generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге workspace. --project можно повторять для нескольких явных потребителей. --all отдельно включает рекурсивный выбор внутри каталога запуска и несовместим с --project. --workspace задаёт границу для путей модулей и наследования; по умолчанию используется ближайший Git-репозиторий или охватывающие файлы EasyP. Модули и корни исходников берутся из protobuf.mod; generate.packages выбирает точные имена protobuf-пакетов среди выбранных модулей. Флагов generate --path и generate --root нет.
-**Components:**
-- `$GIT_LINK` - Git repository URL (GitHub, GitLab, etc.)
-- `$VERSION` - Git tag or full commit hash (optional)
+--descriptor_set_out объединяет совместимые графы в один файл; --descriptor_set_out_dir создаёт независимый файл для каждой пары проект/модуль. Флаги взаимоисключающие, пути считаются от каталога запуска. --include_imports по умолчанию равен false и влияет только на экспорт. plugins[].with_imports также по умолчанию равен false, но отдельно включает генерацию импортов для конкретного плагина. options.go.package_prefix меняет только Go; полный managed mode требует явного generate.managed.enabled: true.
-**Format variations:**
-- `owner/repo` - Latest commit from default branch
-- `owner/repo@v1.0.0` - Specific git tag
-- `owner/repo@47b927cbb41c4fdea1292baf` - Full commit hash
-- `github.com/owner/repo@version` - Full URL with version
-- `gitlab.com/group/repo@tag` - GitLab repository
+lint и breaking читают easyp.yaml версии v1. Для импортов они используют корни ближайшего модуля и его зафиксированных или локальных зависимостей. Политика может существовать без protobuf.mod; тогда используются проверяемые файлы и встроенные импорты.
-```yaml
-deps:
- # Latest commit from default branch
- - googleapis/googleapis
-
- # Specific tag (recommended for production)
- - googleapis/googleapis@v1.0.0
-
- # Full commit hash (most precise)
- - googleapis/googleapis@47b927cbb41c4fdea1292bafadb8976f
-
- # Different Git hosting
- - gitlab.com/acme/proto@v2.1.0
-```
+generate и ls-files тоже работают без protobuf.mod, если у проекта нет модульных зависимостей: текущий каталог проекта считается корнем исходников.
-**Note:** If `@$VERSION` is omitted, EasyP downloads the latest commit from the repository's default branch.
+Перед разбором и проверкой easyp.yaml и easyp.gen.yaml EasyP подставляет переменные окружения. ${NAME} берёт значение переменной, ${NAME:-default} задаёт запасное значение, а $${NAME} оставляет буквальную строку ${NAME}. Отсутствующая переменная без запасного значения превращается в пустую строку. Подстановки в комментариях YAML игнорируются. В protobuf.mod и protobuf.lock такой подстановки нет.
-### `generate`
+В breaking явный --against перекрывает breaking.baseline, затем применяется значение по умолчанию master. Каждая ревизия использует собственные корни, манифесты и lock; база читается из изолированного Git-снимка. Политики берутся из текущей конфигурации, секции наследуются целиком. Поддерживается дополнительная категория FILE; пакетные и другие категории зарезервированы и не принимаются. breaking.ignore_unstable по умолчанию равен false; точные формы нестабильных суффиксов описаны в [справочнике](/ru/docs/reference/easyp-yaml#нестабильные-пакеты).
-**Optional.** Configures code generation from proto files.
+Пути issues.exclude-rules.path считаются от файла, предоставляющего секцию issues, и поддерживают *, ?, [] и полные сегменты **. Буквальный каталог охватывает поддерево. Пустое правило {} явно исключает все файлы. linters.allow_comment_ignores по умолчанию равен true для каждой политики. linters.extends и breaking.extends подключают базы отдельных секций из локальных путей или существующих закреплённых модулей; см. [общие политики](/ru/docs/guides/organization-lint-style).
-**Type:** `object`
-**Default:** `{}`
+validate-config рекурсивно проверяет все easyp.yaml, easyp.gen.yaml, protobuf.mod и protobuf.lock внутри текущего каталога. Передайте --cfg <файл>, чтобы проверить один файл, или --cfg <каталог>, чтобы проверить другой каталог. В JSON-ошибках указан файл, а для ошибок структуры YAML — строка и столбец. Некорректная версия lock-файла, неполные записи и неверные хеши выдаются как ошибки проверки.
-```yaml
-generate:
- inputs:
- - directory: "proto"
- - git_repo:
- url: "github.com/acme/common@v1.0.0"
- sub_directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
- - name: go-grpc
- out: .
- opts:
- paths: source_relative
- require_unimplemented_servers: false
-```
-
-#### `generate.inputs`
-
-**Required when `generate` is set.** Specifies sources of proto files for generation.
-
-**Type:** `[]object` (minimum 1 item)
-**Default:** not set
-
-```yaml
-generate:
- inputs:
- # Local directory
- - directory: "proto"
-
- # Local directory with advanced options
- - directory:
- path: "api/proto"
- root: "."
-
- # Remote git repository
- - git_repo:
- url: "github.com/acme/common@v1.0.0"
- sub_directory: "proto"
- root: "."
-```
-
-**Directory input fields:**
-- `directory` (string or object) - Local directory path
-- `directory.path` (string) - Directory path
-- `directory.root` (string) - Root path for import resolution (default: ".")
-
-**Git repository input fields:**
-- `git_repo.url` (string) - Repository URL with optional version
-- `git_repo.sub_directory` (string) - Subdirectory within the repository
-- `git_repo.root` (string) - Root path used for import resolution
-
-#### `generate.plugins`
-
-**Required when `generate` is set.** Configures protoc plugins for code generation.
-
-**Type:** `[]object` (minimum 1 item)
-**Default:** not set
-
-```yaml
-generate:
- plugins:
- # Local plugin
- - name: go
- out: .
- opts:
- paths: source_relative
-
- # Remote plugin
- - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0"
- out: gen/go
- opts:
- paths: source_relative
-
- # Plugin with import dependencies
- - name: grpc-gateway
- out: .
- with_imports: true
- opts:
- paths: source_relative
-```
-
-**Plugin fields:**
-- `name` (string, optional) - Plugin name (omit `protoc-gen-` prefix)
-- `remote` (string, optional) - Remote plugin URL for execution
-- `path` (string, optional) - Path to plugin executable file
-- `command` ([]string, optional) - Command to execute plugin
-- `out` (string, optional) - Output directory for generated files; defaults to the resolved generate root
-- `opts` (map[string](string | number | boolean | array<string | number | boolean>), optional) - Plugin-specific options; each key can be a single scalar value or an array of scalar values
-- `with_imports` (boolean, optional) - Include imported dependencies
-
-Plugin source is `one-of`: exactly one of `name`, `remote`, `path`, or `command` must be set.
-
-**Common plugin options:**
-```yaml
-# Go plugin options
-opts:
- paths: source_relative # Generate files relative to input
- module: github.com/acme/api # Go module path
-
-# gRPC Gateway options
-opts:
- paths: source_relative
- grpc_api_configuration: api.yaml # gRPC API configuration
-
-# OpenAPI v2 options
-opts:
- simple_operation_ids: true # Use simple operation IDs
- generate_unbound_methods: false # Skip unbound methods
-
-# ts-proto options with repeated key values
-opts:
- env: node
- outputServices:
- - grpc-js
- - generic-definitions
-```
-
-When an `opts` value is a list, EasyP serializes it as repeated plugin params, e.g. `outputServices=grpc-js,outputServices=generic-definitions`.
-
-### `breaking`
-
-**Optional.** Configures backward compatibility checking.
-
-**Type:** `object`
-**Default:** `{}`
-
-```yaml
-breaking:
- ignore:
- - proto/experimental/
- - proto/internal/
- against_git_ref: main
-```
-
-#### `breaking.ignore`
-
-**Optional.** Directories or files to exclude from breaking change detection.
-
-**Type:** `[]string`
-**Default:** `[]`
-
-```yaml
-breaking:
- ignore:
- - proto/experimental/
- - proto/alpha/
- - testdata/
-```
-
-#### `breaking.against_git_ref`
-
-**Optional.** Git reference (branch, tag, or commit) to compare against for breaking changes.
+~~~bash
+easyp validate-config
+easyp validate-config --cfg ./services --format json
+easyp validate-config --cfg ./services/api/easyp.gen.yaml
+~~~
-**Type:** `string`
-**Default:** `""` (falls back to CLI `--against` default: `master`)
+mod vendor проверяет зафиксированные Git-зависимости и копирует их .proto в easyp_vendor по import path. Старый каталог заменяется только после успешного копирования всех файлов. Совпадающие import path вызывают ошибку. При наличии локальных replace копируется эффективный граф локальных и проверенных удалённых исходников без изменения опубликованного lock.
-```yaml
-breaking:
- against_git_ref: main
-```
+ls-files показывает локальные .proto из корней protobuf.mod. По умолчанию команда также включает достижимые импорты из зависимостей и встроенных well-known proto, разрешая зависимости через v1 lock или локальные замены. --include-imports=false показывает только локальные файлы; вне frozen это пропускает разрешение зависимостей. В JSON есть поля files, roots и, при проблемах с импортами, errors.
-Can be overridden by the `--against` CLI flag.
+schema-gen --out-dir schemas создаёт отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock: файлы с суффиксом -v1.schema.json и псевдонимы без версии. protobuf.mod — текстовый манифест; проверяйте его командой validate-config. CLI также проверяет семантические правила, не выраженные в JSON Schema.
+Экспортируемый пакет github.com/easyp-tech/easyp/mcp/easypconfig регистрирует easyp_config_describe через easypconfig.RegisterTool(server). Инструмент описывает easyp.yaml, easyp.gen.yaml, protobuf.lock и protobuf.mod. YAML-справка использует те же JSON Schema, что и schema-gen; для текстового manifest возвращается грамматика, а не вымышленная YAML/JSON Schema.
+~~~json
+{"file":"protobuf.mod","path":"require[].version"}
+~~~
-## Configuration Examples
+~~~json
+{"file":"protobuf.lock","path":"modules[0].commit"}
+~~~
-### Minimal Configuration
+file выбирает известный формат, а не путь для чтения. В ответе есть format; YAML-примеры сохраняют поле yaml, а примеры manifest содержат format: text и text. Объект grammar описывает директивы и правила блоков. Все флаги детализации по умолчанию включены; include_schema=false убирает YAML-схему или текстовую грамматику. examples_limit по умолчанию равен 10 и должен быть от 1 до 50; неверные границы вызывают ошибку. Справочник не читает файлы проекта, не обращается к сети, не запускает плагины и не раскрывает переменные. Commit и hash в примерах синтетические, а не проверенные данные репозитория.
-```yaml
-lint:
- use:
- - MINIMAL
-```
+## Минимальный пример
-### Development Configuration
+~~~text
+module github.com/acme/contracts
+roots proto
+require github.com/acme/shared v1.2.0
+~~~
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
- allow_comment_ignores: true
- ignore:
- - vendor/
- - testdata/
-deps:
- - github.com/googleapis/googleapis@v1.0.0
-generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: .
- opts:
- paths: source_relative
- - name: go-grpc
- out: .
- opts:
- paths: source_relative
-```
-
-### Production Configuration
-
-```yaml
-lint:
- use:
- - MINIMAL
- - BASIC
- - DEFAULT
- - COMMENTS
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
- ignore:
- - vendor/
- except: []
- allow_comment_ignores: false
-deps:
- - github.com/googleapis/googleapis@v1.56.0
- - github.com/grpc-ecosystem/grpc-gateway@v2.18.0
+~~~yaml
+# easyp.gen.yaml
+version: v1
generate:
- inputs:
- - directory: "proto"
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- module: github.com/acme/api/gen/go
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
- - name: grpc-gateway
- out: gen/go
- opts:
- paths: source_relative
- - name: openapiv2
- out: gen/openapi
- opts:
- simple_operation_ids: true
+ modules: [github.com/acme/contracts]
+plugins:
+ - name: go
+ out: ./gen/go
+~~~
+
+~~~yaml
+# easyp.yaml
+version: v1
+linters:
+ default: STANDARD
breaking:
- ignore:
- - proto/experimental/
- against_git_ref: main
-```
-
-### Multi-Service Configuration
-
-```yaml
-lint:
- use:
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
- service_suffix: "Service"
- ignore_only:
- COMMENT_FIELD:
- - proto/internal/
- SERVICE_SUFFIX:
- - proto/legacy/
-deps:
- - github.com/googleapis/googleapis@v1.0.0
- - github.com/acme/common-proto@v2.1.0
-generate:
- inputs:
- - directory: "proto/public"
- - directory: "proto/internal"
- - git_repo:
- url: "github.com/acme/shared-proto@v1.0.0"
- sub_directory: "proto"
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- - name: grpc-gateway
- out: gen/go
- opts:
- paths: source_relative
- - remote: "buf.build/bufbuild/protovalidate-go:v0.4.0"
- out: gen/go
- opts:
- paths: source_relative
-breaking:
- ignore:
- - proto/internal/
- - proto/experimental/
- against_git_ref: develop
-```
-
-## Configuration Validation
-
-EasyP validates configuration files on startup and provides helpful error messages:
-
-```bash
-# Invalid rule name
-Error: invalid rule: INVALID_RULE_NAME
-
-# Missing required field in generate section
-Error: required field "plugins" is missing (path: generate.plugins)
-
-# Invalid dependency format
-Error: invalid dependency format: invalid-repo-url
-```
+ baseline: git:main
+~~~
-Use `easyp --debug` for detailed validation information.
+Точные поля и текущие ограничения описаны в справочниках по ссылкам выше.
-## Migration from Buf
+## Ошибки и неинтерактивный запуск
-EasyP is fully compatible with Buf configurations. To migrate:
+ls-files сначала выводит полный JSON или текстовый результат, затем возвращает ненулевой код, если при обходе импортов обнаружена ошибка. Наличие массива errors не означает успешную проверку. --include-imports=false намеренно перечисляет только локальные файлы и не проверяет целостность импортов.
-1. Place `buf.yaml` or `buf.yml` in the project root
-2. Run `easyp init` and confirm migration when prompted
-3. Update `deps` format if using BSR modules
-4. Review migrated lint/breaking settings and adjust as needed
+init не открывает скрытый управляющий терминал при перенаправленных вводе или выводе. Укажите --module, если идентификатор невозможно получить локально. Идентификатор по origin берётся из объявленного Git URL до транспортной подстановки insteadOf. Перезапись отличающегося существующего конфига требует подтверждения в терминале; ответ из pipe не принимается.
-Most Buf configurations work without changes in EasyP.
+Синтаксис политики и поддерживаемые настройки проверяются и при исполнении команды, и в validate-config. Непустой breaking baseline должен начинаться с git:. Lint группирует файлы по действующей политике и модулю, сохраняя исключения отдельных файлов и порядок диагностики.
diff --git a/content/docs/cli/generator/examples/go.mdx b/content/docs/cli/generator/examples/go.mdx
index 62bf134..bdd9336 100644
--- a/content/docs/cli/generator/examples/go.mdx
+++ b/content/docs/cli/generator/examples/go.mdx
@@ -1,147 +1,34 @@
---
-title: "Go"
+title: "Generate Go code"
+description: "A minimal EasyP v1 generator using Go plugins."
---
-## Installing Plugins
+Declare the source root in `protobuf.mod`:
-First, install the necessary plugins for working with gRPC:
-
-```shell
-go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
-go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
+```text
+module github.com/acme/contracts
+roots proto
```
-These commands will install the `protoc-gen-go` and `protoc-gen-go-grpc` plugins for use with EasyP.
-
-## Example Proto Service
-
-Here is an example proto file for an Echo service:
-
-```proto
-syntax = "proto3";
-
-package api.echo.v1;
-
-option go_package = "github.com/easyp-tech/example/api/echo/v1;pb";
-
-service EchoAPI {
- rpc Echo(EchoRequest) returns (EchoResponse);
- rpc EchoStream(EchoStreamRequest) returns (EchoResponse);
-}
-
-message EchoRequest {
- string payload = 1;
-}
-
-message EchoResponse {
- string payload = 2;
-}
-
-message EchoStreamRequest {
- string payload = 1;
-}
-
-message EchoStreamResponse {
- string payload = 2;
-}
+Select that module and the plugins in `easyp.gen.yaml`:
+
+```yaml
+version: v1
+generate:
+ modules: [github.com/acme/contracts]
+plugins:
+ - name: go
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ - name: go-grpc
+ out: ./gen/go
+ opts:
+ paths: source_relative
```
-## Configuration Setup
-
-Compare generator configurations across formats:
-
-easyp generate selects the closest easyp.gen.yaml in the current directory or an ancestor within the workspace. It compiles the selected modules and runs that project's plugins. Module identities, roots, and dependency versions come from protobuf.mod and protobuf.lock.
+
+## Configure a module
+
+~~~text
+# protobuf.mod
+module github.com/acme/contracts
+roots proto
+require github.com/acme/shared v1.2.0
+~~~
+
+~~~yaml
+# easyp.gen.yaml
+version: v1
+plugins:
+ - name: go
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ - name: go-grpc
+ out: ./gen/go
+ opts:
+ paths: source_relative
+options:
+ go:
+ package_prefix: github.com/acme/contracts/gen/go
+~~~
+
+~~~bash
+easyp mod tidy
+easyp generate
+~~~
+
+If generate.modules is omitted, EasyP selects the nearest protobuf.mod beside or above the generator file within the workspace; without a manifest, the project directory is the source root. Explicit entries select local module identities, workspace-relative module paths, or dependencies resolved through the consumer manifest and lock. generate.packages optionally selects exact protobuf package names; empty selects all module sources.
+
+## Select projects
+
+~~~bash
+# Closest project only
+easyp generate
+# Exactly these two projects
+easyp generate --project backend --project frontend
+# Explicit recursive selection beneath the invocation directory
+easyp generate --all
+# Explicit workspace boundary, useful in a non-Git tree
+easyp generate --workspace ../.. --project ..
+~~~
+
+--project is repeatable and cannot be combined with --all. Recursive discovery skips hidden directories, easyp_vendor, node_modules, and nested Git repositories. Select a project in a skipped directory explicitly. Automatic selection rejects a symlink configuration file; an explicit project selection is required to use it. Choosing --all authorizes plugins in the discovered projects, including command plugins.
+
+The nearest Git repository, including a worktree with a .git file, supplies the workspace boundary. Without Git, enclosing EasyP configuration and manifest files establish the boundary; --workspace sets it explicitly. Project paths and descriptor destinations are relative to the invocation directory. Plugin output paths are relative to their easyp.gen.yaml. The command has no --path or --root flag.
+
+## Frozen generation
+
+~~~bash
+easyp generate --frozen --project backend --project frontend
+easyp --frozen generate --all --descriptor_set_out_dir build/descriptors
+~~~
+
+Each selected local native module must have protobuf.mod and protobuf.lock, including an empty lock without dependencies. An explicit workspace-relative path uses the selected module's files: backend/easyp.gen.yaml with generate.modules: [proto/user] validates proto/user/protobuf.mod and proto/user/protobuf.lock. The generator-only backend directory needs neither file. Frozen rejects all root replacements, even unused ones, and validates the locked direct and transitive graph before any plugin executes. A failure in a later selected project therefore prevents plugins in earlier projects from running. The same preflight applies to both descriptor export modes and pluginless exports.
+
+A dependency selected by identity through generate.modules requires its consumer's manifest and lock; the downloaded dependency does not need its own lock. Unselected projects are ignored. --frozen does not change the existing --project/--all selection and plugin authorization rules.
+
+Exact locked commits may be downloaded into the cache and are hash-verified, including on cache reuse. Manifest and lock files are never rewritten, and dependency HEAD/tags are never resolved. Frozen is explicit, not inferred from CI, and does not make remote plugins offline or pin local plugin executables. See [frozen builds](/docs/cli/package-manager#frozen-builds).
+
+## Export descriptors
+
+~~~bash
+easyp generate --project backend --descriptor_set_out build/backend.pb --include_imports
+easyp generate --all --descriptor_set_out_dir build/descriptors --include_imports
+~~~
+
+--descriptor_set_out combines the selected graphs into one binary FileDescriptorSet. Identical descriptors are deduplicated; conflicting definitions under one import path or conflicting symbols cause an error. Managed options remain part of compatibility checks.
+
+--descriptor_set_out_dir writes an independent descriptor set for each selected project/module pair, so different consumers can retain different options or dependency versions. Project paths are mirrored below the destination; filenames contain a sanitized module basename and the first 12 hex digits of the full module identity's SHA-256. External projects use an _external namespace. Existing unrelated files are retained.
+
+The two destination flags are mutually exclusive. --include_imports defaults to false and includes transitive imports in exported files only. Compilation and compatibility validation always use the complete graph.
+
+All requested graphs and export destinations pass preflight before any plugin runs. Configured plugins still run; a pluginless project can also export descriptors. Descriptor files are written after all selected plugin executions succeed, with atomic replacement per file. This does not provide a transaction across arbitrary plugin side effects or filesystem failures.
+
+## Plugins and managed options
+
+Each plugin sets exactly one source: name, path, command, or remote. Local binaries and commands run from the invocation directory. Remote plugins require a pinned semantic version; local and bundled plugins reject a separate version field.
+
+Bundled names such as go and go-grpc use a matching protoc-gen-* on PATH when available, otherwise their bundled WASM plugin.
+
+plugins[].with_imports defaults to false. Set it to true for a particular plugin to generate code for transitive imports as well as the selected files. Other plugins still receive dependency descriptors for linking. This setting is independent of descriptor export's --include_imports. Keep Go import paths and output directories aligned: different Go packages must not share one generated directory. Identical shared outputs are deduplicated; conflicting file contents or Go package declarations fail before generated files are written.
+
+options.go.package_prefix changes Go options only. Defaults for other languages and field-option transformations require explicit generate.managed.enabled: true. An inherited Go prefix precedes explicit managed Go overrides; a prefix in the current file has the highest priority. Go disable selectors still apply. See the full [configuration reference](/docs/reference/easyp-gen-yaml).
+
+A plain prefix maps a multi-component protobuf package such as common.v1 to <prefix>/common/v1. With explicit paths: source_relative, Go output directories follow the plugin's effective import path under that prefix, including its Mfile.proto mappings. Insertion-point outputs follow the producer's output file. See [Go output paths and plugin mappings](/docs/reference/easyp-gen-yaml#go-output-paths-and-plugin-mappings) for marker templates and precedence.
+
+Dependency repositories may use v1 EasyP, older EasyP, Buf v1, or Buf v2 metadata. EasyP reads dependency metadata without executing dependency plugins. Buf source includes/excludes also apply when selecting a dependency or its packages for generation; excluded files cannot be reintroduced as imports. See [dependency metadata and filters](/docs/cli/package-manager#dependencies-using-buf-or-older-easyp).
diff --git a/content/docs/cli/generator/index.ru.mdx b/content/docs/cli/generator/index.ru.mdx
index 3007b74..02ed54e 100644
--- a/content/docs/cli/generator/index.ru.mdx
+++ b/content/docs/cli/generator/index.ru.mdx
@@ -1,136 +1,98 @@
---
title: "Генератор"
+description: "Выбор проектов-потребителей, генерация protobuf-кода и экспорт дескрипторов в EasyP v1."
---
-EasyP включает мощный генератор, который упрощает процесс получения кода из proto‑файлов. Благодаря YAML‑конфигурациям работа становится гораздо более удобной и интуитивной по сравнению с прямым использованием команды protoc.
-
-## Ключевые особенности генератора
-
-1. **Упрощённая генерация кода**:
- - Генерация кода из proto через декларативную `YAML`‑конфигурацию.
- - Избавляет от необходимости писать длинные и сложные команды protoc.
-
-2. **Обёртка над protoc**:
- - EasyP выступает как удобный слой над protoc, предоставляя декларативный API.
- - Поддерживает все опции и плагины, доступные protoc.
-
-3. **Гибкость и кастомизация**:
- - Используются те же параметры, что и у плагинов protoc, прямо в конфиге.
- - Поддерживается множество плагинов и их параметры в одной конфигурации.
-
-4. **Генерация из нескольких источников**:
- - Локальные директории и удалённые Git‑репозитории одновременно.
- - Лёгкая интеграция с существующими проектами и репозиториями.
-
-5. **Удалённая генерация**:
- - Генерация из удалённых Git репозиториев без локального checkout.
-
-6. **Интеграция с менеджером пакетов**:
- - Прозрачная работа с зависимостями через пакетный менеджер EasyP.
- - Автоматическое разрешение и подключение proto‑зависимостей.
-
-## Справочник конфигурации
-
-### Сравнение конфигураций генератора
-
-easyp generate выбирает ближайший easyp.gen.yaml в текущем или родительском каталоге в пределах workspace. Команда компилирует выбранные модули и запускает плагины этого проекта. Имена модулей, корни исходников и версии зависимостей берутся из protobuf.mod и protobuf.lock.
+
+## Настройка модуля
+
+~~~text
+# protobuf.mod
+module github.com/acme/contracts
+roots proto
+require github.com/acme/shared v1.2.0
+~~~
+
+~~~yaml
+# easyp.gen.yaml
+version: v1
+plugins:
+ - name: go
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ - name: go-grpc
+ out: ./gen/go
+ opts:
+ paths: source_relative
+options:
+ go:
+ package_prefix: github.com/acme/contracts/gen/go
+~~~
+
+~~~bash
+easyp mod tidy
+easyp generate
+~~~
+
+Если generate.modules не указан, EasyP выбирает ближайший protobuf.mod рядом с файлом генератора или выше в пределах workspace; без манифеста корнем исходников становится каталог проекта. Явные элементы выбирают локальный модуль по имени, путь относительно workspace или зависимость из манифеста и lock потребителя. generate.packages выбирает точные имена protobuf-пакетов; пустой список означает все исходники модуля.
+
+## Выбор проектов
+
+~~~bash
+# Только ближайший проект
+easyp generate
+# Ровно два указанных проекта
+easyp generate --project backend --project frontend
+# Явный рекурсивный выбор внутри каталога запуска
+easyp generate --all
+# Явная граница workspace, полезная вне Git
+easyp generate --workspace ../.. --project ..
+~~~
+
+--project можно повторять, но нельзя сочетать с --all. Рекурсивный поиск пропускает скрытые каталоги, easyp_vendor, node_modules и вложенные Git-репозитории. Проект в пропускаемом каталоге можно выбрать явно. Автоматический выбор отклоняет конфигурацию-симлинк; для неё нужен явный выбор проекта. Флаг --all разрешает запуск плагинов найденных проектов, включая command-плагины.
+
+Границу workspace задаёт ближайший Git-репозиторий, включая worktree с файлом .git. Без Git граница определяется по охватывающим конфигам и манифестам EasyP; --workspace задаёт её явно. Пути проектов и дескрипторов считаются от каталога запуска. Пути результатов плагинов считаются от их easyp.gen.yaml. Флагов --path и --root у команды нет.
+
+## Генерация в режиме frozen
+
+~~~bash
+easyp generate --frozen --project backend --project frontend
+easyp --frozen generate --all --descriptor_set_out_dir build/descriptors
+~~~
+
+Каждому выбранному локальному native-модулю нужны protobuf.mod и protobuf.lock, в том числе пустой lock без зависимостей. Явный путь от workspace использует файлы выбранного модуля: backend/easyp.gen.yaml с generate.modules: [proto/user] проверяет proto/user/protobuf.mod и proto/user/protobuf.lock. Самому каталогу backend, содержащему только настройки генератора, эти файлы не нужны. Frozen отклоняет все корневые замены, даже неиспользуемые, и проверяет зафиксированный граф прямых и транзитивных зависимостей до запуска любого плагина. Ошибка в проекте, выбранном позже, поэтому не даст запустить плагины более ранних проектов. Проверка действует для обоих режимов экспорта дескрипторов, включая экспорт без плагинов.
+
+Зависимость, выбранная по идентификатору через generate.modules, требует манифест и lock потребителя; собственный lock в скачанной зависимости не требуется. Невыбранные проекты игнорируются. --frozen не меняет существующие правила выбора и разрешения запуска плагинов через --project/--all.
+
+Точные коммиты из lock могут скачиваться в кеш; хеши проверяются и при повторном использовании кеша. Манифест и lock никогда не переписываются, HEAD/теги зависимостей не разрешаются. Frozen включается явно, а не по окружению CI; он не отключает сеть удалённым плагинам и не фиксирует локальные исполняемые файлы плагинов. Подробнее — в [менеджере пакетов](/ru/docs/cli/package-manager).
+
+## Экспорт дескрипторов
+
+~~~bash
+easyp generate --project backend --descriptor_set_out build/backend.pb --include_imports
+easyp generate --all --descriptor_set_out_dir build/descriptors --include_imports
+~~~
+
+--descriptor_set_out объединяет выбранные графы в один бинарный FileDescriptorSet. Одинаковые дескрипторы объединяются; разные определения под одним import path или конфликтующие символы вызывают ошибку. Managed-опции участвуют в проверке совместимости.
+
+--descriptor_set_out_dir записывает отдельный набор для каждой выбранной пары проект/модуль, позволяя потребителям сохранять разные опции и версии зависимостей. Пути проектов повторяются внутри каталога назначения; имя файла содержит безопасное имя модуля и первые 12 hex-символов SHA-256 его полного идентификатора. Внешние проекты размещаются в _external. Посторонние существующие файлы сохраняются.
+
+Флаги назначения взаимоисключающие. --include_imports по умолчанию равен false и добавляет транзитивные импорты только в экспортируемые файлы. Компиляция и проверка совместимости всегда используют полный граф.
+
+Все выбранные графы и пути экспорта проверяются до запуска плагинов. Настроенные плагины всё равно запускаются; проект без плагинов тоже может экспортировать дескрипторы. Дескрипторы записываются после успешного выполнения всех выбранных плагинов с атомарной заменой каждого файла. Общей транзакции для побочных эффектов плагинов и ошибок файловой системы нет.
+
+## Плагины и managed mode
+
+Каждый плагин задаёт ровно один источник: name, path, command или remote. Локальные бинарные файлы и команды запускаются из каталога вызова EasyP. Удалённому плагину нужен зафиксированный SemVer в version; локальные и встроенные плагины отдельную версию не принимают.
+
+Встроенные имена вроде go и go-grpc используют соответствующий protoc-gen-* из PATH, если он доступен; иначе запускается встроенный WASM-плагин.
+
+plugins[].with_imports по умолчанию равен false. Значение true включает генерацию транзитивных импортов только для этого плагина. Остальные плагины по-прежнему получают дескрипторы зависимостей для связывания. Настройка независима от --include_imports при экспорте дескрипторов. Согласуйте Go import path и выходные каталоги: разные Go-пакеты не должны попадать в один каталог. Одинаковые общие результаты объединяются; конфликт содержимого файлов или объявлений Go-пакетов обнаруживается до записи сгенерированных файлов.
+
+options.go.package_prefix меняет только Go-опции. Значения по умолчанию для других языков и преобразования опций полей требуют явного generate.managed.enabled: true. Унаследованный Go-префикс применяется до явных managed-переопределений Go; префикс текущего файла имеет наивысший приоритет. Go-селекторы disable продолжают действовать. Подробнее — в [справочнике конфигурации](/ru/docs/reference/easyp-gen-yaml).
+
+Обычный префикс отображает protobuf-пакет из нескольких компонентов, например common.v1, в <prefix>/common/v1. С явным paths: source_relative выходные каталоги Go следуют эффективному import path плагина под этим префиксом, включая его параметры Mfile.proto. Результаты с insertion point следуют выходному файлу создавшего его плагина. Шаблоны и приоритеты описаны в [справочнике выходных путей Go](/ru/docs/reference/easyp-gen-yaml#выходные-пути-go-и-параметры-m).
+
+Зависимости могут использовать метаданные EasyP v1, старого EasyP, Buf v1 или Buf v2. EasyP читает метаданные зависимостей, не запуская их плагины. Buf includes/excludes действуют и при выборе зависимости или её пакетов для генерации; исключённые файлы нельзя вернуть через импорты. См. [метаданные и фильтры зависимостей](/ru/docs/cli/package-manager#зависимости-на-buf-или-старом-easyp).
diff --git a/content/docs/cli/index.mdx b/content/docs/cli/index.mdx
index 5ce91e9..c1f248c 100644
--- a/content/docs/cli/index.mdx
+++ b/content/docs/cli/index.mdx
@@ -12,6 +12,10 @@ The EasyP CLI is the local toolkit for Protocol Buffers workflows.
| `easyp generate` | Run local/remote plugins |
| `easyp mod` | Git-based dependencies |
| `easyp init` | Project bootstrap |
+| `easyp validate-config` | Recursively validate v1 configuration and module files |
+| `easyp ls-files` | List local protos and reachable imports |
+| `easyp schema-gen` | Generate v1 JSON Schemas |
+| `easyp completion bash\|zsh` | Print a shell completion script |
## Sections
diff --git a/content/docs/cli/index.ru.mdx b/content/docs/cli/index.ru.mdx
index d022083..696300a 100644
--- a/content/docs/cli/index.ru.mdx
+++ b/content/docs/cli/index.ru.mdx
@@ -12,6 +12,10 @@ CLI EasyP — локальный инструментарий для Protocol Bu
| `easyp generate` | Локальные/удалённые плагины |
| `easyp mod` | Git-зависимости |
| `easyp init` | Инициализация проекта |
+| `easyp validate-config` | Рекурсивная проверка конфигурации и модульных файлов v1 |
+| `easyp ls-files` | Список локальных proto и достижимых импортов |
+| `easyp schema-gen` | Генерация JSON Schema для v1 |
+| `easyp completion bash\|zsh` | Вывод скрипта автодополнения |
## Разделы
diff --git a/content/docs/cli/linter/index.mdx b/content/docs/cli/linter/index.mdx
index b993cfa..9879f2c 100644
--- a/content/docs/cli/linter/index.mdx
+++ b/content/docs/cli/linter/index.mdx
@@ -1,420 +1,67 @@
---
title: "Linter"
+description: "Configure and run the EasyP v1 protobuf linter."
---
-[[toc]]
+easyp lint checks .proto files using the v1 policy in easyp.yaml, reporting source locations and rule names.
-## Why Use a Linter for Proto Files?
-
-Linters play a crucial role in modern software development, particularly for proto files. By enforcing style and formatting rules, linters help maintain code quality, reduce potential bugs, and ensure that the codebase is clean and readable. This leads to several benefits:
-
-- **Reduced Development Costs:** Linters catch errors early in the development cycle, saving time and resources that would be spent on debugging and fixing issues later.
-- **Improved Team Collaboration:** A standardized codebase makes it easier for team members to understand and work with each other's code, facilitating a smoother collaborative environment.
-- **Business Efficiency:** Teams using linters often produce higher quality code, which translates to fewer production issues and maintenance costs. This makes businesses that adopt linting practices more competitive and cost-effective.
-
-## Configuration Reference
-
-EasyP linter provides flexible configuration options to adapt to different project requirements. All configuration is done through the `lint` section in your `easyp.yaml` file.
-
-### Complete Configuration Example
-
-```yaml
-lint:
- # Rules and categories to use
- use:
- - MINIMAL
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
-
- # Custom suffixes for naming conventions
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
-
- # Directory and rule exclusions
- ignore:
- - "vendor/"
- - "third_party/"
- - "legacy/old_protos/"
-
- except:
- - COMMENT_FIELD
- - COMMENT_MESSAGE
-
- # Comment-based rule ignoring
+~~~yaml
+version: v1
+linters:
+ default: STANDARD
+ enable: [COMMENT_SERVICE]
+ disable: [SERVICE_SUFFIX]
allow_comment_ignores: true
-
- # File-specific rule ignoring
- ignore_only:
- COMMENT_SERVICE: ["legacy/", "vendor/"]
- SERVICE_SUFFIX: ["proto/external/"]
-```
-
-### Configuration Parameters
-
-#### `use` ([]string)
-Specifies which linter rules or rule categories to apply. You can mix individual rules with predefined categories.
-
-**Available categories:**
-- **MINIMAL**: Basic package consistency checks
-- **BASIC**: Naming conventions and usage patterns
-- **DEFAULT**: Recommended rules for most projects
-- **COMMENTS**: Comment presence and formatting
-- **UNARY_RPC**: Restrictions on streaming RPCs
-
-**Individual rules**: Any specific rule name (e.g., `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`)
-
-**Examples:**
-```yaml
-# Use predefined categories
-use: [MINIMAL, BASIC, DEFAULT]
-
-# Mix categories with individual rules
-use:
- - MINIMAL
- - COMMENT_SERVICE
- - COMMENT_RPC
- - ENUM_PASCAL_CASE
-
-# Use only specific rules
-use:
- - PACKAGE_DEFINED
- - SERVICE_PASCAL_CASE
- - FIELD_LOWER_SNAKE_CASE
-```
-
-#### `enum_zero_value_suffix` (string)
-Defines the required suffix for zero-value enum entries. This enforces a consistent naming pattern for the default enum value.
-
-**Default**: Empty (no suffix required)
-**Common values**: `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"`
-
-**Example:**
-```yaml
-enum_zero_value_suffix: "UNSPECIFIED"
-```
-
-With this setting, enum definitions must follow this pattern:
-```proto
-enum Status {
- STATUS_UNSPECIFIED = 0; // Required suffix
- STATUS_ACTIVE = 1;
- STATUS_INACTIVE = 2;
-}
-```
-
-#### `service_suffix` (string)
-Specifies the required suffix for service names. This ensures consistent service naming across your project.
-
-**Default**: Empty (no suffix required)
-**Common values**: `"Service"`, `"API"`, `"Svc"`
-
-**Example:**
-```yaml
-service_suffix: "Service"
-```
-
-With this setting, service definitions must follow this pattern:
-```proto
-service UserService { // Required "Service" suffix
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `ignore` ([]string)
-Lists directories or file paths to completely exclude from linting. Supports glob patterns and relative paths from the project root.
-
-**Use cases:**
-- Third-party or vendor proto files
-- Generated proto files
-- Legacy code being phased out
-- Test fixtures that intentionally violate rules
-
-**Examples:**
-```yaml
-ignore:
- - "vendor/" # Exclude vendor directory
- - "third_party/" # Exclude third-party protos
- - "testdata/" # Exclude test fixtures
- - "proto/legacy/" # Exclude legacy protos
- - "**/*_test.proto" # Exclude test proto files
-```
-
-#### `except` ([]string)
-Disables specific rules globally across the entire project. Use this when certain rules don't fit your project's conventions.
-
-**When to use:**
-- Legacy projects with established naming conventions
-- Projects with specific style requirements
-- Gradual adoption of linting rules
-
-**Examples:**
-```yaml
-except:
- - COMMENT_FIELD # Don't require field comments
- - COMMENT_MESSAGE # Don't require message comments
- - SERVICE_SUFFIX # Don't enforce service suffix
- - ENUM_ZERO_VALUE_SUFFIX # Don't enforce enum zero suffix
-```
-
-#### `allow_comment_ignores` (bool)
-Enables or disables the ability to ignore specific rules using inline comments in proto files.
-
-**Default**: `false`
-**Recommended**: `true` for flexibility during development
-
-**Example:**
-```yaml
-allow_comment_ignores: true
-```
-
-When enabled, you can use comments to ignore rules on specific elements:
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-service LegacyUserAPI {
- // nolint:COMMENT_RPC
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `ignore_only` (map[string][]string)
-Allows you to disable specific rules only for certain files or directories, while keeping them active elsewhere.
+linters-settings:
+ ENUM_ZERO_VALUE_SUFFIX:
+ suffix: UNSPECIFIED
+issues:
+ exclude-rules:
+ - path: legacy/**/*.proto
+ linters: [COMMENT_FIELD]
+ - path: generated
+~~~
-**Use cases:**
-- Legacy code that can't be easily updated
-- Third-party protos with different conventions
-- Generated code that doesn't follow your style
-- Gradual migration strategies
+Presets are MINIMAL, BASIC, STANDARD, and COMMENTS. Enable/disable and exclusion lists accept implemented rules and groups. Repetition is idempotent; disabling wins. Unknown names are errors, including when repeated in the opposite list. PACKAGE_NO_IMPORT_CYCLE is reserved and cannot be selected. Supported settings are ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix. linters.extends loads a local or locked-module base before local adjustments; see [shared policies](/docs/guides/organization-lint-style).
-**Format**: `rule_name: [list_of_paths]`
+~~~bash
+easyp lint --path proto
+easyp --format json lint --path proto
+easyp lint --root ./contracts --path proto
+~~~
-**Examples:**
-```yaml
-ignore_only:
- # Don't require service comments in legacy directory
- COMMENT_SERVICE:
- - "proto/legacy/"
- - "vendor/"
-
- # Don't enforce service suffix for external APIs
- SERVICE_SUFFIX:
- - "proto/external/"
- - "third_party/"
-
- # Allow old naming in specific files
- FIELD_LOWER_SNAKE_CASE:
- - "proto/legacy/old_messages.proto"
- - "vendor/external_api.proto"
-```
+--path is relative to the scan root, which defaults to the selected policy's directory; --root changes it. Policy lookup searches upward within the workspace. Without an ancestor policy, one unambiguous outermost descendant policy can be selected; multiple independent policies require --cfg. An explicit config takes precedence. Each nested policy section replaces the nearest inherited section as a whole.
-## Comment-Based Rule Ignoring
+The linter resolves imports using the nearest module's source roots and local or locked dependencies. A policy can also run without protobuf.mod. Vendored sources and hidden storage/Git directories are excluded from lint target discovery, including explicit vendor paths; dependency sources remain available for imports.
-When `allow_comment_ignores` is enabled, you can use inline comments to ignore specific linter rules for individual proto elements. This provides fine-grained control over rule enforcement.
+## Exclude paths
-### Supported Comment Formats
+issues.exclude-rules.path is relative to the policy file supplying the effective issues section, even when that section is inherited. Patterns support *, ?, [], and complete ** segments. Single-segment wildcards do not cross /; ** matches zero or more segments. Literal directories include their subtree. A literal .proto path matches that file only. Absolute paths, backslashes, traversal, and malformed patterns are rejected.
-EasyP supports two comment formats for maximum compatibility:
+A pathless rule applies to all files covered by that issues section. An empty or omitted linters list excludes matching files entirely. An empty rule {} explicitly ignores all files. A nested issues: {} clears inherited exclusions. The example suppresses only COMMENT_FIELD in legacy files and excludes the generated subtree entirely.
-#### Buf-compatible format
-```proto
-// buf:lint:ignore RULE_NAME
-```
+## Suppress with comments
-#### EasyP native format
-```proto
-// nolint:RULE_NAME
-```
-
-### Usage Examples
-
-#### Ignoring Service Rules
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-// buf:lint:ignore SERVICE_SUFFIX
-service UserAPI {
- rpc GetUser(GetUserRequest) returns (GetUserResponse);
-}
-```
-
-#### Ignoring RPC Rules
-```proto
-service UserService {
- // nolint:COMMENT_RPC
- // nolint:RPC_REQUEST_STANDARD_NAME
- rpc GetUserInfo(UserInfoReq) returns (UserInfoResp);
-}
-```
-
-#### Ignoring Message and Field Rules
-```proto
-// buf:lint:ignore COMMENT_MESSAGE
-message UserData {
- // nolint:COMMENT_FIELD
- // nolint:FIELD_LOWER_SNAKE_CASE
- string userName = 1;
-}
-```
-
-#### Ignoring Enum Rules
-```proto
-// nolint:COMMENT_ENUM
-// nolint:ENUM_ZERO_VALUE_SUFFIX
-enum UserType {
- UNKNOWN = 0; // Would normally require suffix
- ADMIN = 1;
- USER = 2;
-}
-```
-
-#### Multiple Rules on One Line
-```proto
-// buf:lint:ignore COMMENT_SERVICE,SERVICE_SUFFIX
-service LegacyAPI {
- // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME
- rpc getData(DataReq) returns (DataResp);
-}
-```
-
-### Best Practices for Comment Ignores
-
-#### Use Sparingly
-Comment ignores should be the exception, not the rule. Overuse indicates that your linting configuration may need adjustment.
-
-**Good:**
-```proto
-// Legacy service - buf:lint:ignore SERVICE_SUFFIX
-service UserAPI {
- rpc GetUser(...) returns (...);
+~~~proto
+// easyp:disable FIELD_LOWER_SNAKE_CASE
+message Example {
+ string legacyField = 1;
}
-```
-**Bad:**
-```proto
-// nolint:COMMENT_SERVICE,SERVICE_SUFFIX,COMMENT_RPC
-service UserAPI {
- // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME
- rpc getUser(...) returns (...);
- // nolint:COMMENT_RPC,RPC_RESPONSE_STANDARD_NAME
- rpc updateUser(...) returns (...);
+message Another {
+ string legacyField = 1; // easyp:disable FIELD_LOWER_SNAKE_CASE
}
-```
-
-#### Add Explanatory Comments
-Always explain why you're ignoring a rule to help future maintainers understand the decision.
-
-```proto
-// Third-party API compatibility requires non-standard naming
-// buf:lint:ignore SERVICE_SUFFIX
-service ExternalUserAPI {
- // Legacy method name for backwards compatibility
- // nolint:RPC_REQUEST_STANDARD_NAME
- rpc getUserData(UserReq) returns (UserResp);
-}
-```
-
-#### Prefer Configuration Over Comments
-When multiple files need the same rule ignored, use `ignore_only` configuration instead of individual comments.
-
-**Instead of:**
-```proto
-// In file1.proto
-// buf:lint:ignore COMMENT_SERVICE
-service API1 { ... }
-
-// In file2.proto
-// buf:lint:ignore COMMENT_SERVICE
-service API2 { ... }
-```
-
-**Use:**
-```yaml
-# In easyp.yaml
-lint:
- ignore_only:
- COMMENT_SERVICE: ["legacy/"]
-```
-
-## Linter Categories
-
-To accommodate different project needs and preferences, EasyP linter provides predefined rule categories. These categories group together various rules, allowing teams to quickly select the level of strictness or areas they want to focus on during linting.
-
-**When to use each category:**
-
-- **MINIMAL:** Essential for any proto project - ensures basic consistency and prevents fundamental issues
-- **BASIC:** Recommended for most projects - enforces common naming conventions and best practices
-- **DEFAULT:** Additional quality checks - useful for mature projects with established workflows
-- **COMMENTS:** Documentation requirements - important for public APIs and team collaboration
-- **UNARY_RPC:** Streaming restrictions - use when your architecture requires only unary RPCs
-
-The available categories are:
-- **MINIMAL:** Basic checks to ensure package consistency.
-- **BASIC:** Additional checks for naming conventions and usage patterns.
-- **DEFAULT:** A set of default rules that most projects should use.
-- **COMMENTS:** Ensures that comments are present and properly formatted.
-- **UNARY_RPC:** Specific rules for unary RPC services.
-
-### Rule Groupings
-
-Below are the rule groupings under each category:
-
-#### MINIMAL
-
-- `DIRECTORY_SAME_PACKAGE`
-- `PACKAGE_DEFINED`
-- `PACKAGE_DIRECTORY_MATCH`
-- `PACKAGE_SAME_DIRECTORY`
-
-#### BASIC
-
-- `ENUM_FIRST_VALUE_ZERO`
-- `ENUM_NO_ALLOW_ALIAS`
-- `ENUM_PASCAL_CASE`
-- `ENUM_VALUE_UPPER_SNAKE_CASE`
-- `FIELD_LOWER_SNAKE_CASE`
-- `IMPORT_NO_PUBLIC`
-- `IMPORT_NO_WEAK`
-- `IMPORT_USED`
-- `MESSAGE_PASCAL_CASE`
-- `ONEOF_LOWER_SNAKE_CASE`
-- `PACKAGE_LOWER_SNAKE_CASE`
-- `PACKAGE_SAME_CSHARP_NAMESPACE`
-- `PACKAGE_SAME_GO_PACKAGE`
-- `PACKAGE_SAME_JAVA_MULTIPLE_FILES`
-- `PACKAGE_SAME_JAVA_PACKAGE`
-- `PACKAGE_SAME_PHP_NAMESPACE`
-- `PACKAGE_SAME_RUBY_PACKAGE`
-- `PACKAGE_SAME_SWIFT_PREFIX`
-- `RPC_PASCAL_CASE`
-- `SERVICE_PASCAL_CASE`
-
-#### DEFAULT
-
-- `ENUM_VALUE_PREFIX`
-- `ENUM_ZERO_VALUE_SUFFIX`
-- `FILE_LOWER_SNAKE_CASE`
-- `RPC_REQUEST_RESPONSE_UNIQUE`
-- `RPC_REQUEST_STANDARD_NAME`
-- `RPC_RESPONSE_STANDARD_NAME`
-- `PACKAGE_VERSION_SUFFIX`
-- `SERVICE_SUFFIX`
-
-#### COMMENTS
-- `COMMENT_ENUM`
-- `COMMENT_ENUM_VALUE`
-- `COMMENT_FIELD`
-- `COMMENT_MESSAGE`
-- `COMMENT_ONEOF`
-- `COMMENT_RPC`
-- `COMMENT_SERVICE`
+// easyp:disable MESSAGE_PASCAL_CASE
+message old_name {}
+message another_old_name {}
+// easyp:enable MESSAGE_PASCAL_CASE
+~~~
-#### UNARY_RPC
+An unpaired disable must annotate a declaration and covers that declaration's line or block. A paired disable/enable bounds a region in the same file; nested regions for the same rule are balanced. Suppressions do not leak to other files or policies. Rule names may be comma- or whitespace-separated; comment directives accept individual rules, not groups.
-- `RPC_NO_CLIENT_STREAMING`
-- `RPC_NO_SERVER_STREAMING`
+Legacy nolint:RULE and buf:lint:ignore RULE remain declaration annotations. An explanation may follow a space-delimited -- or // separator. Only parsed comments are interpreted. Empty directives, unknown rules, unsupported actions, and unmatched enables are errors with source locations.
-## Conclusion
+linters.allow_comment_ignores defaults to true for each effective policy. Set it to false to disable comment suppression in that policy; malformed directives remain errors on files being linted.
-Adopting the EasyP linter for your proto files can significantly enhance your development workflow, code quality,
-and overall project maintainability. With full compatibility with the Buf linter, teams can easily migrate and start benefiting
-from our tool's robust features and flexible configuration options.
+See the [policy reference](/docs/reference/easyp-yaml). The older lint.use, lint.except, and lint.ignore_only configuration is not accepted by the v1 CLI.
diff --git a/content/docs/cli/linter/index.ru.mdx b/content/docs/cli/linter/index.ru.mdx
index 56dcac1..1be2feb 100644
--- a/content/docs/cli/linter/index.ru.mdx
+++ b/content/docs/cli/linter/index.ru.mdx
@@ -1,336 +1,67 @@
---
title: "Линтер"
+description: "Настройка и запуск protobuf-линтера EasyP v1."
---
-[[toc]]
+easyp lint проверяет .proto по политике v1 из easyp.yaml, указывая положение в исходнике и имя правила.
-## Зачем нужен линтер для proto файлов?
-
-Линтеры играют ключевую роль в современной разработке, особенно когда речь о `.proto` файлах. Они обеспечивают единый стиль и структуру, помогают находить потенциальные ошибки на ранних этапах и поддерживают читаемость кода. Это даёт выгоды:
-
-- **Снижение затрат на разработку:** Ошибки ловятся раньше, меньше времени на отладку.
-- **Улучшение командного взаимодействия:** Единообразный код легче понимать и сопровождать.
-- **Бизнес-эффективность:** Более качественный код → меньше инцидентов в проде → ниже стоимость поддержки.
-
-## Справочник по конфигурации
-
-Конфигурация линтера настраивается в секции `lint` файла `easyp.yaml`.
-
-### Полный пример конфигурации
-
-```yaml
-lint:
- # Используемые категории и правила
- use:
- - MINIMAL
- - BASIC
- - COMMENT_SERVICE
- - COMMENT_RPC
-
- # Кастомные суффиксы
- enum_zero_value_suffix: "UNSPECIFIED"
- service_suffix: "Service"
-
- # Исключения директорий и файлов
- ignore:
- - "vendor/"
- - "third_party/"
- - "legacy/old_protos/"
-
- except:
- - COMMENT_FIELD
- - COMMENT_MESSAGE
-
- # Разрешить игнорирование правил комментариями
+~~~yaml
+version: v1
+linters:
+ default: STANDARD
+ enable: [COMMENT_SERVICE]
+ disable: [SERVICE_SUFFIX]
allow_comment_ignores: true
-
- # Игнор отдельных правил только для указанных путей
- ignore_only:
- COMMENT_SERVICE: ["legacy/", "vendor/"]
- SERVICE_SUFFIX: ["proto/external/"]
-```
-
-### Параметры конфигурации
-
-#### `use` ([]string)
-Определяет набор правил или категорий для включения. Можно смешивать категории и конкретные правила.
-
-**Категории:**
-- **MINIMAL**: Базовая согласованность пакетов
-- **BASIC**: Соглашения по именованию и структуре
-- **DEFAULT**: Рекомендованные правила для большинства проектов
-- **COMMENTS**: Требования к комментариям
-- **UNARY_RPC**: Ограничение на streaming RPC
-
-**Индивидуальные правила:** Любое имя правила (например `ENUM_PASCAL_CASE`, `FIELD_LOWER_SNAKE_CASE`)
-
-**Примеры:**
-```yaml
-# Только категории
-use: [MINIMAL, BASIC, DEFAULT]
-
-# Смешивание
-use:
- - MINIMAL
- - COMMENT_SERVICE
- - COMMENT_RPC
- - ENUM_PASCAL_CASE
-
-# Точный набор
-use:
- - PACKAGE_DEFINED
- - SERVICE_PASCAL_CASE
- - FIELD_LOWER_SNAKE_CASE
-```
-
-#### `enum_zero_value_suffix` (string)
-Обязывает нулевое значение enum иметь заданный суффикс.
-
-**Обычно:** `"UNSPECIFIED"`, `"UNKNOWN"`, `"DEFAULT"`
-```yaml
-enum_zero_value_suffix: "UNSPECIFIED"
-```
-
-```proto
-enum Status {
- STATUS_UNSPECIFIED = 0; // Требуемый суффикс
- STATUS_ACTIVE = 1;
- STATUS_INACTIVE = 2;
-}
-```
-
-#### `service_suffix` (string)
-Требуемый суффикс для имён сервисов (унификация стиля).
-
-```yaml
-service_suffix: "Service"
-```
-
-```proto
-service UserService { // Обязательный суффикс
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `ignore` ([]string)
-Полное исключение путей из линтинга.
-
-**Use cases:**
-- vendor / third_party
-- сгенерированные файлы
-- легаси подпакеты
-- тестовые фикстуры
-
-```yaml
-ignore:
- - "vendor/"
- - "third_party/"
- - "testdata/"
- - "proto/legacy/"
- - "**/*_test.proto"
-```
+linters-settings:
+ ENUM_ZERO_VALUE_SUFFIX:
+ suffix: UNSPECIFIED
+issues:
+ exclude-rules:
+ - path: legacy/**/*.proto
+ linters: [COMMENT_FIELD]
+ - path: generated
+~~~
-#### `except` ([]string)
-Глобально отключает правила.
+Пресеты: MINIMAL, BASIC, STANDARD и COMMENTS. Списки enable/disable и исключений принимают реализованные правила и группы. Повторы не добавляют проверок; отключение приоритетнее включения. Неизвестные имена — ошибки, даже если повторены в противоположном списке. PACKAGE_NO_IMPORT_CYCLE зарезервировано и выбирать его нельзя. Поддерживаются настройки ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix. linters.extends подключает локальную или закреплённую базу перед локальными изменениями; см. [общие политики](/ru/docs/guides/organization-lint-style).
-```yaml
-except:
- - COMMENT_FIELD
- - COMMENT_MESSAGE
- - SERVICE_SUFFIX
- - ENUM_ZERO_VALUE_SUFFIX
-```
+~~~bash
+easyp lint --path proto
+easyp --format json lint --path proto
+easyp lint --root ./contracts --path proto
+~~~
-#### `allow_comment_ignores` (bool)
-Разрешает инлайн‑игнор правил комментариями.
+--path считается от корня проверки, по умолчанию — каталога выбранной политики; --root меняет его. Поиск политики идёт вверх в пределах workspace. Без политики в предках можно выбрать одну однозначную внешнюю политику в потомках; несколько независимых политик требуют --cfg. Явный конфиг имеет приоритет. Каждая вложенная секция целиком заменяет ближайшую унаследованную секцию.
-```yaml
-allow_comment_ignores: true
-```
+Для импортов линтер использует корни ближайшего модуля и его локальные или зафиксированные зависимости. Политика может работать без protobuf.mod. Вендорные исходники и скрытые каталоги хранилищ/Git исключены из поиска целей линтинга, включая явные пути в vendor; зависимости остаются доступными для импортов.
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-service LegacyUserAPI {
- // nolint:COMMENT_RPC
- rpc GetUser(...) returns (...);
-}
-```
-
-#### `ignore_only` (map[string][]string)
-Таргетированное игнорирование конкретных правил для указанных путей.
-
-```yaml
-ignore_only:
- COMMENT_SERVICE:
- - "proto/legacy/"
- - "vendor/"
- SERVICE_SUFFIX:
- - "proto/external/"
- - "third_party/"
- FIELD_LOWER_SNAKE_CASE:
- - "proto/legacy/old_messages.proto"
- - "vendor/external_api.proto"
-```
-
-## Игнор правил комментариями
-
-Если включён `allow_comment_ignores`, можно точечно отключать правила.
-
-### Форматы комментариев
+## Исключение путей
-#### Совместимый с Buf
-```proto
-// buf:lint:ignore RULE_NAME
-```
-
-#### Нативный EasyP
-```proto
-// nolint:RULE_NAME
-```
-
-### Примеры
-
-#### Игнор правил сервиса
-```proto
-// buf:lint:ignore COMMENT_SERVICE
-// buf:lint:ignore SERVICE_SUFFIX
-service UserAPI {
- rpc GetUser(GetUserRequest) returns (GetUserResponse);
-}
-```
-
-#### Игнор RPC
-```proto
-service UserService {
- // nolint:COMMENT_RPC
- // nolint:RPC_REQUEST_STANDARD_NAME
- rpc GetUserInfo(UserInfoReq) returns (UserInfoResp);
-}
-```
+issues.exclude-rules.path считается от файла политики, предоставляющего эффективную секцию issues, в том числе унаследованную. Поддерживаются *, ?, [] и полные сегменты **. Односегментные шаблоны не пересекают /; ** совпадает с нулём или более сегментами. Буквальный каталог включает своё поддерево. Буквальный путь с окончанием .proto совпадает только с файлом. Абсолютные пути, обратные слеши, переходы к родителю и некорректные шаблоны отклоняются.
-#### Игнор Message и Field
-```proto
-// buf:lint:ignore COMMENT_MESSAGE
-message UserData {
- // nolint:COMMENT_FIELD
- // nolint:FIELD_LOWER_SNAKE_CASE
- string userName = 1;
-}
-```
+Правило без пути действует на все файлы этой секции issues. Пустой или отсутствующий linters исключает совпавшие файлы целиком. Пустое правило {} явно исключает все файлы. Вложенная issues: {} очищает унаследованные исключения. В примере у legacy-файлов подавляется только COMMENT_FIELD, а поддерево generated исключено полностью.
-#### Игнор Enum
-```proto
-// nolint:COMMENT_ENUM
-// nolint:ENUM_ZERO_VALUE_SUFFIX
-enum UserType {
- UNKNOWN = 0; // Обычно требовался бы суффикс
- ADMIN = 1;
- USER = 2;
-}
-```
+## Подавление комментариями
-#### Несколько правил в одной строке
-```proto
-// buf:lint:ignore COMMENT_SERVICE,SERVICE_SUFFIX
-service LegacyAPI {
- // nolint:COMMENT_RPC,RPC_REQUEST_STANDARD_NAME
- rpc getData(DataReq) returns (DataResp);
+~~~proto
+// easyp:disable FIELD_LOWER_SNAKE_CASE
+message Example {
+ string legacyField = 1;
}
-```
-
-### Рекомендации
-#### Используйте редко
-Частое игнорирование = сигнал пересмотреть конфигурацию.
-```proto
-// Легаси сервис - buf:lint:ignore SERVICE_SUFFIX
-service UserAPI { ... }
-```
-
-#### Плохой пример
-```proto
-// nolint:COMMENT_SERVICE,SERVICE_SUFFIX,COMMENT_RPC
-service UserAPI { ... }
-```
-
-#### Добавляйте пояснения
-```proto
-// Совместимость с внешним API
-// buf:lint:ignore SERVICE_SUFFIX
-service ExternalUserAPI {
- // Легаси имя метода
- // nolint:RPC_REQUEST_STANDARD_NAME
- rpc getUserData(UserReq) returns (UserResp);
+message Another {
+ string legacyField = 1; // easyp:disable FIELD_LOWER_SNAKE_CASE
}
-```
-
-#### Предпочитайте конфигурацию
-Если нужно игнорировать правило в группе файлов — используйте `ignore_only`.
-
-## Категории линтера
-
-Категории помогают быстро выбрать уровень строгости.
-
-**Когда использовать:**
-- **MINIMAL**: Минимальная базовая целостность
-- **BASIC**: Частые соглашения имен
-- **DEFAULT**: Дополнительные проверки качества
-- **COMMENTS**: Обязательные комментарии (API, команды)
-- **UNARY_RPC**: Ограничить streaming RPC
-
-### Группировки правил
-
-#### MINIMAL
-- `DIRECTORY_SAME_PACKAGE`
-- `PACKAGE_DEFINED`
-- `PACKAGE_DIRECTORY_MATCH`
-- `PACKAGE_SAME_DIRECTORY`
-
-#### BASIC
-- `ENUM_FIRST_VALUE_ZERO`
-- `ENUM_NO_ALLOW_ALIAS`
-- `ENUM_PASCAL_CASE`
-- `ENUM_VALUE_UPPER_SNAKE_CASE`
-- `FIELD_LOWER_SNAKE_CASE`
-- `IMPORT_NO_PUBLIC`
-- `IMPORT_NO_WEAK`
-- `IMPORT_USED`
-- `MESSAGE_PASCAL_CASE`
-- `ONEOF_LOWER_SNAKE_CASE`
-- `PACKAGE_LOWER_SNAKE_CASE`
-- `PACKAGE_SAME_CSHARP_NAMESPACE`
-- `PACKAGE_SAME_GO_PACKAGE`
-- `PACKAGE_SAME_JAVA_MULTIPLE_FILES`
-- `PACKAGE_SAME_JAVA_PACKAGE`
-- `PACKAGE_SAME_PHP_NAMESPACE`
-- `PACKAGE_SAME_RUBY_PACKAGE`
-- `PACKAGE_SAME_SWIFT_PREFIX`
-- `RPC_PASCAL_CASE`
-- `SERVICE_PASCAL_CASE`
-#### DEFAULT
-- `ENUM_VALUE_PREFIX`
-- `ENUM_ZERO_VALUE_SUFFIX`
-- `FILE_LOWER_SNAKE_CASE`
-- `RPC_REQUEST_RESPONSE_UNIQUE`
-- `RPC_REQUEST_STANDARD_NAME`
-- `RPC_RESPONSE_STANDARD_NAME`
-- `PACKAGE_VERSION_SUFFIX`
-- `SERVICE_SUFFIX`
+// easyp:disable MESSAGE_PASCAL_CASE
+message old_name {}
+message another_old_name {}
+// easyp:enable MESSAGE_PASCAL_CASE
+~~~
-#### COMMENTS
-- `COMMENT_ENUM`
-- `COMMENT_ENUM_VALUE`
-- `COMMENT_FIELD`
-- `COMMENT_MESSAGE`
-- `COMMENT_ONEOF`
-- `COMMENT_RPC`
-- `COMMENT_SERVICE`
+Непарный disable должен аннотировать объявление и действует на его строку или блок. Пара disable/enable ограничивает регион в одном файле; вложенные регионы одного правила сбалансированы. Подавления не переходят в другие файлы или политики. Имена правил разделяются запятыми или пробелами; группы в директивах комментариев не принимаются.
-#### UNARY_RPC
-- `RPC_NO_CLIENT_STREAMING`
-- `RPC_NO_SERVER_STREAMING`
+Старые nolint:RULE и buf:lint:ignore RULE остаются аннотациями объявлений. Пояснение можно добавить после отделённого пробелами -- или //. Интерпретируются только разобранные комментарии. Пустые директивы, неизвестные правила, неподдерживаемые действия и enable без пары — ошибки с координатами исходника.
-## Заключение
+linters.allow_comment_ignores по умолчанию равен true для каждой эффективной политики. False отключает подавление комментариями в этой политике; некорректные директивы в проверяемых файлах остаются ошибками.
-Внедрение EasyP линдера для ваших proto файлов заметно улучшит workflow, качество и поддерживаемость кода. Полная совместимость с Buf позволяет командам мигрировать без боли, используя гибкую конфигурацию и мощные возможности из коробки.
+См. [справочник политики](/ru/docs/reference/easyp-yaml). Старые поля lint.use, lint.except и lint.ignore_only CLI v1 не принимает.
diff --git a/content/docs/cli/package-manager/easyp-vs-buf.mdx b/content/docs/cli/package-manager/easyp-vs-buf.mdx
index 8d4d7ab..2308751 100644
--- a/content/docs/cli/package-manager/easyp-vs-buf.mdx
+++ b/content/docs/cli/package-manager/easyp-vs-buf.mdx
@@ -1,455 +1,34 @@
---
-title: "EasyP vs Buf Package Management"
+title: "Using Buf-configured Git dependencies"
+description: "How the EasyP v1 pilot reads proto roots from Git dependencies that use Buf configuration."
---
-[[toc]]
+An EasyP v1 project lists Git modules in protobuf.mod. A dependency repository can use Buf configuration; EasyP reads that configuration to find its .proto source roots. The consumer does not need to copy those roots into easyp.gen.yaml.
-This document provides a comprehensive comparison between EasyP's decentralized package management approach and Buf's centralized Buf Schema Registry (BSR) model, helping you understand the key differences and choose the right solution for your needs.
+| Dependency file | Roots used by EasyP |
+|-----------------|---------------------|
+| buf.work.yaml v1 | directories |
+| buf.yaml v2 | modules[].path |
+| buf.yaml v1 | Repository root |
+| buf.yaml v1beta1 | build.roots, or repository root if omitted |
-## Architecture Comparison
+When a dependency has no EasyP or Buf configuration, EasyP uses its repository root. If it has an older EasyP protobuf.mod or easyp.yaml, EasyP also reads its transitive requirements and declared roots.
-### EasyP: Decentralized Git-Based Approach
+When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed.
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ EasyP Architecture │
-├─────────────────────────────────────────────────────────────────┤
-│ │
-│ Developer Machine Git Repositories │
-│ ┌──────────────┐ ┌─────────────────┐ │
-│ │ │ clone/ │ github.com/ │ │
-│ │ ~/.easyp/ │◄─────────►│ googleapis/ │ │
-│ │ cache/ │ fetch │ googleapis │ │
-│ │ │ │ │ │
-│ │ mod/ │ ├─────────────────┤ │
-│ │ │ │ company.com/ │ │
-│ └──────────────┘ │ internal-protos │ │
-│ │ │ │
-│ ├─────────────────┤ │
-│ │ gitlab.com/ │ │
-│ │ team/shared │ │
-│ └─────────────────┘ │
-│ │
-│ ✅ Direct repository access │
-│ ✅ No single point of failure │
-│ ✅ Works with any Git hosting │
-│ ✅ Complete control over dependencies │
-│ │
-└─────────────────────────────────────────────────────────────────┘
-```
+~~~text
+# Consumer protobuf.mod
+module github.com/acme/service
+roots proto
+require github.com/acme/buf-contracts v1.2.0
+~~~
-### Buf: Centralized Registry Approach
+~~~bash
+easyp mod tidy
+easyp mod download
+easyp generate
+~~~
-```
-┌────────────────────────────────────────────────────────────────┐
-│ Buf Architecture │
-├────────────────────────────────────────────────────────────────┤
-│ │
-│ Developer Machine Buf Schema Registry (BSR) │
-│ ┌──────────────┐ ┌─────────────────────────────┐ │
-│ │ │ push/pull │ │ │
-│ │ ~/.cache/ │◄────────────►│ buf.build │ │
-│ │ bufcli/ │ modules │ │ │
-│ │ │ │ ┌─────────────────────────┐ │ │
-│ │ │ │ │ googleapis/googleapis │ │ │
-│ │ │ │ ├─────────────────────────┤ │ │
-│ │ │ │ │ grpc/grpc │ │ │
-│ │ │ │ ├─────────────────────────┤ │ │
-│ │ │ │ │ envoyproxy/protoc-gen- │ │ │
-│ │ │ │ │ validate │ │ │
-│ └──────────────┘ │ └─────────────────────────┘ │ │
-│ │ │ │
-│ └─────────────────────────────┘ │
-│ │
-│ ⚠️ Centralized dependency │
-│ ⚠️ Single point of control │
-│ ⚠️ Requires buf.build access │
-│ ⚠️ Limited to BSR ecosystem │
-│ │
-└────────────────────────────────────────────────────────────────┘
-```
+mod tidy resolves the Git dependency and records the selected commit and content hash in protobuf.lock. Buf Registry dependency names are not converted into Git URLs automatically; declare a suitable Git source in the consumer manifest. Buf include/exclude filters are not yet supported for Git dependency import roots and produce an error.
-## Key Differences Summary
-
-| Aspect | EasyP | Buf |
-|--------|-------|-----|
-| **Architecture** | Decentralized (Git-based) | Centralized (BSR registry) |
-| **Dependency Source** | Any Git repository | Buf Schema Registry only |
-| **Single Point of Failure** | No | Yes (buf.build) |
-| **Enterprise Deployment** | Fully air-gapped support | Requires BSR access or private BSR |
-| **Authentication** | Git credentials (SSH/HTTPS) | Buf tokens + Git credentials |
-| **Vendor Lock-in** | None | Buf ecosystem |
-| **Private Repositories** | Native Git support | Must publish to BSR first |
-| **Offline Support** | Full (via vendoring) | Limited (cached modules only) |
-| **Cost** | Free (uses existing Git) | Free tier + paid plans |
-| **Setup Complexity** | Minimal | Moderate (BSR setup) |
-
-## Detailed Feature Comparison
-
-### 1. Dependency Management Philosophy
-
-#### EasyP: "Any Git Repository is a Package"
-```yaml
-# Direct Git repository references
-deps:
- - github.com/googleapis/googleapis@v1.2.3
- - gitlab.company.com/protos/internal@v2.0.1
- - git.example.com/team/shared-types@main
-```
-
-**Advantages:**
-- ✅ Use any existing Git repository immediately
-- ✅ No need to "publish" to a separate registry
-- ✅ Version control is the source of truth
-- ✅ Works with private Git servers out-of-the-box
-
-#### Buf: "Registry-First Approach"
-```yaml
-# buf.yaml - Must reference BSR modules
-version: v1
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpc/grpc
- - buf.build/envoyproxy/protoc-gen-validate
-```
-
-**Advantages:**
-- ✅ Curated, high-quality modules
-- ✅ Rich metadata and documentation
-- ✅ Dependency graph visualization
-- ✅ Semantic versioning enforcement
-
-**Limitations:**
-- ❌ Must publish to BSR before use
-- ❌ Requires BSR account and authentication
-- ❌ Cannot reference arbitrary Git repositories directly
-
-### 2. Enterprise and Air-Gapped Environments
-
-#### EasyP: Full Air-Gap Support
-
-**Scenario**: Large enterprise with strict network policies
-
-```bash
-# 1. Initial setup (with internet)
-easyp mod download # Downloads to ~/.easyp/
-easyp mod vendor # Creates easyp_vendor/
-
-# 2. Transfer to air-gapped environment
-tar -czf easyp-deps.tar.gz ~/.easyp easyp_vendor/
-# ... transfer archive ...
-
-# 3. Air-gapped environment (no internet)
-tar -xzf easyp-deps.tar.gz
-export EASYPPATH=$PWD/.easyp
-easyp generate # Works offline
-```
-
-**Benefits:**
-- ✅ Complete independence from external services
-- ✅ No need for internal registry infrastructure
-- ✅ Uses existing Git infrastructure
-- ✅ Simple file-based distribution
-
-#### Buf: Requires BSR Infrastructure
-
-**Scenario**: Same enterprise setup
-
-```bash
-# Option 1: Use buf.build (requires internet)
-buf mod download # Must reach buf.build
-
-# Option 2: Set up private BSR (complex)
-# - Deploy BSR server infrastructure
-# - Migrate all modules to private BSR
-# - Configure authentication and access
-# - Maintain registry server
-```
-
-**Challenges:**
-- ❌ Requires constant internet access OR expensive private BSR
-- ❌ Complex infrastructure for private deployments
-- ❌ All modules must be re-published to private registry
-- ❌ Additional operational overhead
-
-### 3. Security and Control
-
-#### EasyP: Direct Control
-```yaml
-# Full control over dependency sources
-deps:
- # Public repository - your choice of version
- - github.com/googleapis/googleapis@common-protos-1_3_1
-
- # Internal repository - complete control
- - gitlab.company.com/security/validated-protos@v1.0.0
-
- # Specific commit for security fix
- - github.com/bufbuild/protoc-gen-validate@abc123def456
-```
-
-**Security advantages:**
-- ✅ **No intermediary** - direct from source repository
-- ✅ **Audit trail** - Git commit history is the source of truth
-- ✅ **Cannot be "banned"** - no external party can revoke access
-- ✅ **Custom validation** - implement your own security scanning
-- ✅ **Fork protection** - easily fork and maintain dependencies
-
-#### Buf: Registry Dependency
-
-```yaml
-# Dependencies controlled by BSR
-deps:
- - buf.build/googleapis/googleapis # Controlled by Buf
- - buf.build/grpc/grpc # Could be removed/updated
-```
-
-**Security considerations:**
-- ⚠️ **Intermediary risk** - BSR controls what's available
-- ⚠️ **Account suspension** - Could lose access to dependencies
-- ⚠️ **Module removal** - Modules can be deleted from registry
-- ⚠️ **Update policies** - BSR may force updates or deprecations
-- ⚠️ **Third-party trust** - Must trust Buf's security practices
-
-### 4. Real-World Scenarios
-
-#### Scenario 1: Startup with Public Dependencies
-
-**EasyP Approach:**
-```yaml
-# Simple, direct references
-deps:
- - github.com/googleapis/googleapis
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
-```
-
-**Buf Approach:**
-```yaml
-# Requires understanding BSR module names
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpcecosystem/grpc-gateway
-```
-
-**Winner**: Tie - both work well for public dependencies
-
-#### Scenario 2: Enterprise with Mixed Public/Private Dependencies
-
-**EasyP Approach:**
-```yaml
-deps:
- # Public
- - github.com/googleapis/googleapis@v1.2.3
-
- # Private (existing Git repos)
- - github.com/mycompany/auth-protos@v2.0.0
- - gitlab.enterprise.com/platform/shared-types@v1.5.1
-```
-
-**Buf Approach:**
-```yaml
-# All must be published to BSR first
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/mycompany/auth-protos # Requires BSR publication
- - buf.build/mycompany/shared-types # Requires BSR publication
-```
-
-**Winner**: **EasyP** - no additional setup for private repos
-
-#### Scenario 3: Government/Defense Contractor (Air-Gapped)
-
-**EasyP Approach:**
-```bash
-# Internet-connected environment
-easyp mod vendor
-
-# Transfer to classified environment
-# Works immediately without any external dependencies
-```
-
-**Buf Approach:**
-```bash
-# Must deploy and maintain private BSR infrastructure
-# All modules must be re-published internally
-# Complex operational overhead
-```
-
-**Winner**: **EasyP** - significantly simpler air-gap deployment
-
-#### Scenario 4: Compliance and Auditing
-
-**EasyP Approach:**
-- ✅ **Direct audit trail**: Git commits show exact changes
-- ✅ **Compliance-friendly**: No external dependencies in production
-- ✅ **Reproducible**: Lock files pin exact Git commits
-- ✅ **Vulnerability management**: Direct control over security updates
-
-**Buf Approach:**
-- ⚠️ **Registry dependency**: Must audit BSR's security practices
-- ⚠️ **Third-party risk**: BSR is part of your compliance scope
-- ⚠️ **Limited control**: Cannot control when modules are updated/removed
-- ⚠️ **Audit complexity**: Must trace registry → Git → actual code
-
-**Winner**: **EasyP** - cleaner compliance story
-
-### 5. Cost and Infrastructure
-
-#### EasyP: Zero Additional Infrastructure
-
-**Costs:**
-- ✅ **$0** - Uses existing Git infrastructure
-- ✅ **No additional servers** to maintain
-- ✅ **No licensing fees** for registry software
-- ✅ **Scales with Git** - proven enterprise scalability
-
-**Infrastructure:**
-- Uses existing Git repositories (GitHub, GitLab, etc.)
-- Leverages existing authentication systems
-- No additional backup/disaster recovery needed
-
-#### Buf: Registry Infrastructure Costs
-
-**BSR Hosted (buf.build):**
-- ✅ Free tier available
-- ❌ Paid plans for private modules and teams
-- ❌ Subject to external pricing changes
-- ❌ Data locality concerns for some enterprises
-
-**Private BSR Deployment:**
-- ❌ Significant infrastructure costs (servers, databases, load balancers)
-- ❌ Operational overhead (monitoring, updates, backups)
-- ❌ Licensing costs for enterprise features
-- ❌ Additional disaster recovery planning
-
-### 6. Migration and Lock-in
-
-#### EasyP: No Lock-in
-
-**Migration FROM EasyP:**
-```yaml
-# EasyP dependencies are just Git repositories
-# Can easily migrate to any other system that supports Git
-deps:
- - github.com/googleapis/googleapis@v1.2.3 # Standard Git reference
-```
-
-**Migration TO EasyP:**
-```bash
-# From any Git-based system
-# Just reference the same repositories directly
-```
-
-#### Buf: Potential Lock-in
-
-**Migration FROM Buf:**
-- ❌ Must identify original Git repositories for each BSR module
-- ❌ BSR-specific module names don't translate directly
-- ❌ May lose version history and metadata
-- ❌ Complex if heavily integrated with BSR ecosystem
-
-**Migration TO Buf:**
-- ❌ Must publish all dependencies to BSR first
-- ❌ Cannot reference Git repositories directly
-- ❌ Must adopt BSR workflow and tooling
-
-## When to Choose Each Solution
-
-### Choose EasyP When:
-
-✅ **Enterprise/Air-gapped environments**
-- Need to work without external dependencies
-- Strict compliance requirements
-- Air-gapped or classified networks
-
-✅ **Security-first organizations**
-- Want direct control over dependency sources
-- Need to audit entire supply chain
-- Concerned about third-party service risks
-
-✅ **Existing Git-heavy workflows**
-- Team already comfortable with Git
-- Extensive private repository usage
-- Want to minimize new tools/infrastructure
-
-✅ **Cost-sensitive projects**
-- Want to avoid additional licensing costs
-- Don't want infrastructure overhead
-- Need predictable, zero-cost scaling
-
-✅ **Mixed public/private dependencies**
-- Heavy use of internal Git repositories
-- Don't want to republish existing repos
-- Need flexibility in dependency sources
-
-### Choose Buf When:
-
-✅ **Heavy BSR ecosystem usage**
-- Already invested in Buf tooling (lint, breaking changes, generation)
-- Want curated, high-quality modules
-- Benefit from BSR's rich metadata and docs
-
-✅ **Collaborative development**
-- Need dependency graph visualization
-- Want centralized module discovery
-- Benefit from BSR's collaboration features
-
-✅ **Simple public-only dependencies**
-- Primarily use well-known public modules
-- Don't mind BSR dependency
-- Value the curated module experience
-
-✅ **Team new to protobuf**
-- Benefit from BSR's documentation and examples
-- Want guided module discovery
-- Prefer opinionated, structured approach
-
-## Migration Paths
-
-### Migrating from Buf to EasyP
-
-1. **Identify source repositories** for each BSR module
-2. **Map BSR modules** to Git repository references
-3. **Update configuration** to use Git URLs
-4. **Test compatibility** and resolve any issues
-
-Example migration:
-```yaml
-# Before (buf.yaml)
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpc/grpc
-
-# After (easyp.yaml)
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1
- - github.com/grpc/grpc@v1.50.0
-```
-
-### Migrating from EasyP to Buf
-
-1. **Publish modules** to BSR (if not already available)
-2. **Create BSR account** and configure authentication
-3. **Update configuration** to reference BSR modules
-4. **Adopt BSR workflow** (push, pull, etc.)
-
-## Conclusion
-
-Both EasyP and Buf offer valid approaches to protobuf dependency management, but they serve different needs:
-
-**EasyP excels in:**
-- Enterprise and air-gapped environments
-- Security-conscious organizations
-- Cost-sensitive projects
-- Direct Git repository usage
-- Zero-infrastructure deployments
-
-**Buf excels in:**
-- Collaborative, open-source focused teams
-- Organizations wanting curated, high-quality modules
-- Teams new to protobuf ecosystem
-- Projects heavily using BSR features
-
-The choice between EasyP and Buf often comes down to your organization's priorities around **control vs. convenience**, **security vs. collaboration features**, and **infrastructure costs vs. managed services**.
-
-For many enterprise environments, EasyP's decentralized, Git-native approach provides the security, control, and cost-effectiveness needed for production protobuf workflows, while Buf's centralized registry excels in collaborative, open-source focused development environments.
+After mod tidy, mod vendor can copy the locked Git dependency's .proto files into easyp_vendor using the roots extracted from its Buf configuration. See the [package manager guide](/docs/cli/package-manager).
diff --git a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx
index 325a85b..01ef92e 100644
--- a/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx
+++ b/content/docs/cli/package-manager/easyp-vs-buf.ru.mdx
@@ -1,430 +1,34 @@
---
-title: "EasyP против Buf: управление пакетами"
+title: "Git-зависимости с конфигом Buf"
+description: "Как пилотная версия EasyP v1 извлекает корни proto из Git-зависимостей на Buf."
---
-[[toc]]
+Проект EasyP v1 перечисляет Git-модули в protobuf.mod. Репозиторий зависимости может использовать конфигурацию Buf: EasyP читает её и находит корни исходных .proto. Дублировать эти корни в easyp.gen.yaml потребителя не нужно.
-Этот документ даёт подробное сравнение децентрализованного подхода EasyP к управлению пакетами и централизованной модели Buf через Buf Schema Registry (BSR), чтобы помочь понять ключевые различия и выбрать подходящее решение для ваших задач.
+| Файл зависимости | Корни, которые использует EasyP |
+|------------------|---------------------------------|
+| buf.work.yaml v1 | directories |
+| buf.yaml v2 | modules[].path |
+| buf.yaml v1 | Корень репозитория |
+| buf.yaml v1beta1 | build.roots или корень репозитория |
-## Сравнение архитектуры
+Если у зависимости нет конфигурации EasyP или Buf, её корнем считается каталог репозитория. Если есть старые EasyP protobuf.mod или easyp.yaml, EasyP также читает транзитивные требования и объявленные корни.
-### EasyP: децентрализованный подход на базе Git
+При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются.
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ Архитектура EasyP │
-├─────────────────────────────────────────────────────────────────┤
-│ │
-│ Машина разработчика Git репозитории │
-│ ┌──────────────┐ ┌─────────────────┐ │
-│ │ │ clone/ │ github.com/ │ │
-│ │ ~/.easyp/ │◄─────────►│ googleapis/ │ │
-│ │ cache/ │ fetch │ googleapis │ │
-│ │ │ │ │ │
-│ │ mod/ │ ├─────────────────┤ │
-│ │ │ │ company.com/ │ │
-│ └──────────────┘ │ internal-protos │ │
-│ │ │ │
-│ ├─────────────────┤ │
-│ │ gitlab.com/ │ │
-│ │ team/shared │ │
-│ └─────────────────┘ │
-│ │
-│ ✅ Прямой доступ к репозиториям │
-│ ✅ Нет единой точки отказа │
-│ ✅ Работает с любым Git хостингом │
-│ ✅ Полный контроль над зависимостями │
-│ │
-└─────────────────────────────────────────────────────────────────┘
-```
+~~~text
+# protobuf.mod потребителя
+module github.com/acme/service
+roots proto
+require github.com/acme/buf-contracts v1.2.0
+~~~
-### Buf: централизованный реестр (BSR)
+~~~bash
+easyp mod tidy
+easyp mod download
+easyp generate
+~~~
-```
-┌────────────────────────────────────────────────────────────────┐
-│ Архитектура Buf │
-├────────────────────────────────────────────────────────────────┤
-│ │
-│ Машина разработчика Buf Schema Registry (BSR) │
-│ ┌──────────────┐ ┌─────────────────────────────┐ │
-│ │ │ push/pull │ │ │
-│ │ ~/.cache/ │◄────────────►│ buf.build │ │
-│ │ bufcli/ │ modules │ │ │
-│ │ │ │ ┌─────────────────────────┐ │ │
-│ │ │ │ │ googleapis/googleapis │ │ │
-│ │ │ │ ├─────────────────────────┤ │ │
-│ │ │ │ │ grpc/grpc │ │ │
-│ │ │ │ ├─────────────────────────┤ │ │
-│ │ │ │ │ envoyproxy/protoc-gen- │ │ │
-│ │ │ │ │ validate │ │ │
-│ └──────────────┘ │ └─────────────────────────┘ │ │
-│ │ │ │
-│ └─────────────────────────────┘ │
-│ │
-│ ⚠️ Централизованная зависимость │
-│ ⚠️ Единая точка контроля │
-│ ⚠️ Требуется доступ к buf.build │
-│ ⚠️ Ограничение экосистемой BSR │
-│ │
-└────────────────────────────────────────────────────────────────┘
-```
+mod tidy разрешает Git-зависимость и записывает выбранный коммит и хеш содержимого в protobuf.lock. Имена зависимостей Buf Registry не превращаются в Git URL автоматически: подходящий Git-источник надо объявить в манифесте потребителя. Фильтры Buf include/exclude для корней Git-зависимостей пока не поддерживаются и вызывают ошибку.
-## Краткое резюме различий
-
-| Аспект | EasyP | Buf |
-|--------|-------|-----|
-| **Архитектура** | Децентрализованная (Git) | Централизованная (реестр BSR) |
-| **Источник зависимостей** | Любой Git репозиторий | Только модули BSR |
-| **Единая точка отказа** | Нет | Да (buf.build) |
-| **Enterprise / air‑gapped** | Полная поддержка | Требует доступа к BSR или приватного BSR |
-| **Аутентификация** | Git (SSH / HTTPS) | Токены Buf + Git |
-| **Vendor lock‑in** | Отсутствует | Привязка к экосистеме Buf |
-| **Частные репозитории** | Нативно через Git | Нужно опубликовать в BSR |
-| **Оффлайн поддержка** | Полная (через vendoring) | Ограничена (кэшированные модули) |
-| **Стоимость** | Бесплатно (использует существующий Git) | Бесплатный тариф + платные планы |
-| **Сложность настройки** | Минимальная | Средняя (настройка BSR) |
-
-## Подробное сравнение возможностей
-
-### 1. Философия управления зависимостями
-
-#### EasyP: «Любой Git репозиторий — это пакет»
-```yaml
-# Прямые ссылки на Git репозитории
-deps:
- - github.com/googleapis/googleapis@v1.2.3
- - gitlab.company.com/protos/internal@v2.0.1
- - git.example.com/team/shared-types@main
-```
-
-**Преимущества:**
-- ✅ Использование любого существующего репозитория сразу
-- ✅ Не нужно «публиковать» в отдельный реестр
-- ✅ Истинный источник версий — Git
-- ✅ Работает с приватными серверами без доп. настроек
-
-#### Buf: «Сначала реестр»
-```yaml
-# buf.yaml — ссылки только на модули BSR
-version: v1
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpc/grpc
- - buf.build/envoyproxy/protoc-gen-validate
-```
-
-**Преимущества:**
-- ✅ Курируемые, проверенные модули
-- ✅ Богатые метаданные и документация
-- ✅ Визуализация графа зависимостей
-- ✅ Принуждение семантического версионирования
-
-**Ограничения:**
-- ❌ Нужно опубликовать в BSR перед использованием
-- ❌ Требует аккаунт и аутентификацию
-- ❌ Нельзя напрямую сослаться на произвольный Git репозиторий
-
-### 2. Корпоративные и изолированные (air‑gapped) среды
-
-#### EasyP: Полноценная оффлайн‑поддержка
-
-**Сценарий**: крупная компания со строгими сетевыми политиками
-
-```bash
-# 1. Среда с доступом в интернет
-easyp mod download # Скачивает в ~/.easyp/
-easyp mod vendor # Создает easyp_vendor/
-
-# 2. Перенос в изолированный сегмент
-tar -czf easyp-deps.tar.gz ~/.easyp easyp_vendor/
-# ... перенос архива ...
-
-# 3. В изолированной среде
-tar -xzf easyp-deps.tar.gz
-export EASYPPATH=$PWD/.easyp
-easyp generate # Работает оффлайн
-```
-
-**Плюсы:**
-- ✅ Не зависит от внешних сервисов
-- ✅ Не нужен внутренний реестр
-- ✅ Использует существующую Git инфраструктуру
-- ✅ Простая файловая дистрибуция
-
-#### Buf: Требует инфраструктуру реестра
-
-```bash
-# Вариант 1: использовать buf.build (нужен интернет)
-buf mod download
-
-# Вариант 2: поднимать приватный BSR (сложно)
-# - Развернуть сервер реестра
-# - Перепубликовать все модули внутрь
-# - Настроить доступы, аутентификацию
-# - Поддерживать работоспособность
-```
-
-**Минусы:**
-- ❌ Постоянный интернет или дорогой приватный BSR
-- ❌ Сложная инфраструктура для частных установок
-- ❌ Все модули нужно републиковать
-- ❌ Дополнительные операционные затраты
-
-### 3. Безопасность и контроль
-
-#### EasyP: Прямой контроль
-```yaml
-# Полный контроль источников
-deps:
- # Публичный репозиторий — ваша конкретная версия
- - github.com/googleapis/googleapis@common-protos-1_3_1
-
- # Внутренний репозиторий
- - gitlab.company.com/security/validated-protos@v1.0.0
-
- # Точный коммит (горячий фикс)
- - github.com/bufbuild/protoc-gen-validate@abc123def456
-```
-
-**Преимущества по безопасности:**
-- ✅ Нет посредника — берём из исходного репозитория
-- ✅ Аудит через историю Git
-- ✅ Нельзя «забанить» доступ извне
-- ✅ Свои процессы сканирования / валидации
-- ✅ Можно форкнуть и удерживать критические версии
-
-#### Buf: Зависимость от реестра
-```yaml
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpc/grpc
-```
-
-**Риски:**
-- ⚠️ Посредник контролирует доступность
-- ⚠️ Возможны ограничения / санкции на аккаунт
-- ⚠️ Модуль могут удалить или депрекейтнуть
-- ⚠️ Политики обновлений диктуются стороной
-- ⚠️ Нужно доверять внешней безопасности
-
-### 4. Реальные сценарии
-
-#### Сценарий 1: Стартап с публичными зависимостями
-
-**EasyP:**
-```yaml
-deps:
- - github.com/googleapis/googleapis
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
-```
-
-**Buf:**
-```yaml
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpcecosystem/grpc-gateway
-```
-
-**Итог:** Паритет — оба хорошо подходят для публичных пакетов.
-
-#### Сценарий 2: Компания со смешанными публичными/приватными зависимостями
-
-**EasyP:**
-```yaml
-deps:
- - github.com/googleapis/googleapis@v1.2.3
- - github.com/mycompany/auth-protos@v2.0.0
- - gitlab.enterprise.com/platform/shared-types@v1.5.1
-```
-
-**Buf:**
-```yaml
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/mycompany/auth-protos
- - buf.build/mycompany/shared-types
-```
-
-**Итог:** **EasyP** — не требует публикации внутрь BSR.
-
-#### Сценарий 3: Государственный / оборонный подрядчик (полный air‑gap)
-
-**EasyP:**
-```bash
-easyp mod vendor
-# Архив → перенос → распаковка → generate (без сети)
-```
-
-**Buf:**
-```bash
-# Нужен приватный BSR с поддержкой полного оффлайна
-# Сложный цикл публикации и обслуживания
-```
-
-**Итог:** **EasyP** — значительно проще.
-
-#### Сценарий 4: Комплаенс и аудит
-
-**EasyP:**
-- ✅ Прямой аудит изменений (коммиты)
-- ✅ Нет внешних точек зависимости в проде
-- ✅ Повторяемость через фиксированные коммиты / vendor
-- ✅ Управление уязвимостями — в ваших руках
-
-**Buf:**
-- ⚠️ Нужно учитывать BSR в области аудита
-- ⚠️ Дополнительный риск третьей стороны
-- ⚠️ Модули — внешние контролируемые артефакты
-- ⚠️ Сложнее трассировать от реестра к исходникам
-
-**Итог:** **EasyP** — проще для комплаенса.
-
-### 5. Стоимость и инфраструктура
-
-#### EasyP: Нулевая дополнительная инфраструктура
-
-**Затраты:**
-- ✅ $0 — используете существующий Git
-- ✅ Нет дополнительных сервисов/серверов
-- ✅ Нет лицензирования
-- ✅ Масштабирование в рамках Git
-
-**Инфраструктура:**
-- Использует текущие репозитории (GitHub/GitLab/и т.д.)
-- Аутентификация — штатная
-- Резервирование/DR — как уже настроено для Git
-
-#### Buf: Затраты на реестр
-
-**Hosted BSR (buf.build):**
-- ✅ Бесплатный уровень
-- ❌ Платные тарифы для приватного и расширенного использования
-- ❌ Потенциальные изменения ценовой политики
-- ❌ Вопросы локализации данных
-
-**Приватный BSR:**
-- ❌ Серверы, БД, балансировка
-- ❌ Мониторинг, обновления, бэкапы
-- ❌ Лицензирование enterprise функционала
-- ❌ Доп. планирование отказоустойчивости
-
-### 6. Миграция и lock‑in
-
-#### EasyP: Нет привязки
-
-**Миграция ИЗ EasyP:**
-```yaml
-deps:
- - github.com/googleapis/googleapis@v1.2.3
-```
-(Обычные Git ссылки — легко перенести в другой инструмент.)
-
-**Миграция В EasyP:**
-```bash
-# Просто указываете те же Git репозитории
-```
-
-#### Buf: Потенциальный lock‑in
-
-**Миграция ИЗ Buf:**
-- ❌ Нужно сопоставить BSR модули с исходными Git репо
-- ❌ Имена модулей BSR не совпадают с URL
-- ❌ Возможна потеря удобных метаданных
-- ❌ Сложно при глубокой интеграции с BSR
-
-**Миграция В Buf:**
-- ❌ Нужно опубликовать всё в BSR
-- ❌ Нельзя ссылаться напрямую на Git
-- ❌ Принять workflow BSR (push/pull модулей)
-
-## Когда выбирать каждое решение
-
-### Выберите EasyP, если:
-
-✅ **Air‑gapped / закрытые среды**
-- Нужна работа без внешних сервисов
-- Строгий комплаенс / контроль цепочки поставок
-
-✅ **Фокус на безопасности**
-- Контроль источников зависимостей
-- Минимизация рисков третьих сторон
-
-✅ **Git‑центричная культура**
-- Частные репозитории — норма
-- Не хотите добавлять новый ключевой сервис
-
-✅ **Ограниченный бюджет**
-- Минимизация операционных расходов
-- Предсказуемая стоимость = 0
-
-✅ **Смешанные публичные/частные зависимости**
-- Не хотите перекладывать всё в реестр
-- Нужна гибкость форматов и размещения
-
-### Выберите Buf, если:
-
-✅ **Глубокая интеграция в экосистему BSR**
-- Уже используете линтеры / генерацию Buf
-- Нужны курируемые официальные модули
-- Важны метаданные и граф зависимостей
-
-✅ **Сотрудничество и открытая разработка**
-- Централизованное обнаружение модулей
-- Совместная работа над общими пакетами
-
-✅ **Команда новичков в protobuf**
-- Требуется «направляющая» структура
-- Ценность документации внутри реестра
-
-✅ **Небольшой набор публичных зависимостей**
-- В основном используете популярные общие пакеты
-- Вас устраивает зависимость от BSR
-
-## Пути миграции
-
-### Переход с Buf на EasyP
-
-1. Найдите исходные Git репозитории для каждого модуля BSR
-2. Сопоставьте имена BSR → Git ссылки (с версиями/тегами)
-3. Обновите конфигурацию (`easyp.yaml`)
-4. Протестируйте генерацию и совместимость
-
-```yaml
-# Было (buf.yaml)
-deps:
- - buf.build/googleapis/googleapis
- - buf.build/grpc/grpc
-
-# Стало (easyp.yaml)
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1
- - github.com/grpc/grpc@v1.50.0
-```
-
-### Переход с EasyP на Buf
-
-1. Опубликуйте используемые репозитории как модули BSR
-2. Настройте аутентификацию / организацию Buf
-3. Замените Git ссылки на BSR модули
-4. Перейдите к push/pull workflow Buf
-
-## Заключение
-
-Оба инструмента решают задачу управления зависимостями protobuf, но подходят под разные приоритеты:
-
-**Сильные стороны EasyP:**
-- Корпоративные / изолированные среды
-- Жёсткие требования безопасности и аудита
-- Минимальные затраты и отсутствие доп. инфраструктуры
-- Прямое использование Git (без промежуточного слоя)
-- Простота масштабирования
-
-**Сильные стороны Buf:**
-- Богатая экосистема вокруг реестра
-- Курируемые и документированные модули
-- Удобство для новых команд в protobuf
-- Средства визуализации и централизованного обмена
-
-Выбор часто сводится к балансу между **контролем vs. удобством**, **безопасностью vs. централизованными функциями**, и **стоимостью vs. managed‑сервисом**.
-
-Для большинства enterprise‑окружений децентрализованный Git‑подход EasyP обеспечивает нужные гибкость, безопасность и предсказуемость расходов, тогда как Buf отлично подходит командам, которым важна централизованная коллаборация и богатая экосистема вокруг реестра.
+После mod tidy команда mod vendor может скопировать .proto зафиксированной Git-зависимости в easyp_vendor, используя корни из её конфигурации Buf. Подробнее — в [руководстве менеджера пакетов](/ru/docs/cli/package-manager).
diff --git a/content/docs/cli/package-manager/index.mdx b/content/docs/cli/package-manager/index.mdx
index 2b77bc9..08c2381 100644
--- a/content/docs/cli/package-manager/index.mdx
+++ b/content/docs/cli/package-manager/index.mdx
@@ -1,554 +1,107 @@
---
title: "Package Manager"
+description: "Resolve and lock Git-based protobuf dependencies in EasyP v1."
---
-[[toc]]
-
-EasyP provides a powerful package manager for protobuf dependencies that simplifies dependency management through a decentralized, Git-based approach. Unlike centralized solutions, EasyP works directly with Git repositories, giving you complete control over your dependencies.
-
-## Overview
-
-The EasyP package manager follows the **Go modules philosophy** - any Git repository can serve as a package source. This approach provides several key advantages:
-
-- **Decentralized**: No single point of failure or control
-- **Security**: Direct access to source repositories
-- **Flexibility**: Support for public, private, and enterprise repositories
-- **Reproducibility**: Lock files ensure consistent builds across environments
-- **Performance**: Local caching minimizes network requests
-
-### Key Features
-
-| Feature | Description |
-|---------|-------------|
-| **Git-Native** | Works with any Git repository - no special server required |
-| **Multiple Version Formats** | Tags, commits, pseudo-versions, latest |
-| **Lock Files** | Reproducible builds with `easyp.lock` |
-| **Local Caching** | Go modules-style cache architecture |
-| **Vendoring Support** | Copy dependencies locally for offline builds |
-| **YAML Configuration** | Simple, readable dependency declarations |
-
-## Architecture
-
-EasyP uses a two-tier caching system inspired by Go modules:
-
-```
-~/.easyp/
-├── cache/
-│ ├── download/ # Downloaded archives + checksums
-│ │ └── github.com/
-│ │ └── googleapis/
-│ │ └── googleapis/
-│ │ ├── v1.2.3.zip # Archive
-│ │ ├── v1.2.3.ziphash # Checksum
-│ │ └── v1.2.3.info # Metadata
-│ └── {git-hash}/ # Git bare repositories (internal)
-└── mod/ # Extracted, ready-to-use modules
- └── github.com/
- └── googleapis/
- └── googleapis/
- ├── v1.2.3/ # Tagged version
- │ ├── google/
- │ │ ├── api/
- │ │ └── rpc/
- │ └── ...
- └── v0.0.0-20250101123456-abc123def/ # Pseudo-version
- ├── google/
- └── ...
-```
-
-### Cache Location
-
-| Environment | Location | How to Set |
-|-------------|----------|------------|
-| **Default** | `$HOME/.easyp` | Automatic |
-| **Custom** | Any directory | Set `EASYPPATH` environment variable |
-| **CI/CD** | Project-relative | `export EASYPPATH=$CI_PROJECT_DIR/.easyp` |
-
-## Configuration
-
-### Basic Configuration
-
-Configure dependencies in your `easyp.yaml` file:
-
-```yaml
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
- - github.com/bufbuild/protoc-gen-validate
-```
-
-### Advanced Configuration Examples
-
-#### Multi-Environment Setup
-```yaml
-# development.easyp.yaml
-deps:
- - github.com/googleapis/googleapis # Latest for development
- - github.com/mycompany/internal-protos # Latest internal changes
- - github.com/bufbuild/protoc-gen-validate # Latest features
-
-# production.easyp.yaml
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1 # Pinned
- - github.com/mycompany/internal-protos@v2.1.0 # Stable release
- - github.com/bufbuild/protoc-gen-validate@v0.10.1 # Tested version
-```
-
-#### Private Repository Setup
-```yaml
-deps:
- # Public dependencies
- - github.com/googleapis/googleapis@common-protos-1_3_1
-
- # Private company repositories
- - github.com/mycompany/auth-protos@v1.5.0
- - github.com/mycompany/common-types@v2.0.1
-
- # Internal GitLab
- - gitlab.company.com/platform/messaging-protos@v0.3.0
-```
-
-## Versioning Strategies
-
-EasyP supports multiple versioning approaches to fit different development workflows:
-
-### 1. Semantic Version Tags (Recommended for Production)
-
-```yaml
-deps:
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
- - github.com/googleapis/googleapis@common-protos-1_3_1
-```
-
-**Use when:**
-- Production deployments
-- Stable API consumption
-- Reproducible builds required
-
-### 2. Latest Tag (Development)
-
-```yaml
-deps:
- - github.com/googleapis/googleapis # Uses latest available tag
- - github.com/bufbuild/protoc-gen-validate
-```
-
-**Use when:**
-- Active development
-- Want latest features
-- Compatibility testing
-
-### 3. Commit Hashes (Bleeding Edge)
-
-```yaml
-deps:
- - github.com/bufbuild/protoc-gen-validate@abc123def456789abcdef123456789abcdef1234
-```
-
-**Use when:**
-- Need unreleased features
-- Testing specific fixes
-- Contributing to upstream
+The v1 package manager reads protobuf.mod and writes protobuf.lock. It records each selected Git commit and an h1: content hash, then verifies the hash when downloading or reusing a cached module.
-### 4. Pseudo-Versions (Automatic)
+## Declare dependencies
-When EasyP can't find a suitable tag, it generates pseudo-versions automatically:
+~~~text
+module github.com/acme/contracts
+roots proto
-```
-Format: v0.0.0-{timestamp}-{short-commit-hash}
-Example: v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df
-```
+require (
+ github.com/acme/shared v1.2.0
+ github.com/acme/weather/v2 v2.1.0
+)
+~~~
-This ensures every commit can be referenced with a version-like identifier.
+roots defaults to .. SemVer requirements select the maximum requested minimum. A full 40- or 64-hex-character commit specifies an exact revision. A tag and SHA are compatible when the selected tag resolves to that same commit; different commits conflict. SHA values are not ordered as SemVer by date or Git ancestry.
-## Commands
-
-### `easyp mod download`
-
-Downloads and installs all dependencies declared in your configuration.
-
-**What happens:**
-1. **Resolves versions**: Converts tags/latest to specific commits
-2. **Downloads archives**: Stores `.zip` files in cache/download
-3. **Verifies checksums**: Ensures archive integrity
-4. **Extracts modules**: Unpacks to cache/mod with proper structure
-5. **Updates lock file**: Records exact versions and content hashes
-
-**Usage:**
-```bash
-# Use default easyp.yaml
-easyp mod download
-
-# Use custom config file
-easyp --cfg production.easyp.yaml mod download
-
-# With custom cache location
-EASYPPATH=/tmp/easyp-cache easyp mod download
-```
-
-**Example output:**
-```
-INFO Download package package=github.com/googleapis/googleapis version=v0.0.0-20250909114430 commit=8727b5ba
-INFO Install package package=github.com/googleapis/googleapis version=v0.0.0-20250909114430 commit=8727b5ba
-INFO Download package package=github.com/grpc-ecosystem/grpc-gateway version=v2.19.1 commit=a070de73
-INFO Install package package=github.com/grpc-ecosystem/grpc-gateway version=v2.19.1 commit=a070de73
-```
-
-### `easyp mod vendor`
-
-Copies all installed proto files to a local `easyp_vendor/` directory for offline usage.
-
-**Use cases:**
-- **Docker builds**: Avoid network dependencies in containers
-- **Air-gapped environments**: No internet access during builds
-- **Reproducible builds**: Bundle exact dependency versions
-- **Performance**: Eliminate network latency in repeated builds
-
-**Usage:**
-```bash
-easyp mod vendor
-```
-
-**Result structure:**
-```
-easyp_vendor/
-├── github.com/
-│ ├── googleapis/
-│ │ └── googleapis/
-│ │ ├── google/
-│ │ │ ├── api/
-│ │ │ │ ├── annotations.proto
-│ │ │ │ └── http.proto
-│ │ │ └── rpc/
-│ │ │ └── status.proto
-│ │ └── ...
-│ └── grpc-ecosystem/
-│ └── grpc-gateway/
-│ └── protoc-gen-openapiv2/
-│ └── options/
-│ └── annotations.proto
-```
-
-### `easyp mod update`
-
-Updates module versions based on current configuration and writes resolved versions to the lock file.
-
-**Behavior:**
-- Respects version constraints in `easyp.yaml`
-- Updates to latest compatible versions
-- Regenerates `easyp.lock` with new versions and hashes
-
-**Usage:**
-```bash
-easyp mod update
-```
-
-## Lock Files
-
-The `easyp.lock` file ensures reproducible builds by recording exact versions and content hashes:
-
-```
-github.com/bufbuild/protoc-gen-validate v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df h1:ZZ5JyUkmrj9OBHM+gOCzeL5L/pAKVbsUl051yhhJTjU=
-github.com/googleapis/googleapis v0.0.0-20250909114430-8727b5ba7f23fbbfddda58239e8bc6b547e05878 h1:eI+XYpPio3fxl9H5/VjW2PxlxM/7yqPjEq3oQ6jUkj4=
-github.com/grpc-ecosystem/grpc-gateway v2.19.1 h1:01NNlCezvwUQ07ZvblXH0kelWq8hNl2qb44bOMcaSTQ=
-```
-
-### Lock File Format
-
-Each line contains three components:
-- **Module path**: Full repository path
-- **Exact version**: Resolved version (tag or pseudo-version)
-- **Content hash**: SHA256 of extracted content (`h1:` prefix)
-
-### Best Practices
-
-✅ **Always commit `easyp.lock`** - Ensures team consistency
-✅ **Run `mod update` deliberately** - Don't auto-update in CI
-✅ **Review lock changes** - Understand what's being updated
-❌ **Don't edit manually** - Let EasyP manage the format
-
-## Authentication
-
-### Public Repositories
-
-No setup required - works out of the box:
-
-```yaml
-deps:
- - github.com/googleapis/googleapis
- - github.com/bufbuild/protoc-gen-validate
-```
-
-### Private Repositories
-
-#### SSH Keys (Recommended)
+A versionless requirement adds no constraint when the graph supplies a SemVer or exact commit. Only a still-unconstrained requirement uses current HEAD on the first mod tidy; subsequent tidy runs preserve the lock pin, while mod update refreshes HEAD. Explicit commits stay pinned.
-Configure Git to use SSH for GitHub/GitLab:
+replace module => ../local-copy applies only from the main protobuf.mod, including to transitive requirements. All relative replacement paths use the main manifest directory; absolute paths are used directly. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace).
-```bash
-# For GitHub
-git config --global url."git@github.com:".insteadOf "https://github.com/"
+A replacement applies only when its module is reached through direct or transitive requirements. An unused replacement is not read or fetched and cannot hide the consumer's sources from lint or breaking checks. Reached replacement trees supply imports during consumer checks; select one explicitly with --path to check its own policy. Frozen still rejects every replacement, including unused ones.
-# For GitLab
-git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/"
+For a Git repository with several manifests, require each nested module separately by its identity. For example, require repo/foo and require repo/bar need no module-specific tags if HEAD is suitable. A v1.2.3 release of the module in foo/ uses tag foo/v1.2.3. Each module's roots are resolved independently.
-# For custom domains
-git config --global url."git@gitlab.company.com:".insteadOf "https://gitlab.company.com/"
-```
+For a selected tag or commit, module identity, roots, and requirements come from that revision. A nested module remains usable even if its directory was deleted or replaced by a regular file at current HEAD. Native manifests must match the requested identity at the selected revision; invalid native metadata does not fall back to Buf or legacy EasyP, and a pinned revision is never replaced with HEAD.
-Then use normal HTTPS URLs in your config:
+Module commands and get find the nearest ancestor protobuf.mod within the workspace. easyp get <module> adds a direct requirement; @v1.2.3 or @<full-commit> selects a version. Without a suffix, the unconstrained-requirement rules above apply. Transitive requirements are added with // indirect, and repeated calls do not duplicate entries. Resolution errors leave the manifest and lock unchanged.
-```yaml
-deps:
- - github.com/mycompany/private-protos@v1.0.0
- - gitlab.company.com/platform/shared-types@v2.1.0
-```
+Major versions use Go-style identities: v0/v1 are unsuffixed; v2+ requires matching /vN. The +incompatible exception requires verified pre-native metadata; it never bypasses a native manifest. See [exact grammar and Git mapping](/docs/reference/protobuf-mod).
-#### Personal Access Tokens
-
-For HTTPS authentication:
-
-```bash
-# Method 1: Credential helper
-git config --global credential.helper store
-echo "https://username:token@github.com" >> ~/.git-credentials
-
-# Method 2: URL rewriting
-git config --global url."https://username:token@github.com/mycompany".insteadOf "https://github.com/mycompany"
-```
-
-#### Corporate Environments
-
-```bash
-# Configure proxy
-git config --global http.proxy http://proxy.company.com:8080
-git config --global https.proxy https://proxy.company.com:8080
-
-# Configure certificates for internal Git servers
-git config --global http.sslCAInfo /path/to/certificate.pem
-```
-
-## Common Workflows
-
-### Initial Project Setup
-
-```bash
-# 1. Create configuration
-cat > easyp.yaml << EOF
-deps:
- - github.com/googleapis/googleapis
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
-EOF
-
-# 2. Download dependencies
-easyp mod download
-
-# 3. Verify installation
-ls ~/.easyp/mod/github.com/googleapis/googleapis/
-```
-
-### Adding New Dependencies
-
-```bash
-# 1. Edit easyp.yaml
-echo " - github.com/bufbuild/protoc-gen-validate@v0.10.1" >> easyp.yaml
-
-# 2. Download new dependency
-easyp mod download
-
-# 3. Commit lock file changes
-git add easyp.lock
-git commit -m "Add protoc-gen-validate dependency"
-```
-
-### Updating Dependencies
-
-```bash
-# Update to latest compatible versions
-easyp mod update
-
-# Review changes
-git diff easyp.lock
-
-# Test with new versions
-easyp generate
-easyp lint
-
-# Commit if everything works
-git add easyp.lock
-git commit -m "Update dependencies"
-```
+## Commands
-### Offline Development
+| Command | Behavior |
+|---------|----------|
+| easyp get <module>[@version|@commit] | Adds or promotes a direct requirement, resolves transitive requirements, and writes protobuf.lock |
+| easyp mod tidy | Resolves direct and transitive requirements and writes protobuf.lock |
+| easyp mod download | Downloads the exact commits in protobuf.lock and verifies their hashes |
+| easyp mod update | Refreshes requirements within their current major versions, then updates the lock |
+| easyp mod vendor | Verifies locked dependencies and copies their .proto files into easyp_vendor |
-```bash
-# Vendor all dependencies
+~~~bash
+easyp get github.com/acme/contracts/proto/user
easyp mod vendor
-
-# Now your project works offline
easyp generate
-```
-
-## Troubleshooting
-
-### Common Issues
-
-#### "Repository not found" or "Authentication failed"
-
-**Problem**: Can't access private repository
-**Solution**: Check authentication setup
-
-```bash
-# Test Git access
-git ls-remote https://github.com/mycompany/private-repo
-
-# Check Git configuration
-git config --list | grep url
-```
-
-#### "Version not found"
-
-**Problem**: Specified tag/version doesn't exist
-**Solution**: Check available tags
+~~~
-```bash
-# List available tags
-git ls-remote --tags https://github.com/googleapis/googleapis
+Commit protobuf.mod and protobuf.lock for repeatable builds. The module cache is under $HOME/.easyp/v1/git by default; set EASYPPATH to change its parent directory. Without replacements, mod vendor uses the published lock. With replacements it snapshots the effective graph without writing that lock. Duplicate import paths are errors. The easyp_vendor directory is a copy of dependency sources, not a replacement for the lock.
-# Use existing tag or commit hash
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1 # Valid tag
-```
+## Immutable tags and cache reuse
-#### "Cache corruption" or "Checksum mismatch"
+tidy, get, and update verify each fetched previously locked SemVer against its recorded commit and hash. A republished tag raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock, including for transitive dependencies and warm caches. Selecting a new version and refreshing unconstrained HEAD requirements remain available.
-**Problem**: Corrupted cache files
-**Solution**: Clear cache and re-download
+mod download retrieves the locked commit even after a tag moves, if that commit remains available. Reused Git objects let known exact commits avoid remote access. A cold request first tries a depth-one fetch of the exact commit and falls back to reachable history when needed; it never substitutes HEAD. Tag lookups are refreshed separately, and installed contents remain hash-verified.
-```bash
-# Clear everything
-rm -rf ~/.easyp
+## Dependencies using Buf or older EasyP
-# Or clear just downloads
-rm -rf ~/.easyp/cache/download
+A Git dependency may declare its proto roots in buf.work.yaml, Buf v1 or v2 buf.yaml, or an older EasyP easyp.yaml. Older EasyP protobuf.mod requirements are also read transitively. If none of those files exists, its repository root is used. This compatibility applies to dependency metadata; the consuming project uses v1 protobuf.mod.
-# Re-download
-easyp mod download
-```
+When adapting an older easyp.yaml, both deps and generation Git inputs contribute requirements. Exact source/version duplicates are removed; different minimums remain visible to MVS, and malformed deps fail explicitly. A matching native protobuf.mod takes precedence. Only metadata is read; dependency plugins are never executed.
-#### Network timeouts
+EasyP reads Buf v1, v1beta1, and v2 deps, including declarations in modules selected through buf.work.yaml. The current compatibility resolver maps known BSR modules to fixed Git snapshots: Googleapis, grpc-gateway, grpc-federation, protoc-gen-validate, and protovalidate. Unknown BSR modules fail explicitly; EasyP does not guess a Git repository from their name. A native protobuf.mod takes precedence, and direct BSR requirements in the consumer's manifest are not supported.
-**Problem**: Slow or unreliable network
-**Solution**: Configure Git timeouts
+The lock preserves the original BSR reference and pin alongside the Git binding. Resolution reports compatibility_snapshot: the fixed Git source is hash-verified, but this is not proof of equivalence to an arbitrary BSR revision or verification of its BSR digest. Frozen builds reuse the recorded bindings. Regenerate older locks with mod tidy outside frozen when a dependency declares BSR inputs.
-```bash
-# Increase timeout
-git config --global http.lowSpeedLimit 1000
-git config --global http.lowSpeedTime 300
+Buf v1/v1beta1 build.excludes and v2 modules[].includes/excludes select files without changing their import paths. Paths are relative to the declaring buf.yaml; nested workspace configs retain that base. Overlapping roots in one Buf module configuration select the union of their allowed files.
-# Use proxy if available
-git config --global http.proxy http://proxy.company.com:8080
-```
+The same selection applies to imports, dependency generation and package selection, file listing, lint and breaking contexts, collision checks, and vendoring. Excluded files stay unavailable through symlink aliases or a broad consumer root, whether the excluded path is the alias or its physical target. An excluded dependency file does not conflict with an allowed consumer file at the same import path.
-### Performance Optimization
+See [protobuf.mod](/docs/reference/protobuf-mod) and [protobuf.lock](/docs/reference/protobuf-lock) for their field-level formats.
-#### For Large Teams
+## Reachable imports and direct requirements
-```bash
-# Use shared cache server (if available)
-export EASYPPATH=/shared/easyp-cache
+Before writing a new manifest or lock, mod tidy checks the import closure reachable from the local module, including imports inside dependency files. Missing files and invalid reachable protobuf syntax stop the operation. Unrelated files in a dependency are not all compiled or linted. An import under google/protobuf/ must actually exist; the prefix alone does not make it a bundled file.
-# Or use team-specific cache
-export EASYPPATH=/team-cache/easyp
-```
+When a local source starts importing a previously indirect module, tidy removes the existing // indirect marker while preserving its version and unrelated comments. This does not discover an arbitrary Git repository from an unknown proto path. Registry-specific Buf dependency identities still require explicit Git mapping and are not silently converted into repository URLs.
-#### For CI/CD Systems
+## Frozen builds
-```bash
-# Use project-relative cache
-export EASYPPATH=$CI_PROJECT_DIR/.easyp
+Commit protobuf.mod and protobuf.lock, then opt into --frozen explicitly. Even a module with no dependencies needs an empty lock; a source directory without a native manifest is rejected. CI=true does not enable this mode.
-# Cache between builds (GitLab CI example)
-cache:
- key: easyp-$CI_COMMIT_REF_SLUG
- paths:
- - .easyp/
-```
+~~~bash
+# Prepare and review the lock outside frozen mode
+easyp mod tidy
+# Use the committed graph; exact-commit cache fills are allowed
+easyp mod download --frozen
+easyp --frozen generate
+easyp mod --frozen vendor
+~~~
-#### Cache Size Management
+Global, mod-level, and leaf-command placement are supported. A true value anywhere in the command lineage stays enabled even if a child passes --frozen=false. See [all supported placements](/docs/cli/configuration#explicit-frozen-mode).
-```bash
-# Check cache usage
-du -sh ~/.easyp
-du -sh ~/.easyp/cache/download # Archives only
-du -sh ~/.easyp/mod # Extracted modules
+Frozen rejects every root replace before accessing its path or fetching dependencies, including unused replacements. It verifies the manifest's direct requirements and the locked modules' transitive requirements; missing, invalid, incomplete, or stale locks fail instead of being repaired. Dependencies selected by identity use the consumer's manifest and lock and do not need their own lock files. Explicit workspace-relative generation module paths instead use the selected native module's manifest and lock; a generator-only directory needs no separate pair. Dependency-local replacement directives remain ignored.
-# Clean old versions (manual)
-find ~/.easyp/mod -type d -name "v0.0.0-*" -mtime +30 -exec rm -rf {} \;
-```
+There is no dependency re-resolution, HEAD/tag lookup, or manifest/lock creation or rewriting. Missing cache entries may be fetched at their exact locked commits. Content hashes are verified on cold and warm caches; corrupted installed contents fail rather than silently replacing the recorded hash. Frozen is not offline, and remote plugins can still need network access.
-## Integration Examples
+mod download installs the verified graph. mod vendor validates it before writing easyp_vendor. mod tidy, get, mod update, init, and migrate refuse frozen execution, including migration preview. Remove replacements and prepare the manifest/lock outside frozen mode. The normal local replacement and vendor behavior above is unchanged.
-### Docker Multi-stage Build
+## Cache and revision-access errors
-```dockerfile
-# Stage 1: Download dependencies
-FROM ghcr.io/easyp-tech/easyp:latest AS deps
-WORKDIR /workspace
-COPY easyp.yaml easyp.lock ./
-RUN easyp mod vendor
+A hash mismatch in an installed module identifies the exact cache directory. Preserve it for investigation or quarantine only that entry, then retry easyp mod download. Do not rewrite protobuf.lock to hide the mismatch; the command does not automatically delete or repair the cache.
-# Stage 2: Build application
-FROM alpine:latest AS build
-WORKDIR /app
-COPY --from=deps /workspace/easyp_vendor ./easyp_vendor
-COPY . .
-# Use vendored dependencies for generation
-RUN easyp generate
-```
-
-### Monorepo Structure
-
-```
-my-monorepo/
-├── services/
-│ ├── auth-service/
-│ │ └── easyp.yaml # Service-specific deps
-│ └── user-service/
-│ └── easyp.yaml # Different deps
-├── shared/
-│ └── common-protos/ # Internal protos
-└── easyp.yaml # Global/shared deps
-```
-
-Each `easyp.yaml` can have different dependencies based on service needs.
-
-## Best Practices
-
-### Development Workflow
-- ✅ Use **latest tags** during active development
-- ✅ **Pin versions** for production deployments
-- ✅ **Commit lock files** to ensure reproducibility
-- ✅ **Review dependency updates** before merging
-- ✅ **Test after updates** to catch compatibility issues
-
-### Security
-- ✅ **Pin to specific versions** in production
-- ✅ **Use SSH keys** for private repositories
-- ✅ **Review new dependencies** for security implications
-- ✅ **Monitor for vulnerabilities** in dependencies
-- ❌ **Don't embed credentials** in configuration files
-
-### Performance
-- ✅ **Cache aggressively** in CI/CD systems
-- ✅ **Use vendoring** for frequently rebuilt projects
-- ✅ **Clean old cache** periodically to save space
-- ✅ **Use shared cache** for team environments
-
-### Team Collaboration
-- ✅ **Document authentication setup** for new team members
-- ✅ **Use consistent tooling** across environments
-- ✅ **Automate dependency updates** with proper testing
-- ✅ **Share cache locations** when possible
-
-The EasyP package manager provides a robust, decentralized solution for protobuf dependency management that scales from individual projects to enterprise environments while maintaining the simplicity and reliability developers expect.
+An inaccessible Git repository is not evidence that a tag is absent. If history was fetched but the pinned commit is unavailable, restore access to the original revision instead of substituting HEAD. Tag revalidation and integrity checks remain enabled; no automatic offline fallback is introduced.
diff --git a/content/docs/cli/package-manager/index.ru.mdx b/content/docs/cli/package-manager/index.ru.mdx
index 653b7bc..de14f1a 100644
--- a/content/docs/cli/package-manager/index.ru.mdx
+++ b/content/docs/cli/package-manager/index.ru.mdx
@@ -1,460 +1,107 @@
---
title: "Менеджер пакетов"
+description: "Разрешение и фиксация Git-зависимостей protobuf в EasyP v1."
---
-[[toc]]
-
-EasyP предоставляет мощный менеджер пакетов для protobuf‑зависимостей, упрощающий их управление за счёт децентрализованного подхода на базе Git. В отличие от централизованных решений, EasyP работает напрямую с Git‑репозиториями, давая вам полный контроль.
-
-## Обзор
-
-Менеджер пакетов EasyP следует философии **Go modules** — любой Git‑репозиторий может быть источником. Это даёт преимущества:
-
-- **Децентрализация** — нет единой точки отказа или контроля
-- **Безопасность** — прямой доступ к исходникам
-- **Гибкость** — публичные, приватные и корпоративные репозитории
-- **Воспроизводимость** — lock‑файлы обеспечивают одинаковые сборки
-- **Производительность** — локальный кеш сокращает сетевые запросы
-
-### Основные возможности
-
-| Возможность | Описание |
-|-------------|----------|
-| **Git-Native** | Любой Git репозиторий, не нужен спец‑сервер |
-| **Множество форматов версий** | Теги, коммиты, псевдо‑версии, latest |
-| **Lock Files** | Воспроизводимые сборки через `easyp.lock` |
-| **Локальный кеш** | Архитектура как у Go modules |
-| **Vendoring** | Локальное копирование для оффлайн сборок |
-| **YAML конфигурация** | Простые и читаемые декларации |
-
-## Архитектура
-
-EasyP использует двухуровневый кеш, вдохновлённый Go modules:
-
-```
-~/.easyp/
-├── cache/
-│ ├── download/ # Архивы + контрольные суммы
-│ │ └── github.com/
-│ │ └── googleapis/
-│ │ └── googleapis/
-│ │ ├── v1.2.3.zip # Архив
-│ │ ├── v1.2.3.ziphash # Checksum
-│ │ └── v1.2.3.info # Метаданные
-│ └── {git-hash}/ # Bare репозитории Git (внутренне)
-└── mod/ # Распакованные готовые модули
- └── github.com/
- └── googleapis/
- └── googleapis/
- ├── v1.2.3/ # Тегированная версия
- │ ├── google/
- │ │ ├── api/
- │ │ └── rpc/
- │ └── ...
- └── v0.0.0-20250101123456-abc123def/ # Псевдо‑версия
- ├── google/
- └── ...
-```
-
-### Расположение кеша
-
-| Окружение | Путь | Как задать |
-|-----------|------|-----------|
-| **По умолчанию** | `$HOME/.easyp` | Автоматически |
-| **Свое** | Любая директория | Переменная `EASYPPATH` |
-| **CI/CD** | В каталоге проекта | `export EASYPPATH=$CI_PROJECT_DIR/.easyp` |
-
-## Конфигурация
-
-### Базовая конфигурация
-
-Зависимости описываются в `easyp.yaml`:
-
-```yaml
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
- - github.com/bufbuild/protoc-gen-validate
-```
-
-### Расширенные примеры
-
-#### Multi-Environment Setup
-```yaml
-# development.easyp.yaml
-deps:
- - github.com/googleapis/googleapis # Последнее для разработки
- - github.com/mycompany/internal-protos # Внутренние изменения
- - github.com/bufbuild/protoc-gen-validate # Новые фичи
-
-# production.easyp.yaml
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1 # Зафиксировано
- - github.com/mycompany/internal-protos@v2.1.0 # Стабильно
- - github.com/bufbuild/protoc-gen-validate@v0.10.1 # Проверено
-```
-
-#### Приватные репозитории
-```yaml
-deps:
- # Публичное
- - github.com/googleapis/googleapis@common-protos-1_3_1
-
- # Частные
- - github.com/mycompany/auth-protos@v1.5.0
- - github.com/mycompany/common-types@v2.0.1
-
- # Внутренний GitLab
- - gitlab.company.com/platform/messaging-protos@v0.3.0
-```
-
-## Стратегии версионирования
-
-Поддерживаются разные способы фиксации версий:
-
-### 1. Семантические теги (для продакшена)
-
-```yaml
-deps:
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
- - github.com/googleapis/googleapis@common-protos-1_3_1
-```
-
-**Используйте когда:**
-- Продакшен
-- Стабильное потребление API
-- Нужна воспроизводимость
-
-### 2. Последний тег (development)
-
-```yaml
-deps:
- - github.com/googleapis/googleapis
- - github.com/bufbuild/protoc-gen-validate
-```
-
-**Подходит для:**
-- Активной разработки
-- Получения свежих возможностей
-- Тестирования совместимости
-
-### 3. Хеш коммита (Bleeding Edge)
-
-```yaml
-deps:
- - github.com/bufbuild/protoc-gen-validate@abc123def456789abcdef123456789abcdef1234
-```
-
-**Когда нужно:**
-- Нерелизные фичи
-- Тест конкретного фикса
-- Вклад в upstream
+Менеджер пакетов v1 читает protobuf.mod и записывает protobuf.lock. Для каждого выбранного модуля lock содержит точный Git-коммит и хеш содержимого h1:. Хеш проверяется при скачивании и повторном использовании кеша.
-### 4. Псевдо‑версии (автоматически)
+## Объявление зависимостей
-Если нет подходящего тега — создаётся псевдо‑версия:
+~~~text
+module github.com/acme/contracts
+roots proto
-```
-Формат: v0.0.0-{timestamp}-{short-commit-hash}
-Пример: v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df
-```
+require (
+ github.com/acme/shared v1.2.0
+ github.com/acme/weather/v2 v2.1.0
+)
+~~~
-## Команды
-
-### `easyp mod download`
-
-Скачивает и устанавливает все объявленные зависимости.
-
-**Что делает:**
-1. Разрешает версии (теги → коммиты)
-2. Скачивает архивы в `cache/download`
-3. Проверяет контрольные суммы
-4. Распаковывает в `cache/mod`
-5. Обновляет `easyp.lock`
-
-**Пример:**
-```bash
-easyp mod download
-easyp --cfg production.easyp.yaml mod download
-EASYPPATH=/tmp/easyp-cache easyp mod download
-```
+Если roots не указан, используется .. SemVer-требования выбирают максимум запрошенных минимумов. Полный хеш коммита из 40 или 64 hex-символов задаёт точную ревизию. Тег и SHA совместимы, если выбранный тег разрешается в этот же коммит; разные коммиты конфликтуют. SHA не получает SemVer-порядка по дате или истории Git.
-### `easyp mod vendor`
-
-Копирует все proto зависимости в локальный `easyp_vendor/` для оффлайна.
-
-**Сценарии:**
-- Docker сборки
-- Air-gapped окружения
-- Воспроизводимость
-- Ускорение
-
-```bash
-easyp mod vendor
-```
+Требование без версии не ограничивает выбор, если в графе есть SemVer или точный коммит. Только оставшееся неограниченным требование использует текущий HEAD при первом mod tidy; следующие tidy сохраняют lock, а mod update освежает HEAD. Явные коммиты остаются закреплёнными.
-Структура:
-```
-easyp_vendor/
-├── github.com/
-│ ├── googleapis/
-│ │ └── googleapis/
-│ │ ├── google/
-│ │ │ ├── api/
-│ │ │ │ ├── annotations.proto
-│ │ │ │ └── http.proto
-│ │ │ └── rpc/
-│ │ │ └── status.proto
-│ │ └── ...
-│ └── grpc-ecosystem/
-│ └── grpc-gateway/
-│ └── protoc-gen-openapiv2/
-│ └── options/
-│ └── annotations.proto
-```
+replace module => ../local-copy применяется только из главного protobuf.mod, в том числе к транзитивным требованиям. Все относительные пути замены считаются от главного манифеста; абсолютные используются напрямую. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace).
-### `easyp mod update`
+Замена применяется, только если модуль достижим через прямые или транзитивные требования. Неиспользуемая замена не читается и не скачивается и не может скрыть исходники потребителя от lint или breaking. При проверке потребителя достижимые деревья замен предоставляют импорты; явно выберите замену через --path, чтобы проверить её собственную политику. Frozen по-прежнему отклоняет все замены, включая неиспользуемые.
-Обновляет версии согласно `easyp.yaml`, пересоздаёт lock.
+Если в Git-репозитории несколько манифестов, объявляйте каждый вложенный модуль отдельно по его имени. Например, require repo/foo и require repo/bar не требуют отдельных тегов, если HEAD подходит. Для релиза v1.2.3 модуля в foo/ используется тег foo/v1.2.3. Корни каждого модуля разрешаются независимо.
-```bash
-easyp mod update
-```
+Для выбранного тега или коммита идентичность модуля, корни и требования читаются из этой ревизии. Вложенный модуль остаётся доступным, даже если на текущем HEAD его каталог удалён или заменён обычным файлом. Нативный манифест в выбранной ревизии должен соответствовать запрошенному модулю; некорректные native-метаданные не заменяются Buf или старым EasyP, а вместо закреплённой ревизии никогда не используется HEAD.
-## Lock файл
+Команды mod и get находят ближайший protobuf.mod в предках в пределах workspace. easyp get <модуль> добавляет прямое требование; @v1.2.3 или @<полный-коммит> задаёт версию. Без суффикса применяется описанное выше неограниченное требование. Транзитивные требования дописываются с // indirect, повторный вызов не создаёт дубликаты. При ошибке разрешения манифест и lock не меняются.
-`easyp.lock` фиксирует точные версии и хеш содержимого:
+Мажорные версии используют идентичность как в Go: v0/v1 — без суффикса, v2+ — с соответствующим /vN. Исключение +incompatible требует проверки домодульных метаданных и не обходит нативный manifest. См. [точную грамматику и Git mapping](/ru/docs/reference/protobuf-mod).
-```
-github.com/bufbuild/protoc-gen-validate v0.0.0-20250908104020-660ec2d64e07f2fa8947527443af058b3d7169df h1:ZZ5JyUkmrj9OBHM+gOCzeL5L/pAKVbsUl051yhhJTjU=
-github.com/googleapis/googleapis v0.0.0-20250909114430-8727b5ba7f23fbbfddda58239e8bc6b547e05878 h1:eI+XYpPio3fxl9H5/VjW2PxlxM/7yqPjEq3oQ6jUkj4=
-github.com/grpc-ecosystem/grpc-gateway v2.19.1 h1:01NNlCezvwUQ07ZvblXH0kelWq8hNl2qb44bOMcaSTQ=
-```
-
-**Формат строки:**
-- Путь модуля
-- Версия (тег или псевдо)
-- Хеш содержимого (`h1:`)
-
-**Практики:**
-✅ Коммитить `easyp.lock`
-✅ Осознанно обновлять `mod update`
-✅ Ревью изменений версий
-❌ Не редактировать вручную
+## Команды
-## Аутентификация
+| Команда | Поведение |
+|---------|-----------|
+| easyp get <модуль>[@версия|@коммит] | Добавляет или делает прямой зависимостью модуль, разрешает транзитивные зависимости и записывает protobuf.lock |
+| easyp mod tidy | Разрешает прямые и транзитивные требования и записывает protobuf.lock |
+| easyp mod download | Скачивает точные коммиты из lock и проверяет хеши |
+| easyp mod update | Обновляет требования в пределах текущих мажорных версий и пересоздаёт lock |
+| easyp mod vendor | Проверяет зафиксированные зависимости и копирует их .proto в easyp_vendor |
-### Публичные репозитории
+~~~bash
+easyp get github.com/acme/contracts/proto/user
+easyp mod vendor
+easyp generate
+~~~
-Работают без настроек:
+Храните protobuf.mod и protobuf.lock в репозитории для воспроизводимой сборки. Кеш по умолчанию расположен в $HOME/.easyp/v1/git; переменная EASYPPATH меняет его родительский каталог. Без замен mod vendor использует опубликованный lock. С заменами он копирует эффективный граф без изменения lock. Повторяющиеся import path отклоняются. Каталог easyp_vendor — копия исходников зависимостей, а не замена lock-файла.
-```yaml
-deps:
- - github.com/googleapis/googleapis
- - github.com/bufbuild/protoc-gen-validate
-```
+## Неизменность тегов и повторное использование кеша
-### Приватные репозитории
+tidy, get и update сверяют каждый повторно полученный зафиксированный SemVer с записанными коммитом и хешем. Перепубликованный тег вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock, в том числе для транзитивных зависимостей и прогретого кеша. Выбор новой версии и обновление неограниченных HEAD-требований остаются доступны.
-#### SSH ключи (рекомендуется)
+mod download получает коммит из lock даже после переноса тега, если он доступен. Кеш повторно использует Git-объекты: известный точный коммит не требует обращения к remote. Холодный запрос сначала пробует загрузку точного коммита с глубиной один, затем при необходимости доступную историю; HEAD вместо коммита не подставляется. Проверки тегов обновляются отдельно, а установленные файлы по-прежнему проверяются по хешу.
-```bash
-git config --global url."git@github.com:".insteadOf "https://github.com/"
-git config --global url."git@gitlab.com:".insteadOf "https://gitlab.com/"
-git config --global url."git@gitlab.company.com:".insteadOf "https://gitlab.company.com/"
-```
+## Зависимости на Buf или старом EasyP
-Конфиг остаётся с HTTPS URL:
+Git-зависимость может объявлять корни .proto через buf.work.yaml, Buf v1/v2 buf.yaml или старый EasyP easyp.yaml. Транзитивные требования из старого EasyP protobuf.mod также читаются. Если ни одного такого файла нет, корнем считается каталог репозитория. Совместимость относится к метаданным зависимости; проект-потребитель использует v1 protobuf.mod.
-```yaml
-deps:
- - github.com/mycompany/private-protos@v1.0.0
- - gitlab.company.com/platform/shared-types@v2.1.0
-```
+При адаптации старого easyp.yaml требования берутся и из deps, и из Git-входов генерации. Точные дубликаты источник/версия удаляются, разные минимумы сохраняются для MVS; некорректные deps вызывают ошибку. Совпадающий нативный protobuf.mod имеет приоритет. Читаются только метаданные, плагины зависимости не запускаются.
-#### Personal Access Tokens
+EasyP читает deps Buf v1, v1beta1 и v2, включая объявления в модулях, выбранных через buf.work.yaml. Текущий resolver совместимости сопоставляет известные BSR-модули с фиксированными Git-снимками: Googleapis, grpc-gateway, grpc-federation, protoc-gen-validate и protovalidate. Неизвестный BSR-модуль вызывает явную ошибку; EasyP не угадывает Git-репозиторий по имени. Нативный protobuf.mod имеет приоритет; прямые BSR-требования в манифесте потребителя не поддерживаются.
-```bash
-git config --global credential.helper store
-echo "https://username:token@github.com" >> ~/.git-credentials
+Lock сохраняет исходную BSR-ссылку и pin вместе с Git-привязкой. Разрешение сообщает compatibility_snapshot: хеш Git-исходников проверяется, но это не доказательство эквивалентности произвольной BSR-ревизии и не проверка её BSR digest. Frozen использует сохранённые привязки. Старые lock-файлы для зависимостей с BSR-объявлениями пересоздайте через mod tidy вне frozen.
-git config --global url."https://username:token@github.com/mycompany".insteadOf "https://github.com/mycompany"
-```
+Buf v1/v1beta1 build.excludes и v2 modules[].includes/excludes выбирают файлы без изменения import path. Пути считаются от объявляющего buf.yaml; вложенные конфиги workspace сохраняют эту базу. Пересекающиеся корни одного Buf-конфига выбирают объединение разрешённых файлов.
-#### Корпоративная среда
+Тот же отбор действует для импортов, генерации зависимостей и выбора пакетов, списка файлов, контекстов lint и breaking, проверки коллизий и vendoring. Исключённый файл нельзя вернуть через symlink или широкий корень потребителя: учитывается как путь ссылки, так и её физическая цель. Исключённый файл зависимости не конфликтует с разрешённым файлом потребителя по тому же import path.
-```bash
-git config --global http.proxy http://proxy.company.com:8080
-git config --global https.proxy https://proxy.company.com:8080
-git config --global http.sslCAInfo /path/to/certificate.pem
-```
+Форматы полей описаны в справочниках [protobuf.mod](/ru/docs/reference/protobuf-mod) и [protobuf.lock](/ru/docs/reference/protobuf-lock).
-## Типовые workflows
+## Достижимые импорты и прямые зависимости
-### Инициализация проекта
+Перед записью manifest и lock команда mod tidy проверяет цепочку импортов, достижимых из локального модуля, включая импорты внутри файлов зависимостей. Отсутствующие файлы и некорректный синтаксис достижимого protobuf останавливают операцию. Неиспользуемые файлы зависимости не компилируются и не проходят lint целиком. Импорт из google/protobuf/ должен действительно существовать: одного префикса недостаточно.
-```bash
-cat > easyp.yaml << EOF
-deps:
- - github.com/googleapis/googleapis
- - github.com/grpc-ecosystem/grpc-gateway@v2.19.1
-EOF
+Когда локальный исходник начинает импортировать ранее косвенную зависимость, tidy удаляет существующую пометку // indirect, сохраняя версию и остальные комментарии. Это не поиск произвольного Git-репозитория по неизвестному proto-пути. Идентификаторам зависимостей реестра Buf по-прежнему нужно явное соответствие Git-модулям; они не преобразуются в URL репозитория автоматически.
-easyp mod download
-ls ~/.easyp/mod/github.com/googleapis/googleapis/
-```
+## Сборки в режиме frozen
-### Добавление зависимости
+Сохраните protobuf.mod и protobuf.lock в репозитории, затем явно включите --frozen. Даже модулю без зависимостей нужен пустой lock; каталог исходников без native-манифеста отклоняется. CI=true не включает этот режим.
-```bash
-echo " - github.com/bufbuild/protoc-gen-validate@v0.10.1" >> easyp.yaml
-easyp mod download
-git add easyp.lock
-git commit -m "Add protoc-gen-validate dependency"
-```
+~~~bash
+# Подготовьте и проверьте lock вне frozen
+easyp mod tidy
+# Используйте сохранённый граф; загрузка точных коммитов в кеш разрешена
+easyp mod download --frozen
+easyp --frozen generate
+easyp mod --frozen vendor
+~~~
-### Обновление
+Флаг можно поставить глобально, на уровне mod или конечной подкоманды. Значение true на любом уровне остаётся включённым, даже если дочерняя команда получила --frozen=false. Все варианты размещения описаны в [конфигурации](/ru/docs/cli/configuration).
-```bash
-easyp mod update
-git diff easyp.lock
-easyp generate
-easyp lint
-git add easyp.lock
-git commit -m "Update dependencies"
-```
+Frozen отклоняет все корневые replace до обращения к их путям или скачивания зависимостей, в том числе неиспользуемые замены. Проверяются прямые требования манифеста и транзитивные требования зафиксированных модулей; отсутствующий, некорректный, неполный или устаревший lock вызывает ошибку вместо исправления. Зависимости, выбранные по идентификатору, используют манифест и lock потребителя и не обязаны иметь собственные lock-файлы. Явный путь от workspace при выборе модуля для генерации использует манифест и lock выбранного native-модуля; каталогу только с настройками генератора отдельная пара не нужна. Замены из манифестов зависимостей по-прежнему игнорируются.
-### Оффлайн режим
+Режим не разрешает зависимости заново, не ищет HEAD/теги, не создаёт и не переписывает манифест или lock. Недостающий кеш может загружаться по точным коммитам из lock. Хеши проверяются при холодном и прогретом кеше; повреждённое содержимое вызывает ошибку, а не незаметную замену сохранённого хеша. Frozen не означает работу без сети; удалённым плагинам также может понадобиться сетевой доступ.
-```bash
-easyp mod vendor
-easyp generate
-```
+mod download устанавливает проверенный граф. mod vendor проверяет его перед записью easyp_vendor. mod tidy, get, mod update, init и migrate отклоняют запуск в frozen, включая предварительный просмотр миграции. Удалите замены и подготовьте манифест/lock вне frozen. Обычное поведение локальных замен и vendor, описанное выше, не меняется.
-## Troubleshooting
+## Ошибки кэша и доступа к ревизии
-### Частые проблемы
+При несовпадении хеша установленного модуля ошибка указывает точный каталог кэша. Сначала сохраните его для расследования или изолируйте только эту запись, затем повторите easyp mod download. Не переписывайте protobuf.lock, чтобы скрыть несовпадение; команда сама не удаляет и не исправляет повреждённый кэш.
-#### "Repository not found" / "Authentication failed"
-
-```bash
-git ls-remote https://github.com/mycompany/private-repo
-git config --list | grep url
-```
-
-#### "Version not found"
-
-```bash
-git ls-remote --tags https://github.com/googleapis/googleapis
-# Проверить корректный тег
-deps:
- - github.com/googleapis/googleapis@common-protos-1_3_1
-```
-
-#### "Cache corruption" / "Checksum mismatch"
-
-```bash
-rm -rf ~/.easyp
-rm -rf ~/.easyp/cache/download
-easyp mod download
-```
-
-#### Тайм-ауты сети
-
-```bash
-git config --global http.lowSpeedLimit 1000
-git config --global http.lowSpeedTime 300
-git config --global http.proxy http://proxy.company.com:8080
-```
-
-### Оптимизация
-
-#### Для больших команд
-
-```bash
-export EASYPPATH=/shared/easyp-cache
-export EASYPPATH=/team-cache/easyp
-```
-
-#### Для CI/CD
-
-```bash
-export EASYPPATH=$CI_PROJECT_DIR/.easyp
-# Пример кеширования (GitLab CI)
-cache:
- key: easyp-$CI_COMMIT_REF_SLUG
- paths:
- - .easyp/
-```
-
-#### Управление размером кеша
-
-```bash
-du -sh ~/.easyp
-du -sh ~/.easyp/cache/download
-du -sh ~/.easyp/mod
-find ~/.easyp/mod -type d -name "v0.0.0-*" -mtime +30 -exec rm -rf {} \;
-```
-
-## Примеры интеграции
-
-### Docker multi-stage
-
-```dockerfile
-FROM ghcr.io/easyp-tech/easyp:latest AS deps
-WORKDIR /workspace
-COPY easyp.yaml easyp.lock ./
-RUN easyp mod vendor
-
-FROM alpine:latest AS build
-WORKDIR /app
-COPY --from=deps /workspace/easyp_vendor ./easyp_vendor
-COPY . .
-RUN easyp generate
-```
-
-### Monorepo
-
-```
-my-monorepo/
-├── services/
-│ ├── auth-service/
-│ │ └── easyp.yaml
-│ └── user-service/
-│ └── easyp.yaml
-├── shared/
-│ └── common-protos/
-└── easyp.yaml
-```
-
-Каждый `easyp.yaml` может иметь свой набор зависимостей.
-
-## Лучшие практики
-
-### Workflow разработки
-- ✅ Latest теги в активной разработке
-- ✅ Фиксация версий в продакшене
-- ✅ Коммит lock файла
-- ✅ Ревью обновлений
-- ✅ Тест после обновления
-
-### Безопасность
-- ✅ Фиксируйте версии
-- ✅ Используйте SSH ключи
-- ✅ Оценивайте новые зависимости
-- ✅ Следите за уязвимостями
-- ❌ Не храните секреты в конфиге
-
-### Производительность
-- ✅ Агрессивное кеширование в CI
-- ✅ Vendoring для частых сборок
-- ✅ Чистка старого кеша
-- ✅ Общий кеш для команды
-
-### Командная работа
-- ✅ Документация по аутентификации
-- ✅ Единые инструменты
-- ✅ Автоматизация обновлений с тестами
-- ✅ Общий кеш при возможности
-
-Менеджер пакетов EasyP — масштабируемое децентрализованное решение от одиночных проектов до enterprise, сохраняя простоту и надёжность.
+Недоступность Git-репозитория не означает, что тег отсутствует. Когда история получена, но закреплённого коммита в ней нет, восстановите доступ к исходной ревизии вместо замены на HEAD. Проверка тегов и защита от изменения их содержимого сохраняются; автоматического перехода на офлайн-разрешение нет.
diff --git a/content/docs/guides/adding-dependency.mdx b/content/docs/guides/adding-dependency.mdx
index 4287081..f622d9f 100644
--- a/content/docs/guides/adding-dependency.mdx
+++ b/content/docs/guides/adding-dependency.mdx
@@ -1,21 +1,39 @@
---
title: "Adding a Dependency"
-description: "Step-by-step guide on adding Protobuf module dependencies, resolving transitive dependencies via easyp mod tidy, and committing lockfiles."
+description: "Add Protobuf module dependencies with easyp get and commit the resolved lockfile."
---
This guide demonstrates how to add a third-party or shared Protobuf module dependency to your EasyP project.
---
+## Add a module with `easyp get`
+
+From the directory containing your `protobuf.mod`, run:
+
+```bash
+easyp get github.com/acme/weather
+# Or select a tag or full Git commit:
+easyp get github.com/acme/weather@v1.2.3
+```
+
+`get` adds the selected module as a direct `require`, writes its transitive dependencies as `// indirect`, and updates `protobuf.lock` with exact commits and content hashes. A module inside a Git repository can be named by its full module path, such as `github.com/acme/contracts/proto/user`. A tag is optional; without one, EasyP locks the repository's current HEAD. Run the command separately in each local module directory that has its own `protobuf.mod`.
+
+Add the required protobuf `import` to your `.proto` file, then review and commit both `protobuf.mod` and `protobuf.lock`.
+
+The steps below show the equivalent manual manifest workflow.
+
+---
+
## Workflow Overview
-1. **Declare Dependency**: Add the target module repository URL and version tag to `protobuf.mod` or reference it directly via `import` statements in your `.proto` schema files.
-2. **Run Resolution**: Execute `easyp mod tidy` to compute the transitive dependency graph.
+1. **Declare Dependency**: Add the target Git module identity to `protobuf.mod`. Use `import` statements to reference files from that declared dependency.
+2. **Run Resolution**: Execute `easyp mod tidy` to compute the transitive dependency graph after editing the manifest manually.
3. **Commit Lockfile**: Review the updated `protobuf.mod` and `protobuf.lock` files and commit them to version control.
---
-## Step 1: Declare the Dependency
+## Step 1: Declare the Dependency Manually
Open your module's `protobuf.mod` file and add the required module under the `require` block:
@@ -28,7 +46,7 @@ require (
)
```
-Alternatively, you can write an `import` statement directly in your Protobuf source file:
+Then import a file provided by that dependency in your Protobuf source:
```protobuf
// proto/user/v1/user.proto
@@ -56,6 +74,18 @@ easyp mod tidy
- Appends transitive dependencies to `protobuf.mod` marked with `// indirect`.
- Generates or updates `protobuf.lock` with Git commit hashes and cryptographic content digests.
+### Git repositories using Buf or older EasyP configs
+
+The consuming project still declares a Git source with `require`. The dependency repository may use another configuration format:
+
+- EasyP v1 `protobuf.mod`: reads `roots` and `require`.
+- Buf v2 `buf.yaml`: reads `modules[].path` as import roots.
+- Buf v1 `buf.work.yaml`: reads `directories`; a single-module v1 `buf.yaml` uses `.`.
+- Buf v1beta1 `buf.yaml`: reads `build.roots`, defaulting to `.`.
+- Older EasyP: reads `direct` dependencies from the old `protobuf.mod` and local `generate.inputs[].directory.root` plus Git inputs from `easyp.yaml`.
+
+For an old EasyP dependency without a version on one of its Git requirements, `mod tidy` resolves the Git repository's HEAD and pins its commit in the v1 lock. No tag is required. The old EasyP `source@.proto files with a Git revision. For a repository with schemas under proto, put this policy in the root easyp.yaml:
-FILE adds declaration-move checks; existing compatibility checks stay enabled. Other categories are unsupported. Set ignore_unstable: true only if you intend to skip packages with supported unstable version suffixes; see the [breaking checker](/docs/cli/breaking-changes) for the exact forms.
- - name: Run Proto Linting
- run: easyp lint
+The ignore path is relative to the file defining the effective breaking section. In proto/easyp.yaml, the same directory would be ignore: [experimental]. Changing --root does not change that base.
- - name: Run Breaking Change Detection
- run: easyp breaking --against git:origin/main
- ```
- mod download verifies the commits and content hashes recorded in protobuf.lock. The breaking checker uses each revision's own manifests, locks, and dependency context; the baseline may need additional downloads. Keep manifests and locks committed and resolve dependency updates before the CI check.
-## Handling Breaking Change Failures
+## Make the baseline available
-When `easyp breaking` detects an incompatible schema modification, it exits with a non-zero status code and prints detailed error diagnostic messages:
+The baseline can be a branch, lightweight or annotated tag, full commit SHA, or another locally resolvable Git revision such as HEAD. Fetch the required refs and objects first. Bare branch names take precedence over identically named tags; use refs/tags/v1.2.0 to select a tag explicitly.
-```text
-user/v1/user.proto:24:5: field "email" changed type from "string" to "bytes" (category: WIRE)
-user/v1/user.proto:18:1: field "phone_number" (number 3) was deleted without reservation (category: WIRE)
-```
+An explicit --against overrides breaking.baseline; without either, the default is master. Pass the ref directly to the flag, without git: or git-ref=.
-### Remediation Strategies
+After provisioning a v1-capable EasyP binary, these GitHub Actions steps compare with the pull request's base commit:
-1. **Reserve Deleted Tags**: Instead of removing a field entirely, mark its tag number and name as `reserved` to prevent reuse:
- ```protobuf
- message User {
- reserved 3;
- reserved "phone_number";
- string id = 1;
- string email = 2;
- }
- ```
-2. **Major Version Bump**: If backwards-incompatible changes are unavoidable, introduce a new major package version (e.g., `user.v2`) in a separate directory (`proto/user/v2/`).
-3. **Unstable Iteration**: Work inside an alpha or beta package (e.g., `user.v1alpha1`) where `ignore_unstable: true` allows free modification until API stabilization.
+~~~yaml
+- uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+- name: Check protobuf compatibility
+ env:
+ BASE_REF: ${{ github.event.pull_request.base.sha }}
+ run: easyp breaking --path proto --against "$BASE_REF"
+~~~
-For related configuration details, refer to the [EasyP Configuration Reference](/docs/cli/configuration) and [Adding Dependencies Guide](/docs/guides/adding-dependencies).
+Use this snippet in a pull_request job. Full history makes the baseline available in ordinary PR checkouts; a missing revision fails the check instead of selecting a different baseline. See the complete [GitHub Actions workflow](/docs/ci-cd/github-actions).
diff --git a/content/docs/guides/breaking-checks-ci.ru.mdx b/content/docs/guides/breaking-checks-ci.ru.mdx
index 10e29fe..19f2b02 100644
--- a/content/docs/guides/breaking-checks-ci.ru.mdx
+++ b/content/docs/guides/breaking-checks-ci.ru.mdx
@@ -1,134 +1,51 @@
---
title: "Breaking-проверки в CI"
-description: "Настройка проверки обратной совместимости, категорий строгости и исключений для нестабильных пакетов с помощью EasyP в CI/CD."
+description: "Запуск проверки совместимости EasyP v1 относительно доступной локально Git-базы в CI."
---
-Предотвращение несовместимых изменений (breaking changes) в схемах Protocol Buffer имеет критическое значение для сохранения обратной совместимости между микросервисами и клиентскими приложениями. EasyP предоставляет команду `easyp breaking` для автоматического обнаружения ломающих изменений до их мёрджа в основную ветку репозитория.
+Проверка v1 сравнивает текущие .proto с Git-ревизией. Для репозитория со схемами в proto сохраните эту политику в корневом easyp.yaml:
-FILE добавляет проверки перемещения объявлений; существующие проверки совместимости остаются включёнными. Другие категории не поддерживаются. Задавайте ignore_unstable: true, только если нужно пропускать пакеты с поддерживаемыми нестабильными суффиксами версий; точные формы описаны в [справочнике breaking-проверок](/ru/docs/cli/breaking-changes).
- - name: Run Proto Linting
- run: easyp lint
+Путь исключения отсчитывается от файла, задающего эффективную секцию breaking. В proto/easyp.yaml тот же каталог задавался бы как ignore: [experimental]. Изменение --root не меняет эту базу.
- - name: Run Breaking Change Detection
- run: easyp breaking --against git:origin/main
- ```
- mod download проверяет коммиты и хеши содержимого из protobuf.lock. Breaking-проверка использует собственные манифесты, lock-файлы и зависимости каждой ревизии; для базы могут потребоваться дополнительные загрузки. Храните манифесты и lock-файлы в репозитории и разрешайте обновления зависимостей до проверки в CI.
-## Работа с ошибками несовместимости
+## Доступность базовой ревизии
-Когда `easyp breaking` обнаруживает несовместимое изменение, команда завершается с ненулевым кодом ответа и выводит диагностическое сообщение:
+Базой может быть ветка, лёгкий или аннотированный тег, полный SHA коммита или другая разрешимая локально Git-ревизия, например HEAD. Сначала получите нужные ссылки и объекты. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0.
-```text
-user/v1/user.proto:24:5: field "email" changed type from "string" to "bytes" (category: WIRE)
-user/v1/user.proto:18:1: field "phone_number" (number 3) was deleted without reservation (category: WIRE)
-```
+Явный --against перекрывает breaking.baseline; без обоих значений используется master. Передавайте ссылку прямо во флаг, без git: и git-ref=.
-### Способы решения
+После подготовки бинарника EasyP с поддержкой v1 эти шаги GitHub Actions сравнят схемы с базовым коммитом pull request:
-1. **Резервирование удаленных тегов**: Вместо полного удаления поля отметьте его номер и имя как `reserved`:
- ```protobuf
- message User {
- reserved 3;
- reserved "phone_number";
- string id = 1;
- string email = 2;
- }
- ```
-2. **Повышение мажорной версии**: Если ломающие изменения неизбежны, создайте новую мажорную версию пакета (например, `user.v2`) в отдельной директории (`proto/user/v2/`).
-3. **Разработка в нестабильном пакете**: Ведите разработку в альфа- или бета-пакете (`user.v1alpha1`), где `ignore_unstable: true` разрешает любые изменения до стабилизации API.
+~~~yaml
+- uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+- name: Check protobuf compatibility
+ env:
+ BASE_REF: ${{ github.event.pull_request.base.sha }}
+ run: easyp breaking --path proto --against "$BASE_REF"
+~~~
-Подробности смотрите в [Справочнике конфигурации EasyP](/ru/docs/cli/configuration) и [Руководстве по добавлению зависимостей](/ru/docs/guides/adding-dependencies).
+Используйте фрагмент в job для pull_request. Полная история обеспечивает доступность базы в обычном checkout PR; отсутствие ревизии завершает проверку ошибкой, а не выбирает другую базу. См. полный [workflow GitHub Actions](/ru/docs/ci-cd/github-actions).
diff --git a/content/docs/guides/buf-migration.mdx b/content/docs/guides/buf-migration.mdx
index f14e06e..58c7016 100644
--- a/content/docs/guides/buf-migration.mdx
+++ b/content/docs/guides/buf-migration.mdx
@@ -3,7 +3,7 @@ title: "Migrating from Buf to EasyP"
description: "Step-by-step migration guide for transitioning configurations and commands from Buf CLI to EasyP."
---
-This guide provides a comprehensive migration walkthrough for transitioning existing projects from **Buf** to **EasyP**.
+This guide maps Buf configuration to the EasyP v1 files and commands. Review each setting against the v1 schema rather than copying the old configuration unchanged.
---
@@ -11,47 +11,49 @@ This guide provides a comprehensive migration walkthrough for transitioning exis
| Buf Construct | EasyP Equivalent | Key Distinction |
| --- | --- | --- |
-| `buf.yaml` (deps section) | `protobuf.mod` | Tool-neutral dependency DSL; uses Git URLs instead of proprietary BSR names. |
-| `buf.yaml` (lint section) | `easyp.yaml` (linters) | Follows golangci-lint syntax; supports directory cascading & `extends`. |
-| `buf.yaml` (breaking section) | `easyp.yaml` (breaking) | Explicit git baseline comparison (e.g. `git:main`). |
-| `buf.gen.yaml` | `easyp.gen.yaml` | Resides at consumer project level; zero duplicated source input paths. |
-| `buf.gen.yaml` (managed) | `easyp.gen.yaml` (options) | Grouped logically by target language (e.g., `options.go.package_prefix`). |
-| `buf.lock` | `protobuf.lock` | Includes Git commit SHAs and content hashes. |
-| `buf dep update` | `easyp mod tidy` | Resolves minimal versions (MVS) per-module. |
-| `buf lint` | `easyp lint` | Cascades through nearest `easyp.yaml`. |
-| `buf breaking` | `easyp breaking` | CI gate against explicit baseline. |
-| `buf generate` | `easyp generate` | Auto-discovers all `easyp.gen.yaml` files. |
+| buf.yaml (deps section) | protobuf.mod | Tool-neutral dependency DSL; uses Git URLs instead of proprietary BSR names. |
+| buf.yaml (lint section) | easyp.yaml (linters) | Uses presets and rule lists; each policy section comes whole from its nearest definition. extends explicitly loads a section base from a local file or an existing locked module. |
+| buf.yaml (breaking section) | easyp.yaml (breaking) | Explicit git baseline comparison (e.g. git:main). |
+| buf.gen.yaml | easyp.gen.yaml | Resides at consumer project level and selects complete modules. |
+| buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Explicit managed mode; options.go.package_prefix is a separate Go-only convenience. |
+| buf.lock | protobuf.lock | Includes Git commit SHAs and content hashes. |
+| buf dep update | easyp mod tidy | Resolves declared requirements with MVS and writes the lock; review version updates separately. |
+| buf lint | easyp lint | Cascades through nearest easyp.yaml. |
+| buf breaking | easyp breaking | CI gate against explicit baseline. |
+| buf generate | easyp generate | Selects the nearest enclosing generator file; use --project or explicit recursive --all. |
---
## Step-by-Step Migration Steps
-### Step 1: Automatic Initial Migration
+### Step 1: Initial Setup
-Run `easyp init` in your project root. EasyP detects existing `buf.yaml` and `buf.gen.yaml` files and automatically generates initial `protobuf.mod`, `easyp.yaml`, and `easyp.gen.yaml` files.
+Run easyp init in a new project root to create protobuf.mod, easyp.yaml, and easyp.gen.yaml. Pass --module when the canonical Git module identity cannot be derived from the repository's origin remote.
-```bash
-easyp init
-```
+~~~bash
+easyp init --module github.com/acme/my-service
+~~~
-### Step 2: Separate Dependencies into `protobuf.mod`
+Automatic Buf Registry dependency conversion is deferred. If buf.yaml or buf.yml exists, easyp init stops before writing files because a buf.build/... identity cannot be safely treated as a Git module URL. Choose the Git source for each dependency, then create the v1 files explicitly.
-Extract module dependencies from `buf.yaml` into `protobuf.mod`:
+### Step 2: Separate Dependencies into protobuf.mod
-```protobuf
+Extract module dependencies from buf.yaml into protobuf.mod:
+
+~~~protobuf
// protobuf.mod
module github.com/acme/my-service
require (
github.com/googleapis/googleapis v1.5.0
)
-```
+~~~
-### Step 3: Convert Lint & Breaking Rules to `easyp.yaml`
+### Step 3: Convert Lint & Breaking Rules to easyp.yaml
-Convert `buf.yaml` lint/breaking configurations into `easyp.yaml`:
+Convert buf.yaml lint/breaking configurations into easyp.yaml:
-```yaml
+~~~yaml
# easyp.yaml
version: v1
@@ -60,36 +62,39 @@ linters:
breaking:
baseline: git:main
- categories:
- - WIRE
-```
+~~~
-### Step 4: Remove Inputs from Generator Configs
+### Step 4: Select Modules for Generation
-In `easyp.gen.yaml`, remove `inputs` blocks (such as `directory` or `git_repo`). EasyP infers schema sources directly from `protobuf.mod`:
+Replace legacy inputs blocks with module selection. In this example, the root protobuf.mod owns the schemas, and backend/easyp.gen.yaml selects that root module using .. Module roots come from the manifest:
-```yaml
+~~~yaml
# backend/easyp.gen.yaml
version: v1
generate:
modules:
- - proto/user
+ - .
plugins:
- name: go
- version: v1.34.2
out: ./gen/go
opts:
paths: source_relative
-```
+~~~
+
+The local go plugin requires protoc-gen-go in the build environment. Fix its version there; local plugins reject a YAML version. Remote plugins require a separate pinned semantic version. generate.packages selects exact protobuf package names within the selected modules.
### Step 5: Tidy and Verify
-Run `easyp mod tidy`, followed by `easyp lint` and `easyp generate`:
+From the repository root, resolve dependencies, lint schemas, and generate the selected project:
-```bash
+~~~bash
easyp mod tidy
easyp lint
-easyp generate
-```
+easyp generate --project ./backend
+~~~
+
+Review and commit protobuf.mod and protobuf.lock. Active local replacements must be removed before tidy or update; both commands reject them. In CI, use easyp mod download to verify locked dependencies and run easyp breaking --against main with the baseline available locally.
+
+Only FILE is supported in breaking.categories; ignore_unstable is available. Check the [policy reference](/docs/reference/easyp-yaml) before translating Buf breaking settings, and compare generated output and consumer tests before retiring the old workflow.
diff --git a/content/docs/guides/buf-migration.ru.mdx b/content/docs/guides/buf-migration.ru.mdx
index 9495592..b5d99cc 100644
--- a/content/docs/guides/buf-migration.ru.mdx
+++ b/content/docs/guides/buf-migration.ru.mdx
@@ -3,7 +3,7 @@ title: "Миграция с Buf на EasyP"
description: "Пошаговое руководство по миграции конфигураций и команд с Buf на EasyP."
---
-В данном руководстве подробно рассматривается процесс перехода существующих проектов с **Buf** на **EasyP**.
+Это руководство сопоставляет конфигурацию Buf с файлами и командами EasyP v1. Проверяйте каждую настройку по схеме v1, а не переносите прежнюю конфигурацию без изменений.
---
@@ -11,47 +11,49 @@ description: "Пошаговое руководство по миграции к
| Конструкция Buf | Эквивалент в EasyP | Ключевое отличие |
| --- | --- | --- |
-| `buf.yaml` (секция deps) | `protobuf.mod` | Независимый от инструментов DSL; использует Git URL вместо BSR. |
-| `buf.yaml` (секция lint) | `easyp.yaml` (linters) | Использует синтаксис golangci-lint; поддерживает каскадирование и `extends`. |
-| `buf.yaml` (секция breaking) | `easyp.yaml` (breaking) | Явное сравнение с git-baseline (например, `git:main`). |
-| `buf.gen.yaml` | `easyp.gen.yaml` | Находится у потребителя; не содержит дублирующих путей к источникам. |
-| `buf.gen.yaml` (managed) | `easyp.gen.yaml` (options) | Сгруппирован по языкам (например, `options.go.package_prefix`). |
-| `buf.lock` | `protobuf.lock` | Включает SHA коммитов Git и хеши содержимого. |
-| `buf dep update` | `easyp mod tidy` | Вычисляет минимальные версии (MVS) помодульно. |
-| `buf lint` | `easyp lint` | Каскадируется через ближайший `easyp.yaml`. |
-| `buf breaking` | `easyp breaking` | CI-гейт против явного baseline. |
-| `buf generate` | `easyp generate` | Автоматически находит все `easyp.gen.yaml`. |
+| buf.yaml (секция deps) | protobuf.mod | Независимый от инструментов DSL; использует Git URL вместо BSR. |
+| buf.yaml (секция lint) | easyp.yaml (linters) | Использует пресеты и списки правил; каждая секция политики берётся целиком из ближайшего определения. extends явно подключает базу секции из локального файла или существующего закреплённого модуля. |
+| buf.yaml (секция breaking) | easyp.yaml (breaking) | Явное сравнение с git-baseline (например, git:main). |
+| buf.gen.yaml | easyp.gen.yaml | Находится у потребителя и выбирает целые модули. |
+| buf.gen.yaml (managed) | easyp.gen.yaml (generate.managed) | Явный managed mode; options.go.package_prefix — отдельная настройка только для Go. |
+| buf.lock | protobuf.lock | Включает SHA коммитов Git и хеши содержимого. |
+| buf dep update | easyp mod tidy | Разрешает объявленные требования через MVS и записывает lock; обновления версий проверяйте отдельно. |
+| buf lint | easyp lint | Каскадируется через ближайший easyp.yaml. |
+| buf breaking | easyp breaking | CI-гейт против явного baseline. |
+| buf generate | easyp generate | Выбирает ближайший вышестоящий файл генератора; используйте --project или явный рекурсивный --all. |
---
## Пошаговый процесс миграции
-### Шаг 1: Автоматическая первичная инициализация
+### Шаг 1: Первичная инициализация
-Запустите `easyp init` в корне вашего проекта. EasyP обнаружит существующие файлы `buf.yaml` и `buf.gen.yaml` и автоматически создаст первичные `protobuf.mod`, `easyp.yaml` и `easyp.gen.yaml`.
+В новом проекте easyp init создаёт protobuf.mod, easyp.yaml и easyp.gen.yaml. Укажите --module, если идентификатор Git-модуля нельзя получить из удалённого репозитория origin.
-```bash
-easyp init
-```
+~~~bash
+easyp init --module github.com/acme/my-service
+~~~
-### Шаг 2: Вынос зависимостей в `protobuf.mod`
+Автоматический перенос зависимостей Buf Registry отложен. При наличии buf.yaml или buf.yml команда easyp init завершится до записи файлов: имя buf.build/... нельзя безопасно считать URL Git-модуля. Выберите Git-источник для каждой зависимости и создайте v1-файлы явно.
-Перенесите зависимости модулей из `buf.yaml` в `protobuf.mod`:
+### Шаг 2: Вынос зависимостей в protobuf.mod
-```protobuf
+Перенесите зависимости модулей из buf.yaml в protobuf.mod:
+
+~~~protobuf
// protobuf.mod
module github.com/acme/my-service
require (
github.com/googleapis/googleapis v1.5.0
)
-```
+~~~
-### Шаг 3: Конвертация правил в `easyp.yaml`
+### Шаг 3: Конвертация правил в easyp.yaml
-Перенесите конфигурацию линтера и breaking-проверок в `easyp.yaml`:
+Перенесите конфигурацию линтера и breaking-проверок в easyp.yaml:
-```yaml
+~~~yaml
# easyp.yaml
version: v1
@@ -60,36 +62,39 @@ linters:
breaking:
baseline: git:main
- categories:
- - WIRE
-```
+~~~
-### Шаг 4: Удаление блоков источников из генератора
+### Шаг 4: Выбор модулей для генерации
-В `easyp.gen.yaml` удалите блоки `inputs` (такие как `directory` или `git_repo`). EasyP берёт источники схем напрямую из `protobuf.mod`:
+Замените старые блоки inputs выбором модулей. В примере корневой protobuf.mod владеет схемами, а backend/easyp.gen.yaml выбирает этот корневой модуль через .. Корни исходников определяются манифестом:
-```yaml
+~~~yaml
# backend/easyp.gen.yaml
version: v1
generate:
modules:
- - proto/user
+ - .
plugins:
- name: go
- version: v1.34.2
out: ./gen/go
opts:
paths: source_relative
-```
+~~~
+
+Локальному плагину go нужен protoc-gen-go в окружении сборки. Фиксируйте версию там: локальные плагины отклоняют version в YAML. Удалённым плагинам нужна отдельная фиксированная семантическая версия. generate.packages выбирает точные имена protobuf-пакетов внутри выбранных модулей.
### Шаг 5: Наведение порядка и проверка
-Запустите `easyp mod tidy`, затем `easyp lint` и `easyp generate`:
+Из корня репозитория разрешите зависимости, проверьте схемы линтером и запустите выбранный проект генерации:
-```bash
+~~~bash
easyp mod tidy
easyp lint
-easyp generate
-```
+easyp generate --project ./backend
+~~~
+
+Проверьте и закоммитьте protobuf.mod и protobuf.lock. Перед tidy или update нужно убрать активные локальные замены: обе команды их отклоняют. В CI проверяйте зафиксированные зависимости через easyp mod download и запускайте easyp breaking --against main с доступной локально базой.
+
+В breaking.categories поддерживается только FILE; ignore_unstable доступно. Перед переносом breaking-настроек Buf сверьтесь со [справочником политики](/ru/docs/reference/easyp-yaml), сравните результат генерации и запустите тесты потребителей до отказа от старого workflow.
diff --git a/content/docs/guides/debugging-replace.mdx b/content/docs/guides/debugging-replace.mdx
index 90ba8d2..75077b9 100644
--- a/content/docs/guides/debugging-replace.mdx
+++ b/content/docs/guides/debugging-replace.mdx
@@ -1,55 +1,60 @@
---
title: "Debugging with Replace Directives"
-description: "Using the replace directive in protobuf.mod for local multi-module debugging, and understanding CI build guards."
+description: "Use local module replacements for development and understand their lockfile and network limits."
---
-During active multi-module development, you often need to modify a dependency locally alongside your consuming project. This guide explains how to use the `replace` directive in `protobuf.mod` for local debugging, and how EasyP prevents accidental production leaks.
-
----
+A local replace in protobuf.mod lets you edit a dependency alongside its consumer without publishing each intermediate change.
## Setting Up a Local Replace
-Suppose your module `proto/user` depends on `github.com/acme/weather`. To debug local changes in `weather` without publishing Git tags:
-
-1. Clone or fork `weather` to a local directory (e.g. `../weather-fork`).
-2. Add a `replace` directive to `proto/user/protobuf.mod`:
+Suppose proto/user requires github.com/acme/weather. Put the dependency checkout at proto/weather-fork, next to proto/user, and add:
-```protobuf
+~~~protobuf
// proto/user/protobuf.mod
-
module github.com/acme/user
require (
github.com/acme/weather v1.2.3
)
-// Overrides remote dependency with local disk path
replace github.com/acme/weather => ../weather-fork
-```
+~~~
----
+The relative replacement path is resolved from the directory containing this protobuf.mod, so it points to proto/weather-fork, regardless of the shell's working directory. Absolute paths also work. The replacement's native protobuf.mod must declare github.com/acme/weather; a missing directory or mismatched identity is an error.
## Local Development Workflow
-When `replace` is active:
-- `easyp generate` resolves imports directly from `../weather-fork`.
-- You can iterate on proto schema changes in both modules simultaneously.
-- No remote Git tags or network downloads are required.
+With a generator file in proto/user, run from the repository root:
----
+~~~bash
+easyp generate --project ./proto/user
+~~~
-## CI Build Guardrails
+Only the main consumer's replacements apply, at every depth of the required graph. EasyP reads the replacement's protobuf.mod requirements and source roots; dependency-owned replacements are ignored. Relative paths always use the main manifest directory. A replacement alone does not add a dependency, and unused replacements are not read or fetched. Ordinary dependency cycles are deduplicated. Legacy dependency metadata remains supported through the existing compatibility reader; dependency plugins are not executed.
-To prevent local file paths from breaking production builds, EasyP enforces a **strict CI check**:
+Generate, selected dependency generation, both descriptor export modes, lint, ls-files and breaking import resolution use this same effective graph. Replaced modules need no remote fetch and may be unpublished. A fully local graph works offline without a lock.
---path to check a replacement explicitly. Unused replacement paths cannot exclude the consumer's own sources. Buf includes/excludes remain effective for replacement sources; see [dependency filters](/docs/cli/package-manager#dependencies-using-buf-or-older-easyp).
+
+## Local Mode and the Published Lock
+
+While the main manifest contains replacements, EasyP leaves an existing protobuf.lock **byte-for-byte unchanged** and does not create one if absent. Local paths, local versions/hashes and fork-only transitive dependencies never enter the shared lock. This is an explicit EasyP invariant: protobuf.lock is not go.sum, and this does not mean Go never updates go.sum with replacements. The main-module replacement semantics follow [Go's replacement model](https://go.dev/ref/mod#go-mod-file-replace).
+
+- mod tidy resolves and validates the effective graph and installs needed remote snapshots without editing the manifest or lock.
+- get may edit the explicitly requested requirement. mod update refreshes unreplaced direct requirements using the existing version rules; replaced requirements keep their declared versions without a remote lookup. Neither command promotes fork-only transitives or writes a lock.
+- mod download verifies/installs only needed unreplaced snapshots. It can resolve new remote requirements of the fork without adding them to the shared lock; replaced roots and unused lock entries are not downloaded.
+- mod vendor copies current local and verified remote sources into easyp_vendor without writing the lock. This local artifact does not prove published reproducibility.
+
+require in the consumer's protobuf.mod.
+3. Remove the replace directive.
+4. Run easyp mod tidy in that module to update protobuf.lock.
+5. Regenerate the selected project, run consumer tests, and commit the reviewed manifest, lock, and generated changes.
+
+For breaking checks, replacements inside the Git repository use each revision's own contents. External local replacements are rejected because the baseline has no recoverable historical copy. A versionless remote requirement from a historical fork needs a historical lock pin; current HEAD cannot substitute for the baseline. See [breaking checks](/docs/cli/breaking-changes).
diff --git a/content/docs/guides/debugging-replace.ru.mdx b/content/docs/guides/debugging-replace.ru.mdx
index 002f84f..a5dabee 100644
--- a/content/docs/guides/debugging-replace.ru.mdx
+++ b/content/docs/guides/debugging-replace.ru.mdx
@@ -1,55 +1,60 @@
---
title: "Отладка через replace"
-description: "Использование директивы replace в protobuf.mod для локальной отладки нескольких модулей и защита от попадания локальных путей в CI."
+description: "Локальные замены модулей при разработке и их ограничения для lock-файла и сети."
---
-В процессе разработки часто требуется править зависимый модуль локально одновременно с основным проектом. В данном руководстве рассматривается использование директивы `replace` в `protobuf.mod` для отладки и механизмы защиты EasyP от случайного попадания локальных путей в продакшн.
-
----
+Локальный replace в protobuf.mod позволяет менять зависимость вместе с потребителем, не публикуя каждое промежуточное изменение.
## Настройка локального replace
-Предположим, ваш модуль `proto/user` зависит от `github.com/acme/weather`. Для отладки изменений в `weather` без публикации Git-тегов:
-
-1. Клонируйте репозиторий `weather` в соседнюю директорию (например, `../weather-fork`).
-2. Добавьте директиву `replace` в `proto/user/protobuf.mod`:
+Предположим, proto/user требует github.com/acme/weather. Разместите checkout зависимости в proto/weather-fork, рядом с proto/user, и добавьте:
-```protobuf
+~~~protobuf
// proto/user/protobuf.mod
-
module github.com/acme/user
require (
github.com/acme/weather v1.2.3
)
-// Переопределяет удалённую зависимость локальным путем на диске
replace github.com/acme/weather => ../weather-fork
-```
+~~~
----
+Относительный путь замены отсчитывается от каталога с этим protobuf.mod и указывает на proto/weather-fork независимо от рабочего каталога shell. Абсолютные пути также поддерживаются. Нативный protobuf.mod замены должен объявлять github.com/acme/weather; отсутствие каталога или несовпадение имени вызывает ошибку.
## Процесс локальной разработки
-При активной директиве `replace`:
-- `easyp generate` резолвит импорты напрямую из `../weather-fork`.
-- Вы можете параллельно править `.proto` файлы в обоих модулях.
-- Публикация Git-тегов и обращение к сети не требуются.
+Если файл генератора расположен в proto/user, запустите из корня репозитория:
----
+~~~bash
+easyp generate --project ./proto/user
+~~~
-## Защита в CI
+Применяются только замены главного модуля-потребителя, на любой глубине требуемого графа. EasyP читает требования и корни из protobuf.mod замены, но игнорирует директивы замены в зависимостях. Относительные пути всегда считаются от главного манифеста. Сама директива замены не добавляет зависимость; неиспользуемые замены не читаются и не скачиваются. Обычные циклы зависимостей обходятся без повторной обработки. Старые метаданные поддерживаются существующим адаптером совместимости; плагины зависимостей не запускаются.
-Чтобы локальные пути к диску не сломали сборку в CI, EasyP включает **строгую проверку**:
+Генерация, выбор зависимостей для генерации, оба режима экспорта дескрипторов, lint, ls-files и разрешение импортов breaking используют один эффективный граф. Заменённые модули не требуют удалённой загрузки и могут быть неопубликованными. Полностью локальный граф работает офлайн без lock-файла.
---path для явной проверки замены. Пути неиспользуемых замен не исключают собственные исходники потребителя. Buf includes/excludes действуют и для замен; см. [фильтры зависимостей](/ru/docs/cli/package-manager#зависимости-на-buf-или-старом-easyp).
+
+## Локальный режим и публикуемый lock
+
+Пока в главном манифесте есть замены, EasyP оставляет существующий protobuf.lock **побайтно неизменным**, а отсутствующий не создаёт. Локальные пути, версии/хеши и транзитивные зависимости только из форка не попадают в общий lock. Это явный инвариант EasyP: protobuf.lock не является go.sum, и это не утверждение, что Go никогда не меняет go.sum при заменах. Правила применения замен главного модуля следуют [модели Go](https://go.dev/ref/mod#go-mod-file-replace).
+
+- mod tidy разрешает и проверяет эффективный граф и устанавливает нужные удалённые снимки без изменения манифеста или lock.
+- get может изменить явно запрошенное требование. mod update обновляет незаменённые прямые требования по прежним правилам версий; заменённые требования сохраняют объявленные версии без удалённого поиска. Обе команды не добавляют транзитивные зависимости только из форка и не записывают lock.
+- mod download проверяет/устанавливает только нужные незаменённые снимки. Новые удалённые требования форка разрешаются без записи в общий lock; заменённые модули и неиспользуемые записи lock не скачиваются.
+- mod vendor копирует текущие локальные и проверенные удалённые исходники в easyp_vendor, не меняя lock. Этот локальный артефакт не доказывает воспроизводимость опубликованного графа.
+
+require в protobuf.mod потребителя.
+3. Удалите директиву replace.
+4. В этом модуле запустите easyp mod tidy для обновления protobuf.lock.
+5. Повторите генерацию выбранного проекта, запустите тесты потребителей и закоммитьте проверенные изменения манифеста, lock и сгенерированных файлов.
+
+При breaking-проверках замены внутри Git-репозитория используют содержимое соответствующей ревизии. Внешние локальные замены отклоняются: у базы нет восстановимой исторической копии. Удалённому требованию без версии из исторического форка нужен pin в историческом lock: текущий HEAD не подставляется вместо базы. См. [breaking-проверки](/ru/docs/cli/breaking-changes).
diff --git a/content/docs/guides/microservice-isolation.mdx b/content/docs/guides/microservice-isolation.mdx
index 3e685ff..a0f48af 100644
--- a/content/docs/guides/microservice-isolation.mdx
+++ b/content/docs/guides/microservice-isolation.mdx
@@ -53,5 +53,5 @@ require (
## Key Benefits
1. **Independent Release Cycles**: Team `order` can upgrade to `common v2.0.0` without waiting for Team `user`.
-2. **Zero Monorepo Friction**: Separate lockfiles (`proto/user/protobuf.lock` vs `proto/order/protobuf.lock`) mean pull requests in one service never pollute lockfiles in another.
-3. **Clean Schema Namespaces**: Because FQNs in `user` and `order` do not collide during code generation, each consumer target compiles against its expected dependency version.
+2. **Independent version decisions**: module lockfiles can change independently. Shared configuration or contract changes still require cross-service review.
+3. **Isolated dependency graphs**: each module compiles against its selected version. Generated package namespaces may still collide; configure distinct output/import paths. Incompatible graphs cannot share one descriptor set; use independent exports.
diff --git a/content/docs/guides/microservice-isolation.ru.mdx b/content/docs/guides/microservice-isolation.ru.mdx
index 0253f4b..e0c0a9f 100644
--- a/content/docs/guides/microservice-isolation.ru.mdx
+++ b/content/docs/guides/microservice-isolation.ru.mdx
@@ -53,5 +53,5 @@ require (
## Ключевые преимущества
1. **Независимые релизные циклы**: Команда `order` может обновиться до `common v2.0.0`, не дожидаясь команды `user`.
-2. **Отсутствие конфликтов в монорепе**: Раздельные lock-файлы (`proto/user/protobuf.lock` и `proto/order/protobuf.lock`) гарантируют, что PR одного сервиса никогда не затрагивают зависимости другого.
-3. **Чистые пространства имён**: Полные имена типов (FQN) в `user` и `order` не сталкиваются при генерации кода, поскольку каждый потребитель компилируется со своими версиями.
+2. **Отдельные решения о версиях**: lock-файлы модулей обновляются независимо. Изменения общей конфигурации или самих контрактов всё равно требуют межкомандной проверки.
+3. **Изолированные графы зависимостей**: каждый модуль компилируется со своей выбранной версией. Это не гарантирует отсутствие коллизий сгенерированных пакетов: настройте отдельные output/import paths. Несовместимые графы нельзя объединять в один descriptor set; используйте раздельный экспорт.
diff --git a/content/docs/guides/multi-target-generation.mdx b/content/docs/guides/multi-target-generation.mdx
index 3254ffa..4b5a89e 100644
--- a/content/docs/guides/multi-target-generation.mdx
+++ b/content/docs/guides/multi-target-generation.mdx
@@ -1,141 +1,104 @@
---
title: "Multi-Target Code Generation"
-description: "Configuring independent per-project generation specs for backend microservices and web frontends with unified versioning in EasyP."
+description: "Select independent backend and frontend generation projects that consume the same protobuf modules."
---
-In modern polyglot architectures, multiple applications (such as Go microservices, TypeScript frontends, and Python data pipelines) consume code generated from the same Protocol Buffer schemas. EasyP uses a file-per-project generation model (`easyp.gen.yaml`) that keeps generation targets isolated while guaranteeing version alignment through `protobuf.mod` and `protobuf.lock`.
-
-easyp.gen.yaml files. Dependency identities and requirements belong in protobuf.mod; resolved dependency commits and hashes belong in protobuf.lock.
## Project Architecture & Configuration
-Each consuming project defines its own `easyp.gen.yaml` file inside its project directory. EasyP automatically discovers all `easyp.gen.yaml` files in the repository hierarchy when executing `easyp generate`.
-
-proto/user and proto/order, each with its own protobuf.mod. The backend selects both modules; the frontend selects only the user module. Paths in generate.modules are relative to the repository root.
+
+### Backend project
+
+~~~yaml
+# backend/easyp.gen.yaml
+version: v1
+generate:
+ modules:
+ - proto/user
+ - proto/order
+plugins:
+ - name: go
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ - name: go-grpc
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ require_unimplemented_servers: false
+options:
+ go:
+ package_prefix: github.com/acme/app/backend/gen/go
+~~~
+
+Install the required protoc-gen-go and protoc-gen-go-grpc executables in the build environment. Control their versions there; a local plugin cannot declare version in this file.
+
+### Frontend project
+
+~~~yaml
+# frontend/easyp.gen.yaml
+version: v1
+generate:
+ modules:
+ - proto/user
+plugins:
+ - name: es
+ out: ./src/gen
+ opts:
+ target: ts
+~~~
+
+This project requires protoc-gen-es on PATH. Output directories are relative to the project file, so backend and frontend output stay separate. Give modules distinct proto-relative output paths if they share an output directory.
+
+### Shared Go option
+
+An ancestor generator file can supply a Go package prefix:
+
+~~~yaml
+# easyp.gen.yaml at the repository root
+version: v1
+options:
+ go:
+ package_prefix: github.com/acme/app/gen/go
+~~~
+
+The nearest explicit options.go.package_prefix wins. The backend above overrides this value. This inheritance does not copy generate or plugins into child projects. The prefix sets go_package; full managed mode is configured separately through generate.managed.
+
+## Key Configuration Elements
+
+- generate.modules selects complete local modules or canonical module identities available in the selected dependency context. With no list, generation uses the nearest enclosing module, or the project directory when no manifest exists.
+- generate.packages selects exact protobuf package names, not prefixes or globs. Empty selects all source files.
+- Each plugin selects exactly one source: name, path, command, or remote, and requires out.
+- opts accepts a map or a list of option strings. with_imports: true also generates transitive imports for that plugin.
## Plugin Execution Sources
-EasyP supports three execution mechanisms for code generator plugins, allowing teams to balance local performance with build hermeticity:
-
-name | Uses the installed executable; supported built-in names fall back to bundled WASM when no matching executable is on PATH. Pin the build environment and EasyP binary. |
+| path or command | Uses the executable you provide. Manage its version outside the generator YAML. |
+| remote | Requires a separate pinned semantic version; do not embed the version in the remote name. |
+
+Local and bundled plugins reject a nonempty version because EasyP cannot verify it against the executable. Remote execution requires network access. Neither WASM nor a remote version pin alone guarantees identical output bytes.
## Execution Workflow
-Run `easyp generate` from the repository root to trigger code generation across all configured projects:
+From the repository root, select the projects explicitly:
+
+~~~bash
+easyp generate --project ./backend --project ./frontend
+~~~
+
+Or recursively select every project below the working directory:
-```bash
-# Discover and execute all easyp.gen.yaml files in workspace
-easyp generate
+~~~bash
+easyp generate --all
+~~~
-# Target a specific project directory only
-easyp generate --project ./backend
-```
+Do not combine --all and --project. Without either flag, easyp generate selects the nearest enclosing easyp.gen.yaml; it does not recurse through child projects.
-Because all projects consume proto versions locked in `protobuf.lock`, the Go backend and TypeScript frontend generated code are guaranteed to be in sync.
+Projects selecting the same module use that module's manifest and dependency lock. Separate modules can have different dependency graphs, so review their locks and test the generated clients together.
-For complete generator options, see the [EasyP Generator Reference](/docs/cli/generator) and [Build Reproducibility Guide](/docs/guides/build-reproducibility).
+See the [generator reference](/docs/reference/easyp-gen-yaml) and [build reproducibility guide](/docs/guides/reproducibility).
diff --git a/content/docs/guides/multi-target-generation.ru.mdx b/content/docs/guides/multi-target-generation.ru.mdx
index 33631a0..1f79ade 100644
--- a/content/docs/guides/multi-target-generation.ru.mdx
+++ b/content/docs/guides/multi-target-generation.ru.mdx
@@ -1,141 +1,104 @@
---
title: "Многоцелевая генерация кода"
-description: "Настройка независимых конфигураций генерации для бэкенда и фронтенда при едином версионировании модулей в EasyP."
+description: "Явный выбор независимых проектов генерации для бэкенда и фронтенда, использующих одни protobuf-модули."
---
-В современных полиглотных архитектурах несколько приложений (например, Go-микросервисы, TypeScript-фронтенд и Python-сервисы аналитики) используют код, сгенерированный из одних и тех же схем Protocol Buffer. EasyP использует модель генерации «файл-на-проект» (`easyp.gen.yaml`), которая изолирует цели генерации и при этом гарантирует согласованность версий через `protobuf.mod` и `protobuf.lock`.
-
-easyp.gen.yaml. Идентификаторы и требования зависимостей задаются в protobuf.mod, а выбранные коммиты и хеши — в protobuf.lock.
## Архитектура проектов и конфигурация
-Каждый проект-потребитель определяет собственный файл `easyp.gen.yaml` внутри своей директории. При запуске `easyp generate` EasyP автоматически находит все файлы `easyp.gen.yaml` в дереве репозитория.
-
-proto/user и proto/order, каждый со своим protobuf.mod. Бэкенд выбирает оба модуля, фронтенд — только пользовательский. Пути в generate.modules отсчитываются от корня репозитория.
+
+### Проект бэкенда
+
+~~~yaml
+# backend/easyp.gen.yaml
+version: v1
+generate:
+ modules:
+ - proto/user
+ - proto/order
+plugins:
+ - name: go
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ - name: go-grpc
+ out: ./gen/go
+ opts:
+ paths: source_relative
+ require_unimplemented_servers: false
+options:
+ go:
+ package_prefix: github.com/acme/app/backend/gen/go
+~~~
+
+Установите нужные исполняемые файлы protoc-gen-go и protoc-gen-go-grpc в окружении сборки. Их версии фиксируются там; локальный плагин не может задавать version в этом файле.
+
+### Проект фронтенда
+
+~~~yaml
+# frontend/easyp.gen.yaml
+version: v1
+generate:
+ modules:
+ - proto/user
+plugins:
+ - name: es
+ out: ./src/gen
+ opts:
+ target: ts
+~~~
+
+Проекту нужен protoc-gen-es в PATH. Каталоги вывода задаются относительно проектного файла, поэтому результаты бэкенда и фронтенда разделены. Если несколько модулей пишут в один каталог, используйте разные относительные пути proto-файлов, определяющие пути вывода.
+
+### Общая Go-опция
+
+Вышестоящий файл генератора может задавать префикс Go-пакетов:
+
+~~~yaml
+# easyp.gen.yaml в корне репозитория
+version: v1
+options:
+ go:
+ package_prefix: github.com/acme/app/gen/go
+~~~
+
+Побеждает ближайшее явно заданное значение options.go.package_prefix. Бэкенд выше переопределяет его. Такое наследование не копирует generate или plugins в дочерние проекты. Префикс задаёт go_package; полный managed mode настраивается отдельно через generate.managed.
+
+## Ключевые элементы конфигурации
+
+- generate.modules выбирает целые локальные модули или канонические идентификаторы модулей, доступные в выбранном контексте зависимостей. Без списка используется ближайший вышестоящий модуль, а при отсутствии манифеста — каталог проекта.
+- generate.packages выбирает точные имена protobuf-пакетов, не префиксы или glob-шаблоны. Пустой список выбирает все исходники.
+- Каждый плагин выбирает ровно один источник: name, path, command или remote, и обязательно задаёт out.
+- opts принимает словарь или список строк опций. with_imports: true дополнительно генерирует транзитивные импорты для этого плагина.
## Источники плагинов
-EasyP поддерживает три механизма выполнения плагинов кодогенерации:
-
-name | Использует установленный исполняемый файл; поддерживаемые встроенные имена переходят на комплектный WASM, если соответствующего файла нет в PATH. Фиксируйте окружение сборки и бинарник EasyP. |
+| path или command | Использует предоставленный исполняемый файл. Управляйте его версией вне YAML генератора. |
+| remote | Требует отдельную фиксированную семантическую version; не включайте версию в имя удалённого плагина. |
+
+Локальные и встроенные плагины отклоняют непустое поле version: EasyP не может проверить его соответствие исполняемому файлу. Удалённая генерация требует сети. Ни WASM, ни фиксация удалённой версии сами по себе не гарантируют побайтовую идентичность результата.
+
+## Запуск генерации
+
+Из корня репозитория явно выберите проекты:
+
+~~~bash
+easyp generate --project ./backend --project ./frontend
+~~~
+
+Или рекурсивно выберите все проекты ниже рабочего каталога:
+
+~~~bash
+easyp generate --all
+~~~
+
+Не сочетайте --all и --project. Без этих флагов easyp generate выбирает ближайший вышестоящий easyp.gen.yaml, а не обходит дочерние проекты.
+
+Проекты, выбравшие один модуль, используют его манифест и lock зависимостей. У разных модулей графы зависимостей могут отличаться: проверяйте их lock-файлы и тестируйте сгенерированные клиенты вместе.
+
+См. [справочник генератора](/ru/docs/reference/easyp-gen-yaml) и [руководство по воспроизводимости](/ru/docs/guides/reproducibility).
diff --git a/content/docs/guides/organization-lint-style.mdx b/content/docs/guides/organization-lint-style.mdx
index 4414593..fa20896 100644
--- a/content/docs/guides/organization-lint-style.mdx
+++ b/content/docs/guides/organization-lint-style.mdx
@@ -1,79 +1,82 @@
---
-title: "Organizational Lint Policy Sharing"
-description: "How to centralize linter rules using extends, and handle legacy directories via cascading configurations."
+title: "Organizational Lint Policies"
+description: "Share producer policies through local files or verified, pinned Git modules."
---
-Maintaining consistent Protobuf linting rules across hundreds of microservice repositories is a common challenge. This guide demonstrates how to share organizational base policies using `linters.extends` and manage exceptions cleanly.
+Each section of easyp.yaml first comes from its nearest definition in the directory tree. That section may explicitly extend a base. Lint and breaking inheritance are independent; a lint base does not import its breaking or issues section.
----
-
-## 1. Defining a Shared Base Policy
+## Local base
-Platform engineering teams can publish a centralized linting policy repository (e.g. `github.com/uzum/proto-policy/lint-base`).
+Create .policies/lint.yaml inside the workspace:
-```yaml
-# Shared policy repo: github.com/uzum/proto-policy/lint-base/easyp.yaml
+~~~yaml
version: v1
-
linters:
default: STANDARD
- enable:
- - ENUM_VALUE_PREFIX
- - RPC_REQUEST_RESPONSE_UNIQUE
- disable:
- - PACKAGE_VERSION_SUFFIX
-
+ disable: [PACKAGE_VERSION_SUFFIX]
linters-settings:
- ENUM_ZERO_VALUE_SUFFIX:
- suffix: UNSPECIFIED
-```
+ SERVICE_SUFFIX:
+ suffix: Service
+~~~
----
+Then use it from the repository's easyp.yaml:
-## 2. Inheriting Policies via `extends`
+~~~yaml
+version: v1
+linters:
+ extends: ./.policies/lint.yaml
+ enable: [PACKAGE_VERSION_SUFFIX]
+ disable: [RPC_REQUEST_RESPONSE_UNIQUE]
+~~~
-Individual service repositories inherit the central policy using `linters.extends`. They can also override individual rules locally:
+A local reference begins with ./ or ../ and resolves from the file containing it. A directory means its easyp.yaml. References cannot escape the workspace, including through symlinks. Recursive bases are supported, with cycle detection and a limit of 16 base policies.
-```yaml
-# Service repo: proto/easyp.yaml
-version: v1
+## Pinned shared module
-linters:
- extends: github.com/uzum/proto-policy/lint-base
- disable:
- - PACKAGE_VERSION_SUFFIX # Local exception to shared policy
+Declare the policy module as an ordinary dependency. The following organization identity is illustrative; substitute a published module you control.
+
+~~~text
+module github.com/acme/service
+require github.com/acme/proto-policy v1.2.3
+~~~
+
+Resolve and review its lock with easyp mod tidy. Reference the policy without duplicating the version:
+~~~yaml
+version: v1
+linters:
+ extends: github.com/acme/proto-policy#lint/base.yaml
breaking:
- baseline: git:main
- categories:
- - WIRE
-```
+ extends: github.com/acme/proto-policy#breaking/easyp.yaml
+ ignore: []
+~~~
----
+The explicit form is declared-module#policy-path. An exact module identity selects its easyp.yaml. The form declared-module/path uses the longest matching identity already present in the consumer graph; it does not discover a new repository. A nested or major-version module resolves paths from its actual manifest directory, not its proto import roots.
-## 3. Handling Legacy Subtrees via Directory Cascading
+Execution may download an exact missing locked commit, but does not re-resolve a tag, choose HEAD, add dependencies or write the lock. A moved tag cannot silently change an existing base. Relative references made by a dependency policy stay inside that module. The main module's local replacement can supply a policy in normal mode; all remote edges still require existing pins. --frozen rejects replacements and verifies the complete locked graph.
-If your repository contains legacy Protobuf files that cannot yet adhere to corporate standards, create a targeted `easyp.yaml` inside the legacy directory:
+## Precedence
-```text
-proto/
-├── easyp.yaml # Standard corporate policy for active services
-├── user/v1/user.proto
-└── legacy/
- ├── easyp.yaml # MINIMAL policy override strictly for legacy/
- └── old.proto
-```
+The resolved base is applied before explicit local values. A local preset replaces the base preset without discarding inherited explicit rule adjustments. A local enable can undo a base disable, including one supplied by a group. Disable wins over enable in the same layer; repeated rules do not duplicate diagnostics.
-`proto/legacy/easyp.yaml`:
+Linter settings merge by rule and key. An explicit empty linters-settings map clears inherited settings; an empty rule map clears that rule. Explicit false and empty breaking lists remain overrides. YAML aliases and merge keys preserve these distinctions.
-```yaml
-version: v1
+Nearest-directory cascading is unchanged: a child section without extends replaces its ancestor section, rather than partially merging with it. Only explicit inheritance merges base and local adjustments.
-linters:
- default: MINIMAL
- disable:
- - FIELD_LOWER_SNAKE_CASE
- - ENUM_VALUE_PREFIX
-```
+## Consumer-relative breaking behavior
+
+The inherited baseline is a Git reference in the consuming repository. Inherited ignore paths are relative to the consuming policy file, never to the Git cache. Local ignore lists replace the inherited list, including an explicitly empty list. An explicit --against still overrides the effective baseline.
+
+A common ancestor policy is resolved independently for each checked module, using that module's dependency graph. Different modules can therefore use different pinned versions or local replacements of the same policy. Deleted modules are checked against historical snapshots. For a wholly deleted module whose base exists only in its old dependency graph, pass --against to identify the historical revision.
+
+## Validation
+
+~~~bash
+easyp validate-config --cfg easyp.yaml
+easyp lint
+easyp breaking --against main
+~~~
+
+The parser validates reference syntax without network access. The CLI additionally follows local references and verifies already cached dependency content. Missing cached policies produce an actionable error: run easyp mod download, then validate again. Validation itself does not download dependencies. Invalid bases, cycles and boundary violations include the consuming field and the reference chain.
-Due to EasyP's nearest-file cascading rule, the relaxed policy applies exclusively to `.proto` files under `proto/legacy/`, while the rest of the repository adheres to corporate standards.
+Loading policies never runs generation plugins or imports a base's issues.exclude-rules. Environment variables are expanded once in each original file, not again after merging. See the [policy reference](/docs/reference/easyp-yaml).
diff --git a/content/docs/guides/organization-lint-style.ru.mdx b/content/docs/guides/organization-lint-style.ru.mdx
index 528558f..d70089e 100644
--- a/content/docs/guides/organization-lint-style.ru.mdx
+++ b/content/docs/guides/organization-lint-style.ru.mdx
@@ -1,79 +1,82 @@
---
-title: "Общий стиль линта в организации"
-description: "Централизация правил линтинга через extends и обработка legacy-директорий с помощью каскадных конфигов."
+title: "Общие политики линтинга"
+description: "Наследование политик из локальных файлов и закреплённых Git-модулей."
---
-Поддержание единых правил линтинга Protobuf в сотнях репозиториев микросервисов — частая задача. В данном руководстве объясняется, как шарить единые политики организации с помощью `linters.extends` и корректно управлять исключениями.
+Каждая секция easyp.yaml сначала выбирается из ближайшего определения в дереве каталогов. Затем она может явно подключить базовую политику. Наследование lint и breaking независимо: база линтинга не переносит свои секции breaking и issues.
----
-
-## 1. Определение базовой политики организации
+## Локальная база
-Платформенная команда публикует репозиторий с централизованной политикой линтинга (например, `github.com/uzum/proto-policy/lint-base`).
+Создайте .policies/lint.yaml внутри рабочего пространства:
-```yaml
-# Базовая политика: github.com/uzum/proto-policy/lint-base/easyp.yaml
+~~~yaml
version: v1
-
linters:
default: STANDARD
- enable:
- - ENUM_VALUE_PREFIX
- - RPC_REQUEST_RESPONSE_UNIQUE
- disable:
- - PACKAGE_VERSION_SUFFIX
-
+ disable: [PACKAGE_VERSION_SUFFIX]
linters-settings:
- ENUM_ZERO_VALUE_SUFFIX:
- suffix: UNSPECIFIED
-```
+ SERVICE_SUFFIX:
+ suffix: Service
+~~~
----
+Подключите её в корневом easyp.yaml:
-## 2. Наследование политик через `extends`
+~~~yaml
+version: v1
+linters:
+ extends: ./.policies/lint.yaml
+ enable: [PACKAGE_VERSION_SUFFIX]
+ disable: [RPC_REQUEST_RESPONSE_UNIQUE]
+~~~
-Репозитории отдельных сервисов подключают центральную политику через `linters.extends`. Также они могут переопределять отдельные правила локально:
+Локальная ссылка начинается с ./ или ../ и считается от содержащего её файла. Для каталога выбирается его easyp.yaml. Выход за границы рабочего пространства, в том числе через симлинк, запрещён. Базы могут наследовать другие базы; циклы отклоняются, максимальная цепочка — 16 базовых политик.
-```yaml
-# Сервисный репозиторий: proto/easyp.yaml
-version: v1
+## Закреплённый модуль политик
-linters:
- extends: github.com/uzum/proto-policy/lint-base
- disable:
- - PACKAGE_VERSION_SUFFIX # Локальное отклонение от общей базы
+Объявите модуль политик обычной зависимостью. Ниже использован пример идентификатора организации: замените его реально опубликованным модулем.
+
+~~~text
+module github.com/acme/service
+require github.com/acme/proto-policy v1.2.3
+~~~
+
+Выполните easyp mod tidy и проверьте созданный lock. В ссылке на политику версия не дублируется:
+~~~yaml
+version: v1
+linters:
+ extends: github.com/acme/proto-policy#lint/base.yaml
breaking:
- baseline: git:main
- categories:
- - WIRE
-```
+ extends: github.com/acme/proto-policy#breaking/easyp.yaml
+ ignore: []
+~~~
----
+Явная форма — объявленный-модуль#путь-политики. Точный идентификатор модуля выбирает его easyp.yaml. В форме объявленный-модуль/путь используется самый длинный известный идентификатор из графа потребителя; поиска нового репозитория нет. Пути вложенных и major-модулей считаются от их фактического manifest, а не от корней proto-импортов.
-## 3. Обработка legacy-кода через каскадирование
+Команда может скачать отсутствующий закреплённый commit, но не пересчитывает теги, не выбирает HEAD, не добавляет зависимости и не переписывает lock. Перенос тега не подменяет базовую политику. Относительные ссылки внутри зависимости остаются в пределах того же модуля. В обычном режиме политику может предоставить локальный replace главного модуля; удалённые зависимости всё равно требуют существующих закреплений. --frozen запрещает replace и проверяет полный закреплённый граф.
-Если в вашем репозитории есть старые `.proto` файлы, которые пока не соответствуют стандартам компании, создайте локальный `easyp.yaml` внутри legacy-директории:
+## Приоритеты
-```text
-proto/
-├── easyp.yaml # Стандартная политика организации
-├── user/v1/user.proto
-└── legacy/
- ├── easyp.yaml # Ослабленная политика MINIMAL только для legacy/
- └── old.proto
-```
+Сначала применяется разрешённая база, затем явно заданные локальные значения. Локальный пресет заменяет базовый, сохраняя унаследованные явные изменения правил. Локальный enable может отменить базовый disable, включая отключение через группу. В одной секции disable имеет приоритет над enable; повторные правила не дублируют сообщения.
-`proto/legacy/easyp.yaml`:
+Настройки линтеров объединяются по правилу и ключу. Явная пустая секция linters-settings очищает настройки базы, пустая карта отдельного правила очищает это правило. Явные false и пустые списки breaking сохраняют смысл переопределения. YAML-алиасы и merge-ключи учитываются.
-```yaml
-version: v1
+Каскад каталогов не изменён: дочерняя секция без extends заменяет секцию предка целиком, а не частично объединяет её. Слияние базовых и локальных значений происходит только при явном наследовании.
-linters:
- default: MINIMAL
- disable:
- - FIELD_LOWER_SNAKE_CASE
- - ENUM_VALUE_PREFIX
-```
+## Breaking в контексте потребителя
+
+Унаследованный baseline — Git-ссылка в репозитории потребителя. Пути ignore считаются от подключающего политику файла, не от кэша Git. Локальный список ignore заменяет базовый, в том числе когда он пуст. Явный --against сохраняет приоритет над итоговым baseline.
+
+Общая корневая политика разрешается отдельно для каждого проверяемого модуля по его графу зависимостей. Поэтому модули могут использовать разные закреплённые версии или локальные замены одной политики. Удалённые модули сравниваются с историческими снимками. Для полностью удалённого модуля, чья база доступна только через старый граф зависимостей, укажите --against для определения исторической ревизии.
+
+## Проверка
+
+~~~bash
+easyp validate-config --cfg easyp.yaml
+easyp lint
+easyp breaking --against main
+~~~
+
+Парсер проверяет синтаксис ссылки без сетевых запросов. CLI дополнительно разрешает локальные ссылки и проверяет целостность уже закэшированных зависимостей. Если базы нет в кэше, выполните easyp mod download и повторите проверку. Сама validate-config зависимости не скачивает. Ошибки базы, циклы и выходы за границы содержат поле потребителя и цепочку ссылок.
-Благодаря правилу ближайшего файла ослабленная политика применяется исключительно к файлам в `proto/legacy/`, в то время как остальное дерево репозитория проверяется по полному стандарту.
+Загрузка политик не запускает плагины генерации и не наследует issues.exclude-rules базы. Переменные среды раскрываются один раз в каждом исходном файле и не раскрываются повторно после слияния. Подробнее — в [справочнике политики](/ru/docs/reference/easyp-yaml).
diff --git a/content/docs/guides/reproducibility.mdx b/content/docs/guides/reproducibility.mdx
index 3e461bd..463f84b 100644
--- a/content/docs/guides/reproducibility.mdx
+++ b/content/docs/guides/reproducibility.mdx
@@ -1,38 +1,55 @@
---
-title: "Hermetic Build Reproducibility"
-description: "Achieving 100% bit-for-bit reproducible Protobuf builds with lockfiles, pinned plugin versions, and prohibition of floating latest tags."
+title: "Build Reproducibility"
+description: "Control schema dependencies, generator executables, and build inputs without assuming byte-identical output."
---
-Build reproducibility ensures that checking out a commit today produces the exact same generated output as building it months or years later. This guide explains how EasyP guarantees hermetic, reproducible builds.
+Reproducible generation requires control over schema sources, dependency versions, generator executables, options, and the build environment. EasyP's lockfile verifies dependency inputs; it does not by itself guarantee hermetic or byte-for-byte reproducible output.
----
-
-## 3 Pillars of EasyP Reproducibility
+## Three Inputs to Control
-1. **`protobuf.lock`**: Locks transitive dependency Git commit SHAs and cryptographic content hashes (`h1:...`).
-2. **Pinned Plugin Versions**: Generator plugins in `easyp.gen.yaml` require explicit semantic version tags. Floating `:latest` tags are prohibited.
-3. **WASM / Remote Executors**: Eliminates system environment dependencies (such as locally installed `protoc` or plugin binaries) by running plugins inside deterministic WASM sandboxes or remote generation environments.
-
----
+1. **Schema dependencies:** protobuf.lock records selected dependency versions, Git commits, and h1: content hashes. Commit it together with protobuf.mod and your own schemas.
+2. **Generator versions:** Remote plugins require a pinned semantic version. Local and bundled plugins reject that field: pin local executables in your build environment and pin the EasyP binary that contains bundled generators.
+3. **Execution environment:** Keep plugin options and relevant environment variables consistent. A named built-in plugin can use an executable on PATH instead of the bundled WASM implementation. WASM and remote execution do not independently prove output determinism.
## Workflow for Clean Repositories
-When cloning a repository on a fresh machine or CI runner:
+After preparing the same EasyP and plugin versions used by the project, run from a fresh checkout with a root module and generator file:
-```bash
-# 1. Download exact schema versions locked in protobuf.lock
+~~~bash
easyp mod download
+easyp generate --project .
+~~~
-# 2. Execute code generation using pinned plugin versions
-easyp generate
-```
+mod download installs and verifies the locked dependencies without selecting newer versions or rewriting the lock. Missing dependencies may require downloads. If locked content cannot be retrieved or verified, the command fails; it cannot guarantee that remote repositories remain available forever.
-Because `easyp mod download` reads strictly from `protobuf.lock`, remote registry updates or force-pushed Git tags cannot alter your build output.
+For multiple consumer projects, select them with repeated --project flags or explicitly use --all. Compare generated output in CI and run tests against it. When generated files are committed, a simple check is:
----
+~~~bash
+git diff --exit-code -- gen
+test -z "$(git ls-files --others --exclude-standard -- gen)"
+~~~
+
+Adapt gen to your tracked output directories. The second command catches new untracked files; ignored output is outside this check.
+
+## Local Replacements and Network Access
+
+A local replace redirects one dependency to disk. It avoids dependency downloads only when the whole dependency graph is local or already present in verified cache. Unreplaced dependencies can still require downloads, and a remote generator still needs network access.
+
+Local replacement contents are editable and are not pinned by the published dependency lock. With replacements, mod tidy validates an ephemeral effective graph and leaves the shared manifest/lock unchanged; get/mod update may edit explicit requirements but never write a local-graph lock. Remove replacements and publish the intended versions, then run mod tidy to resolve a release lock.
+
+## CI Practices
+
+- Resolve intended dependency changes in a reviewed update, then use easyp mod download in verification jobs. tidy and update are mutating commands, not a frozen verification mode.
+- Pin the EasyP binary, local plugin executables, and remote plugin versions using the mechanisms appropriate to each source.
+- Keep generated-output checks and consumer tests: valid locks and semantic versions do not prove schema compatibility or identical output bytes.
+
+See [local replacement debugging](/docs/guides/debugging-replace) and [GitHub Actions](/docs/ci-cd/github-actions).
+
+## Explicit frozen verification
-## Prohibited Patterns in CI
+~~~bash
+easyp mod download --frozen
+easyp generate --frozen
+~~~
-- ❌ Running `easyp mod update` inside CI pipelines (updates should only occur locally via PRs).
-- ❌ Using floating plugin tags like `version: latest`.
-- ❌ Leaving uncommitted `replace` directives in `protobuf.mod`.
+Frozen mode validates existing manifests and locks, refuses all main-module local replacements, and never resolves new dependency versions or writes either file. It may fetch exact locked commits into the cache. It is not enabled by the CI environment. Mutating commands such as tidy/update refuse frozen execution; prepare the published graph first. See [frozen configuration](/docs/cli/configuration#explicit-frozen-mode).
diff --git a/content/docs/guides/reproducibility.ru.mdx b/content/docs/guides/reproducibility.ru.mdx
index f3a2153..ac4c7d6 100644
--- a/content/docs/guides/reproducibility.ru.mdx
+++ b/content/docs/guides/reproducibility.ru.mdx
@@ -1,38 +1,55 @@
---
title: "Воспроизводимость сборок"
-description: "Достижение 100% герметичных и воспроизводимых сборок Protobuf с помощью lock-файлов, пина версий плагинов и запрета плавающих тегов latest."
+description: "Контроль зависимостей схем, исполняемых файлов генераторов и входов сборки без обещания побайтово идентичного результата."
---
-Воспроизводимость сборки гарантирует, что клон коммита сегодня даст байт-в-байт тот же результат кодогенерации, что и сборка спустя месяцы или годы. В данном руководстве объясняется, как EasyP обеспечивает герметичность сборок.
+Для воспроизводимой генерации нужно контролировать исходники схем, версии зависимостей, исполняемые файлы генераторов, опции и окружение сборки. Lock-файл EasyP проверяет входные зависимости, но сам по себе не гарантирует герметичность или побайтовую воспроизводимость результата.
----
-
-## 3 кита воспроизводимости EasyP
+## Три группы входных данных
-1. **`protobuf.lock`**: Фиксирует точные SHA коммитов Git и криптографические хеши содержимого (`h1:...`).
-2. **Пины версий плагинов**: Плагины в `easyp.gen.yaml` требуют явных тегов версий. Использование плавающих тегов `:latest` запрещено.
-3. **WASM / Remote исполнители**: Исключают зависимость от окружения хоста (установленных бинарников `protoc` и системных плагинов), заново выполняя генерацию в детерминированном песке WASM или удалённом сервисе.
-
----
+1. **Зависимости схем:** protobuf.lock хранит выбранные версии зависимостей, Git-коммиты и хеши содержимого h1:. Коммитьте его вместе с protobuf.mod и собственными схемами.
+2. **Версии генераторов:** Удалённые плагины требуют фиксированную семантическую version. Локальные и встроенные плагины отклоняют это поле: фиксируйте локальные исполняемые файлы в окружении сборки и бинарник EasyP со встроенными генераторами.
+3. **Окружение выполнения:** Сохраняйте одинаковые опции плагинов и значимые переменные окружения. Встроенный плагин, выбранный по имени, может использовать исполняемый файл из PATH вместо комплектного WASM. WASM и удалённое выполнение сами по себе не доказывают детерминированность результата.
## Процесс работы на свежем окружении
-При клонировании репозитория на новом компьютере или в CI:
+Подготовив те же версии EasyP и плагинов, что использует проект, запустите команды в свежем checkout с корневым модулем и файлом генератора:
-```bash
-# 1. Скачивание точных версий схем строго по protobuf.lock
+~~~bash
easyp mod download
+easyp generate --project .
+~~~
-# 2. Выполнение генерации кода с использованием запиненных версий плагинов
-easyp generate
-```
+mod download устанавливает и проверяет зафиксированные зависимости, не выбирая новые версии и не переписывая lock. Отсутствующие зависимости могут потребовать загрузки. Если зафиксированное содержимое нельзя получить или проверить, команда завершается ошибкой; она не гарантирует вечную доступность удалённых репозиториев.
-Поскольку `easyp mod download` читает данные строго из `protobuf.lock`, изменения в удалённых репозиториях или подмена Git-тегов не влияют на результат.
+Для нескольких проектов-потребителей повторяйте флаг --project или явно используйте --all. Сравнивайте результат генерации в CI и запускайте тесты. Если сгенерированные файлы хранятся в Git, простая проверка выглядит так:
----
+~~~bash
+git diff --exit-code -- gen
+test -z "$(git ls-files --others --exclude-standard -- gen)"
+~~~
+
+Замените gen своими отслеживаемыми каталогами вывода. Вторая команда обнаруживает новые неотслеживаемые файлы; игнорируемый вывод эта проверка не охватывает.
+
+## Локальные замены и сеть
+
+Локальный replace перенаправляет одну зависимость на диск. Загрузки зависимостей не нужны, только если весь граф локальный или уже находится в проверенном кеше. Незаменённым зависимостям всё ещё может потребоваться загрузка, а удалённому генератору — сеть.
+
+Содержимое локальных замен изменяемо и не записывается в опубликованный lock. При наличии замен mod tidy проверяет временный эффективный граф без изменения manifest и lock; get/mod update могут менять явные требования, но не записывают lock локального графа. Уберите замены, опубликуйте нужные версии и выполните mod tidy, чтобы получить lock для релиза.
+
+## Практика CI
+
+- Разрешайте намеренные обновления зависимостей в проверяемом изменении, а в проверочных job используйте easyp mod download. tidy и update изменяют файлы, а не предоставляют режим frozen-проверки.
+- Фиксируйте бинарник EasyP, локальные исполняемые файлы плагинов и версии удалённых плагинов подходящим для каждого источника способом.
+- Сохраняйте проверки сгенерированных файлов и тесты потребителей: корректный lock и семантические версии не доказывают совместимость схем или побайтовую идентичность вывода.
+
+См. [отладку с локальными заменами](/ru/docs/guides/debugging-replace) и [GitHub Actions](/ru/docs/ci-cd/github-actions).
+
+## Явная проверка frozen
-## Запрещённые паттерны в CI
+~~~bash
+easyp mod download --frozen
+easyp generate --frozen
+~~~
-- ❌ Запуск `easyp mod update` внутри CI (обновление версий должно производиться только локально через PR).
-- ❌ Использование плавающих версий плагинов, таких как `version: latest`.
-- ❌ Наличие незакоммиченных директив `replace` в `protobuf.mod`.
+Режим проверяет существующие manifest и lock, запрещает все локальные замены главного модуля и не выбирает новые версии зависимостей, не записывая оба файла. Загрузка точных закреплённых коммитов в кеш разрешена. Переменная CI не включает frozen автоматически. Команды изменения графа, включая tidy/update, отклоняют запуск в frozen; сначала подготовьте опубликованный граф. См. [конфигурацию frozen](/ru/docs/cli/configuration).
diff --git a/content/docs/guides/version-diamond.mdx b/content/docs/guides/version-diamond.mdx
index bdd3e99..ba15967 100644
--- a/content/docs/guides/version-diamond.mdx
+++ b/content/docs/guides/version-diamond.mdx
@@ -1,21 +1,21 @@
---
title: "Resolving Diamond Dependencies"
-description: "How Minimal Version Selection (MVS) deterministically resolves diamond version conflicts across direct and indirect requirements without manual intervention."
+description: "How Minimal Version Selection (MVS) chooses a version in a dependency diamond, and what still needs compatibility testing."
---
-A common conflict in module package management is the **Diamond Dependency Problem**. This guide explains how EasyP's MVS algorithm resolves version discrepancies deterministically without human intervention or SAT solver backtracking.
+The **diamond dependency problem** occurs when direct and transitive requirements request different versions of the same module. EasyP uses MVS to select a version within each module's dependency graph.
---
## Scenario Description
-Consider a service module `user` that relies on two dependencies: `common` and `weather`.
+Consider a service module user that relies on two dependencies: common and weather.
-- `user` explicitly requires `common v1.2.0`.
-- `user` explicitly requires `weather v2.1.0`.
-- `weather v2.1.0` transitively requires `common v1.3.0`.
+- user explicitly requires common v1.2.0.
+- user explicitly requires weather v2.1.0.
+- weather v2.1.0 transitively requires common v1.3.0.
-```text
+~~~text
+-------------------+
| proto/user |
+---------+---------+
@@ -33,26 +33,26 @@ Consider a service module `user` that relies on two dependencies: `common` and `
| github.com/acme/ |
| common v1.3.0 |
+---------------------+
-```
+~~~
---
## The MVS Resolution Rule
-Unlike traditional resolvers that attempt complex range matching or halt with a manual version conflict error, MVS applies a simple high-water mark rule:
+For semantic-version requirements on the same module, MVS selects the highest requested minimum:
-`Resolved Version = max(Requested Minimums)`
+Resolved Version = max(Requested Minimums)
-1. **Collect requested minimums**: `[ v1.2.0 (from user), v1.3.0 (from weather) ]`
-2. **Select maximum**: $\max(v1.2.0, v1.3.0) = v1.3.0$
-3. **Outcome**: `common v1.3.0` is selected for the module resolution graph.
+1. **Collect requested minimums**: [ v1.2.0 (from user), v1.3.0 (from weather) ]
+2. **Select maximum**: max(v1.2.0, v1.3.0) = v1.3.0
+3. **Outcome**: common v1.3.0 is selected for the module resolution graph.
-Because `v1.3.0` is backwards-compatible with `v1.2.0` under Semantic Versioning guidelines, both `user` and `weather` compile successfully against `v1.3.0`.
+MVS selects v1.3.0 from these requirements; it does not test whether either consumer compiles. Semantic version labels express maintainer intent and do not prove schema or generated-code compatibility. Separate root modules resolve independently and can select different versions.
---
## What If Breaking Changes Occur?
-If `v1.3.0` introduced an incompatible schema modification, this represents a semantic versioning violation on the part of `common`'s maintainers.
+If the selected version is incompatible, the graph can resolve successfully while generation or consumer tests fail. Run easyp breaking against an appropriate available baseline before release, then test generated clients. The checker covers its implemented rules and configured scope; it cannot guarantee every consumer remains compatible.
-EasyP catches such violations on the producer side via `easyp breaking` checks before release, ensuring that minor version upgrades remain 100% backwards-compatible.
+This maximum-of-minimums example applies to semantic versions. Different exact commit requirements conflict. An exact commit can coexist with semantic-version requirements only when the selected tag resolves to that same commit. See [dependency resolution](/docs/architecture/mvs-dependency-resolution).
diff --git a/content/docs/guides/version-diamond.ru.mdx b/content/docs/guides/version-diamond.ru.mdx
index b08cf42..6d39219 100644
--- a/content/docs/guides/version-diamond.ru.mdx
+++ b/content/docs/guides/version-diamond.ru.mdx
@@ -1,21 +1,21 @@
---
title: "Разрешение ромбовидных зависимостей (Diamond Dependency)"
-description: "Как алгоритм Minimal Version Selection (MVS) детерминированно решает конфликты ромбовидных зависимостей без ручного вмешательства."
+description: "Как Minimal Version Selection (MVS) выбирает версию в ромбе зависимостей и какие проверки совместимости всё ещё нужны."
---
-Распространённая проблема в управлении пакетами — **проблема ромбовидной зависимости (Diamond Dependency)**. В данном руководстве объясняется, как алгоритм MVS в EasyP детерминированно разрешает расхождения версий без вмешательства человека и без возвратов (backtracking) SAT-солвера.
+**Ромбовидная зависимость** возникает, когда прямые и транзитивные требования задают разные версии одного модуля. EasyP использует MVS для выбора версии внутри графа зависимостей каждого модуля.
---
## Описание сценария
-Рассмотрим модуль сервиса `user`, который зависит от двух пакетов: `common` и `weather`.
+Рассмотрим модуль сервиса user, который зависит от двух пакетов: common и weather.
-- `user` напрямую требует `common v1.2.0`.
-- `user` напрямую требует `weather v2.1.0`.
-- `weather v2.1.0` транзитивно требует `common v1.3.0`.
+- user напрямую требует common v1.2.0.
+- user напрямую требует weather v2.1.0.
+- weather v2.1.0 транзитивно требует common v1.3.0.
-```text
+~~~text
+-------------------+
| proto/user |
+---------+---------+
@@ -33,26 +33,26 @@ description: "Как алгоритм Minimal Version Selection (MVS) детер
| github.com/acme/ |
| common v1.3.0 |
+---------------------+
-```
+~~~
---
## Правило выбора MVS
-В отличие от традиционных менеджер пакетов, пытающихся сопоставлять сложные диапазоны версий или падающих с ошибкой конфликта, MVS применяет правило максимума из минимумов:
+Для семантических требований к одному модулю MVS выбирает наибольший из запрошенных минимумов:
-`Итоговая версия = max(Запрошенных минимумов)`
+Итоговая версия = max(Запрошенных минимумов)
-1. **Сбор требований**: `[ v1.2.0 (от user), v1.3.0 (от weather) ]`
-2. **Выбор максимума**: $\max(v1.2.0, v1.3.0) = v1.3.0$
-3. **Результат**: Для графа модуля выбирается `common v1.3.0`.
+1. **Сбор требований**: [ v1.2.0 (от user), v1.3.0 (от weather) ]
+2. **Выбор максимума**: max(v1.2.0, v1.3.0) = v1.3.0
+3. **Результат**: Для графа модуля выбирается common v1.3.0.
-Поскольку `v1.3.0` обратимо совместима с `v1.2.0` по правилам SemVer, и `user`, и `weather` успешно компилируются с версией `v1.3.0`.
+MVS выбирает v1.3.0 по этим требованиям, но не проверяет компиляцию потребителей. Семантические версии выражают намерение сопровождающих и не доказывают совместимость схем или сгенерированного кода. Отдельные корневые модули разрешаются независимо и могут выбрать разные версии.
---
## Что если возникло ломающее изменение?
-Если бы версия `v1.3.0` содержала несовместимые изменения, это являлось бы нарушением семантического версионирования со стороны разработчиков `common`.
+При несовместимой выбранной версии граф может успешно разрешиться, а генерация или тесты потребителей — упасть. Перед релизом запускайте easyp breaking относительно подходящей доступной базы, затем тестируйте сгенерированные клиенты. Проверка охватывает реализованные правила и настроенную область; она не гарантирует совместимость каждого потребителя.
-EasyP отлавливает такие нарушения на стороне продюсера с помощью команды `easyp breaking` ещё до релиза, гарантируя совместимость минорных обновлений.
+Пример максимума из минимумов относится к семантическим версиям. Разные точные коммиты конфликтуют. Точный коммит может сосуществовать с семантическими требованиями, только если выбранный тег указывает на тот же коммит. См. [разрешение зависимостей](/ru/docs/architecture/mvs-dependency-resolution).
diff --git a/content/docs/introduction/install.mdx b/content/docs/introduction/install.mdx
index f22add4..6478ab8 100644
--- a/content/docs/introduction/install.mdx
+++ b/content/docs/introduction/install.mdx
@@ -1,10 +1,12 @@
---
-title: "Install the EasyP cli"
+title: "Install EasyP"
---
-### Install from system's package manager
+--write and --resolve-lock do not bypass wizard confirmations. No plugin is executed.
+
+Declining, Ctrl+C or EOF before application leaves project files unchanged. Cache entries from previously authorized resolution may remain. A change to the project during the prompts is detected instead of silently overwriting it. The existing restrictions and multi-file crash boundary still apply.
+
+For compatibility, supplying --module without --interactive keeps the existing flag-only behavior, including in a terminal. --interactive=false explicitly disables prompting. Redirected input or output never triggers the wizard, and forced --interactive requires both streams to be terminals; a pipe of yes answers is not accepted as interactive consent. Scripts must supply --module and the relevant explicit flags.
+
+## Preview first
+
+~~~bash
+easyp migrate --dir . --module github.com/acme/contracts
+~~~
+
+In flag-only mode, without --write, the command prints actual candidate files and warnings. It does not change the project or execute plugins. A plain preview does not resolve dependencies or write their cache.
+
+The candidate files are easyp.yaml for policies, easyp.gen.yaml for generation, protobuf.mod for module metadata, and a verified protobuf.lock when dependency conversion is required. The supplied module identity is literal and must match the intended local module.
+
+## Verify dependencies and apply
+
+~~~bash
+# Explicitly permit dependency access/cache writes while still previewing.
+easyp migrate --dir . --module github.com/acme/contracts --resolve-lock
+
+# Apply only after the complete candidate set passes validation.
+easyp migrate --dir . --module github.com/acme/contracts --resolve-lock --write
+~~~
+
+For a dependency-free project, --resolve-lock is unnecessary. With dependencies, --write without completed lock verification fails before writing the candidate configuration. No generation plugin is run by either command.
+
+Modified legacy policy and manifest files receive byte-identical .v0.bak backups. Existing conflicting v1 files or backups are not overwritten. Original permissions are preserved when replacing a legacy file. The old easyp.lock remains unchanged as a historical record. A repeated migration of a validated v1 project is a no-op; it does not update dependencies.
+
+## What is preserved
+
+The converter preserves the effective selected lint rules, exceptions, rule settings, and explicit legacy comment-suppression setting. It converts literal ignores and rule-specific prefix ignores to the corresponding v1 exclusions. Generation preserves plugin sources, argv, options, with_imports, and supported managed settings. Relative paths remain relative to the configuration directory.
+
+Legacy direct and indirect requirements are converted to native require directives. The tool checks that whole v1 source roots would select the same local protobuf files with the same import paths. It does not silently expand a sliced input into an entire module.
+
+Variable placeholders are not expanded into saved values. If a placeholder or selector prevents safe analysis, conversion fails rather than persisting credentials or guessing its meaning.
+
+## Historical lock integrity
+
+A full commit SHA is preserved, including a full SHA embedded in an old pseudo-version. For a legacy lock entry containing a tag but no SHA, conversion resolves that tag and verifies the historical installed-tree hash before accepting the revision. A moved tag or mismatched historical hash is an error.
+
+The v1 content hash is then calculated independently over the tracked repository files. Old and new hashes cover different path layouts and cannot be copied or compared as interchangeable values. A missing historical dependency pin is not replaced with current HEAD.
+
+## Explicit limitations
+
+Unknown fields, invalid or multi-document YAML, ambiguous source selection, unsupported references, and conflicting native outputs are rejected. Custom Git-input roots/subdirectories, external or sliced local inputs whose exact selection cannot be preserved, unsafe managed selectors, and full lock conversion with local replacements may require manual migration. Buf configurations are not inputs to this v0 converter.
+
+The command stages all outputs and checks observed inputs again before applying. Ordinary application failures are rolled back. Several file replacements are not one process-crash-atomic transaction: after a machine or process failure, inspect the preserved backups and Git state before continuing. Uncooperative concurrent writers cannot be made safe by this command.
+
+## Verify the result
+
+~~~bash
+easyp validate-config
+easyp mod download
+easyp lint
+easyp generate
+~~~
+
+Run mod download when the migrated project has a lock. Check real generated code, not only the exit status of configuration validation. Recursive multi-project generation now requires explicit --all or repeated --project; migration does not authorize unrelated projects.
+
+Command plugins now receive literal argv rather than an implicitly assembled shell command. Review legacy commands that relied on shell operators; use an explicit shell invocation only when that is intentional. Migration does not prove equivalence of arbitrary plugin side effects.
+
+An unsuffixed native v2+ dependency cannot be converted automatically. Select a published /vN identity and matching version, or a valid v0/v1 release; migration never renames dependencies or substitutes versions. An explicit +incompatible requirement is eligible only when the exact revision has no native manifest; migration does not add the marker speculatively. Requirements from older metadata are also checked when used at the native source boundary. See [major version identities](/docs/reference/protobuf-mod).
diff --git a/content/docs/migration/easyp-v0.ru.mdx b/content/docs/migration/easyp-v0.ru.mdx
new file mode 100644
index 0000000..7118b20
--- /dev/null
+++ b/content/docs/migration/easyp-v0.ru.mdx
@@ -0,0 +1,83 @@
+---
+title: "Переход с EasyP v0 на v1"
+description: "Миграция с предварительным просмотром, сохранением настроек и проверкой исторических зависимостей."
+---
+
+CLI v1 не исполняет старый объединённый конфиг. Для поддерживаемых однозначных v0-проектов предусмотрена отдельная команда миграции. Перед применением сохраните проект в Git и остановите другие процессы, изменяющие его файлы.
+
+## Интерактивный мастер в терминале
+
+~~~bash
+# Мастер запускается, когда ввод и вывод подключены к терминалу.
+easyp migrate
+
+# Явный запуск с заранее заполненными значениями.
+easyp migrate --interactive --dir . --module github.com/acme/contracts
+~~~
+
+Мастер запрашивает каталог проекта и идентификатор модуля, если они не переданы флагами. Он может предложить идентификатор из существующего native-manifest или локального Git origin текущего каталога; предложение всё равно нужно принять явно. Для этой подсказки нет обращения к серверу и не выводятся учётные данные Git.
+
+Сначала показывается фактическое содержимое будущих файлов. Если необходима проверка зависимостей, мастер отдельно запрашивает разрешение на их загрузку и проверку с записью кэша. Затем показывает полный проверенный план, включая lock, и спрашивает, применять ли его с созданием резервных копий. Enter означает **нет** в обоих подтверждениях. Даже заранее переданные --write и --resolve-lock не обходят подтверждения мастера. Плагины не запускаются.
+
+Отказ, Ctrl+C или EOF до применения оставляют файлы проекта неизменными. Кэш ранее разрешённой загрузки может сохраниться. Изменения проекта во время вопросов обнаруживаются, а не перезаписываются молча. Прежние ограничения миграции и граница атомарности при падении процесса сохраняются.
+
+Для совместимости --module без --interactive сохраняет прежнее поведение через флаги, в том числе в терминале. --interactive=false явно отключает вопросы. Перенаправленный ввод или вывод не запускает мастер автоматически; принудительный --interactive требует терминала для обоих потоков. Передача yes через pipe не считается интерактивным согласием. Скриптам нужно задавать --module и необходимые явные флаги.
+
+## Сначала предварительный просмотр
+
+~~~bash
+easyp migrate --dir . --module github.com/acme/contracts
+~~~
+
+В режиме явных флагов без --write команда показывает фактическое содержимое будущих файлов и предупреждения. Файлы проекта не меняются, плагины не запускаются. Обычный предварительный просмотр не разрешает зависимости и не записывает их кэш.
+
+Подготавливаются easyp.yaml с политиками, easyp.gen.yaml с генерацией, protobuf.mod с метаданными модуля и проверенный protobuf.lock, когда требуется перенос зависимостей. Явно указанный идентификатор должен соответствовать локальному модулю.
+
+## Проверка зависимостей и применение
+
+~~~bash
+# Разрешить доступ к зависимостям и запись кэша, но не менять проект.
+easyp migrate --dir . --module github.com/acme/contracts --resolve-lock
+
+# Применить только после проверки всего набора файлов.
+easyp migrate --dir . --module github.com/acme/contracts --resolve-lock --write
+~~~
+
+Проекту без зависимостей --resolve-lock не требуется. При наличии зависимостей применение без завершённой проверки lock-файла отклоняется до записи конфигурации. Ни одна из этих команд не запускает плагины генерации.
+
+Для заменяемых legacy-политики и manifest создаются побайтовые резервные копии .v0.bak. Конфликтующие v1-файлы и существующие резервные копии не перезаписываются. При замене legacy-файла сохраняются его права. Старый easyp.lock остаётся неизменным историческим свидетельством. Повторная миграция проверенного v1-проекта ничего не меняет и не обновляет зависимости.
+
+## Что переносится
+
+Сохраняются фактически выбранные lint-правила, исключения, параметры правил и прежняя явная настройка подавления комментариями. Буквальные исключения и префиксные исключения отдельных правил преобразуются в соответствующие правила v1. В генерации сохраняются источники плагинов, argv, options, with_imports и поддерживаемые managed-настройки. Относительные пути остаются привязанными к каталогу конфигурации.
+
+Legacy-требования direct и indirect преобразуются в require. Проверяется, что новые корни целиком выбирают те же локальные protobuf-файлы с теми же import-путями. Выбранная часть каталога не расширяется молча до всего модуля.
+
+Подстановки переменных не сохраняются в раскрытом виде. Если переменная или selector мешает безопасному анализу, перенос останавливается, а не записывает секреты и не угадывает смысл настройки.
+
+## Целостность исторического lock-файла
+
+Полный SHA коммита сохраняется, в том числе когда он встроен в старую псевдоверсию. Если запись содержит только тег, миграция разрешает его и проверяет исторический хеш установленного дерева перед принятием ревизии. Перенос тега или несовпадение прежнего хеша приводит к ошибке.
+
+После проверки новый хеш v1 рассчитывается независимо по отслеживаемым файлам репозитория. Старый и новый хеши относятся к разным раскладкам путей; их нельзя просто копировать или считать взаимозаменяемыми. Отсутствующий исторический pin не заменяется текущим HEAD.
+
+## Явные ограничения
+
+Неизвестные поля, некорректный YAML или несколько YAML-документов, неоднозначный набор исходников, неподдерживаемые refs и конфликтующие native-файлы отклоняются. Нестандартные root/sub_directory Git-input, внешние или частичные локальные inputs с непереносимой выборкой, неоднозначные managed selectors и полный перенос lock при локальных заменах могут потребовать ручной миграции. Buf-конфигурация не является входом этого v0-конвертера.
+
+Все результаты сначала подготавливаются, затем состояние входов проверяется повторно. Обычные ошибки применения вызывают откат. Несколько замен файлов не образуют общую транзакцию, атомарную при падении процесса или компьютера: после такого сбоя нужно проверить резервные копии и Git-состояние. Команда не гарантирует безопасность при записи файлов посторонними несогласованными процессами.
+
+## Проверка результата
+
+~~~bash
+easyp validate-config
+easyp mod download
+easyp lint
+easyp generate
+~~~
+
+Запускайте mod download, когда у мигрированного проекта есть lock-файл. Проверяйте реально сгенерированный код, а не только успешную валидацию. Для рекурсивной генерации нескольких проектов теперь нужны явный --all или повторяемый --project; миграция не разрешает запуск посторонних проектов.
+
+Command-плагины теперь получают буквальный argv, а не неявно собранную shell-команду. Проверьте старые команды, использовавшие shell-операторы; явный shell нужен только при намеренном исполнении скрипта. Миграция не доказывает эквивалентность произвольных побочных эффектов плагинов.
+
+Нативный v2+ без мажорного суффикса не переносится автоматически. Выберите опубликованное имя /vN и соответствующую версию либо допустимый релиз v0/v1; миграция не переименовывает зависимости и не подменяет версии. Явная метка +incompatible допустима только при отсутствии нативного manifest в точной ревизии; миграция не добавляет её предположительно. Требования из старых метаданных также проходят проверку при использовании нативного источника. См. [идентичность мажорных версий](/ru/docs/reference/protobuf-mod).
diff --git a/content/docs/migration/meta.json b/content/docs/migration/meta.json
index 55dbd09..f4cd277 100644
--- a/content/docs/migration/meta.json
+++ b/content/docs/migration/meta.json
@@ -1,6 +1,7 @@
{
"title": "Migration",
"pages": [
+ "easyp-v0",
"buf-cli",
"protoc",
"protolock",
diff --git a/content/docs/migration/protoc.mdx b/content/docs/migration/protoc.mdx
index b4c04c3..f67e643 100644
--- a/content/docs/migration/protoc.mdx
+++ b/content/docs/migration/protoc.mdx
@@ -1,5 +1,64 @@
---
-title: "Protoc"
+title: "Moving from protoc to EasyP v1"
---
-## Work in progress
+Map the existing source roots, plugins and checks to v1 explicitly. The easyp migrate command accepts EasyP v0 configuration, not arbitrary scripts or another tool's configuration. Keep the original inputs and generated output for comparison.
+
+## Module and source roots
+
+protobuf.mod:
+
+~~~text
+module github.com/acme/contracts
+roots proto
+~~~
+
+A file at proto/hello/v1/hello.proto has the import name hello/v1/hello.proto. If the previous invocation selected only part of a root, do not silently broaden it: v1 generates complete selected modules.
+
+## Generation
+
+easyp.gen.yaml:
+
+~~~yaml
+version: v1
+plugins:
+ - name: go
+ out: gen/go
+ opts: [paths=source_relative]
+ - name: go-grpc
+ out: gen/go
+ opts: [paths=source_relative]
+~~~
+
+Pin the actual plugin executables in the environment. Preserve existing go_package values and align them with the physical output. Set with_imports: true per plugin when imported contracts also need generated code; this is independent of descriptor export.
+
+## Check policy
+
+easyp.yaml:
+
+~~~yaml
+version: v1
+linters:
+ default: BASIC
+breaking:
+ baseline: git:main
+ categories: [FILE]
+~~~
+
+Map individual checks by their actual identifiers and results; similarly named presets in different tools do not prove equivalence. breaking.ignore contains paths, not rule names.
+
+## Dependencies and result verification
+
+Declare external dependencies with easyp get or manifest require directives. An arbitrary proto import does not uniquely identify a Git source. Run mod tidy for initial resolution and commit the lock; subsequent checks use mod download, not an implicit version update.
+
+~~~bash
+easyp validate-config
+easyp mod tidy
+easyp lint
+easyp breaking --against main
+easyp generate
+~~~
+
+The selected baseline must exist locally. Compare filenames, import paths and contents with the old generator, then build and test the consumer. Keep the old scripts until this comparison succeeds. Multiple projects require repeated --project or explicit --all.
+
+For an existing EasyP v0 project, start with the [migration preview](/docs/migration/easyp-v0).
diff --git a/content/docs/migration/protoc.ru.mdx b/content/docs/migration/protoc.ru.mdx
index 79b288d..2b6c12a 100644
--- a/content/docs/migration/protoc.ru.mdx
+++ b/content/docs/migration/protoc.ru.mdx
@@ -1,250 +1,64 @@
---
-title: "Миграция с protoc на EasyP"
+title: "Переход с protoc на EasyP v1"
---
-> Исходная англоязычная версия файла содержала только заголовок и пометку “Work in progress”. Ниже — полноценный русскоязычный черновик раздела миграции. Уточни, если требуется сократить или изменить уровень детализации.
-
-## 1. Краткое сравнение
-
-| Аспект | `protoc` | EasyP |
-|--------|----------|-------|
-| Базовая роль | Базовый компилятор `.proto` файлов | Инструмент “всё в одном”: линтинг, проверка несовместимых изменений, менеджер пакетов, генерация |
-| Конфигурация | Чаще shell‑скрипты / Makefile / вручную передаваемые флаги | Единый файл `easyp.yaml` (YAML или JSON) |
-| Управление зависимостями | Ручной `git clone`, `submodule`, vendoring | Секция `deps` с Git‑репозиториями |
-| Набор правил линтера | Нет встроенного | Встроенный линтер с правилами (можно включать/исключать) |
-| Проверка breaking changes | Отсутствует из коробки | Команда `easyp breaking` |
-| Расширенные плагины | Установка и вызов через флаги `--plugin` | Плагины через конфиг; поддержка удалённого выполнения (API Service) и стандартного локального |
-| Единообразие в CI | Нужно собирать вручную | Консистентные команды: `lint`, `breaking`, `generate` |
-
-## 2. Когда имеет смысл мигрировать
-
-Миграция на EasyP особенно полезна если:
-- Есть потребность в автоматической проверке качества (стиль, именование) `.proto` файлов.
-- Нужна защита от нелегитимных несовместимых изменений при эволюции схем.
-- В проекте используется несколько языков генерации и растёт число скриптов вокруг `protoc`.
-- Вы хотите единый конфиг вместо множества shell/Makefile комбинаций.
-- Планируется централизованное исполнение плагинов (через API Service) или унификация окружения в CI.
-
-## 3. Типичный сценарий “до” (только protoc)
-
-Пример: локальные скрипты / Makefile:
-
-```makefile
-protoc \
- -I . \
- -I third_party \
- --go_out=./gen/go --go_opt=paths=source_relative \
- --go-grpc_out=./gen/go --go-grpc_opt=paths=source_relative \
- api/echo/v1/echo.proto
-```
-
-Дополнительные зависимости (googleapis, validate, grpc-gateway) скачиваются вручную или через submodules.
-
-## 4. Типичный сценарий “после” (EasyP)
-
-Единый файл `easyp.yaml`:
-
-```yaml
-deps:
- - github.com/googleapis/googleapis
- - github.com/envoyproxy/protoc-gen-validate
-
-generate:
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
- - name: validate
- out: gen/go
- opts:
- paths: source_relative
- lang: "go"
-```
-
-Команды:
-```bash
-easyp mod update # Скачивание/обновление deps
-easyp lint # Линтинг .proto
-easyp breaking --against git-ref=origin/main
-easyp generate # Генерация кода
-```
-
-## 5. Пошаговая миграция
-
-1. Инвентаризация:
- - Соберите список всех вызовов `protoc` (скрипты, Makefile, CI).
- - Зафиксируйте используемые плагины и их версии.
-2. Создание `easyp.yaml`:
- - Поле `version` не обязательно (можете оставить его только для обратной совместимости).
- - Перенесите плагины в секцию `generate.plugins`.
- - Укажите опции, которые ранее передавались в командной строке.
-3. Зависимости:
- - Все внешние каталоги (googleapis, validate, grpc-gateway и т.п.) занесите в `deps`.
- - Удалите лишние submodules при необходимости.
-4. Линтер:
- - Запустите `easyp lint` и посмотрите на предупреждения.
- - При необходимости добавьте `lint.use`, `lint.ignore`, `lint.except`.
-5. Проверка breaking changes:
- - Выберите референс (обычно `origin/main` или предыдущий тег).
- - Запустите `easyp breaking --against git-ref=origin/main`.
- - Настройте игнорируемые изменения (`breaking.ignore`), если нужно.
-6. Обновление CI:
- - Замените прямые вызовы `protoc` на `easyp generate`.
- - Добавьте отдельные шаги `lint` и `breaking`.
-7. Очистка:
- - Удалите устаревшие генерационные скрипты, если они дублируют функционал EasyP.
-8. Документация:
- - Обновите README / CONTRIBUTING (новый способ генерации).
-9. Верификация:
- - Сравните результат генерации до и после (git diff).
- - Убедитесь, что имена файлов и пути совпадают или скорректируйте структуру.
-
-## 6. Замена в CI (пример GitHub Actions)
-
-```yaml
-- name: Install EasyP
- run: go install github.com/easyp-tech/easyp/cmd/easyp@latest
-
-- name: Lint
- run: easyp lint
-
-- name: Breaking
- run: easyp breaking --against git-ref=origin/main
-
-- name: Generate
- run: easyp generate
-```
-
-## 7. Работа с плагинами
-
-| Тип | В protoc | В EasyP |
-|-----|----------|---------|
-| Стандартные (`protoc-gen-go`) | Указание через `--go_out` | `plugins: - name: go ...` |
-| gRPC | `--go-grpc_out` | Второй плагин `go-grpc` |
-| Validate | Доп. установка + `--validate_out` | `- name: validate` с opts |
-| gRPC-Gateway / OpenAPI | `--grpc-gateway_out` / `--openapiv2_out` | Плагины `grpc-gateway`, `openapiv2` |
-| Кастомные | Путь к бинарю / `--plugin=protoc-gen-xxx` | `- name: xxx` или удалённый `remote:` (если используется API Service) |
-
-Если вы переходите на удалённое выполнение (API Service), записи в конфиге могут выглядеть так:
-
-```yaml
-generate:
- plugins:
- - remote: api.easyp.tech/protobuf/go:v1.36.10
- out: gen/go
- opts:
- paths: source_relative
-```
-
-## 8. Проверка корректности после миграции
-
-1. `git diff` после `easyp generate` — не должно быть неожиданных изменений.
-2. Сравнить размер и содержимое каталога сгенерированных файлов.
-3. Запустить ваш потребляющий код (сборка, тесты).
-4. Проверить, что плагины (validate, grpc-gateway) продолжают вставлять необходимые аннотации / опции.
-5. Линт не должен выдавать критичных ошибок — скорректируйте стиль .proto, если требуется.
-
-## 9. Частые проблемы
-
-| Проблема | Причина | Решение |
-|----------|---------|---------|
-| Плагин не найден | Не установлен или не указан в PATH | Выполнить `go install ...` или добавить в конфиг как remote |
-| Ошибка импорта `.proto` | Отсутствует репозиторий в `deps` | Добавить адрес в секцию `deps` и `easyp mod update` |
-| Несовместимые изменения на каждом PR | Отсутствует игнор/настройка сравнения | Уточнить ветку/тег в `--against` или настроить `breaking.ignore` |
-| Локально работает, в CI падает | В CI нет зависимостей (не вызван update) | Добавить шаг `easyp mod update` перед `generate` |
-| Дубликаты сгенерированных файлов | Изменена структура путей или `out` | Синхронизировать `out` и `paths: source_relative` опции |
-
-## 10. Минимальный пример конфигурации (только Go)
-
-```yaml
-generate:
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
-```
-
-Команды:
-```bash
-easyp generate
-```
-
-## 11. Расширенный пример (Go + gRPC + Gateway + Validate + Breaking и Lint)
-
-```yaml
-lint:
- use:
- - ENUM_FIRST_VALUE_ZERO
- - SERVICE_SUFFIX
- allow_comment_ignores: false
- enum_zero_value_suffix: _NONE
- service_suffix: Service
-
-deps:
- - github.com/googleapis/googleapis
- - github.com/envoyproxy/protoc-gen-validate
-
-generate:
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
- - name: validate
- out: gen/go
- opts:
- paths: source_relative
- lang: "go"
- - name: grpc-gateway
- out: gen/go
- opts:
- paths: source_relative
- - name: openapiv2
- out: gen/openapi
- opts:
- simple_operation_ids: true
+Это ручное сопоставление существующих исходников, плагинов и правил с v1. Команда easyp migrate принимает конфигурацию EasyP v0, а не произвольные скрипты или конфигурацию другого инструмента. Сохраните исходные файлы и результаты прежней генерации для сравнения.
-breaking:
- against_git_ref: main
- ignore:
- - ENUM_VALUE_SAME_NAME
-```
+## Модуль и исходники
-## 12. Checklist миграции
+protobuf.mod:
-- [ ] Собраны все текущие вызовы `protoc`.
-- [ ] Создан `easyp.yaml` с секциями `generate` и (опционально) `lint`, `breaking`.
-- [ ] Добавлены все внешние зависимости в `deps`.
-- [ ] Успешно выполнен `easyp mod update`.
-- [ ] `easyp generate` даёт идентичный или ожидаемо обновлённый результат.
-- [ ] `easyp lint` проходит без критичных ошибок (или ошибки обработаны).
-- [ ] `easyp breaking --against git-ref=origin/main` не выдаёт неожиданных блокирующих нарушений.
-- [ ] CI обновлён (заменены прямые вызовы `protoc`).
-- [ ] Документация проекта обновлена (README: как генерировать).
+~~~text
+module github.com/acme/contracts
+roots proto
+~~~
-## 13. Дополнительные рекомендации
+Путь proto/hello/v1/hello.proto имеет import-имя hello/v1/hello.proto. Если прежний запуск выбирал только часть корня, не переносите его механически на весь модуль: v1 генерирует целые выбранные модули.
-- Сначала мигрируйте один сервис / пакет — снизит риск массовых конфликтов.
-- Закоммитьте `easyp.yaml` отдельно, затем выполните генерацию и линт — проще ревью.
-- Если нужны разные наборы плагинов для разных микросервисов — используйте несколько конфигов (например: `easyp.microservice-a.yaml` + `easyp.microservice-b.yaml`).
-- Внедрите проверку актуальности генерации: шаг CI, который валидирует отсутствие diff после `easyp generate`.
+## Генерация
-## 14. Статус
+easyp.gen.yaml:
-Этот файл — русская расширенная версия, заменяющая placeholder “Work in progress”. При появлении новых возможностей EasyP (дополнительные поля в конфиге, новые плагины, расширения breaking‑проверок) обновите соответствующие разделы.
+~~~yaml
+version: v1
+plugins:
+ - name: go
+ out: gen/go
+ opts: [paths=source_relative]
+ - name: go-grpc
+ out: gen/go
+ opts: [paths=source_relative]
+~~~
----
+Зафиксируйте версии используемых исполняемых плагинов в окружении. Сохраните прежние go_package и согласуйте их с физическим output. При необходимости генерировать также импорты включите with_imports: true у конкретного плагина. Это не параметр descriptor export.
+
+## Политика проверок
+
+easyp.yaml:
+
+~~~yaml
+version: v1
+linters:
+ default: BASIC
+breaking:
+ baseline: git:main
+ categories: [FILE]
+~~~
+
+Сопоставляйте отдельные правила по фактическим именам и результатам; одинаковые названия пресетов разных инструментов не доказывают эквивалентность. breaking.ignore содержит пути, а не имена правил.
+
+## Зависимости и проверка результата
+
+Объявите внешние зависимости через easyp get или require в manifest. Git-источник нельзя однозначно угадать по произвольному proto-import. Для первоначального разрешения выполните mod tidy и закоммитьте lock; в последующих проверках используйте mod download, а не обновление версий.
+
+~~~bash
+easyp validate-config
+easyp mod tidy
+easyp lint
+easyp breaking --against main
+easyp generate
+~~~
+
+Указанный baseline должен быть доступен локально. Сравните с прежней генерацией имена файлов, import paths и содержимое, затем соберите и протестируйте потребляющий проект. Не удаляйте прежние скрипты до этого сравнения. Для нескольких проектов используйте повторяемый --project или явно разрешённый --all.
-Если нужен упрощённый вариант (только перевод без расширения), сообщи — могу сократить до минимальных двух блоков.
+Если исходный проект уже использует EasyP v0, начните с [предварительного просмотра миграции](/docs/migration/easyp-v0).
diff --git a/content/docs/migration/prototool.mdx b/content/docs/migration/prototool.mdx
index 7ee311d..4d6480b 100644
--- a/content/docs/migration/prototool.mdx
+++ b/content/docs/migration/prototool.mdx
@@ -1,5 +1,64 @@
---
-title: "Prototool"
+title: "Moving from prototool to EasyP v1"
---
-## Work in progress
+Map the existing source roots, plugins and checks to v1 explicitly. The easyp migrate command accepts EasyP v0 configuration, not arbitrary scripts or another tool's configuration. Keep the original inputs and generated output for comparison.
+
+## Module and source roots
+
+protobuf.mod:
+
+~~~text
+module github.com/acme/contracts
+roots proto
+~~~
+
+A file at proto/hello/v1/hello.proto has the import name hello/v1/hello.proto. If the previous invocation selected only part of a root, do not silently broaden it: v1 generates complete selected modules.
+
+## Generation
+
+easyp.gen.yaml:
+
+~~~yaml
+version: v1
+plugins:
+ - name: go
+ out: gen/go
+ opts: [paths=source_relative]
+ - name: go-grpc
+ out: gen/go
+ opts: [paths=source_relative]
+~~~
+
+Pin the actual plugin executables in the environment. Preserve existing go_package values and align them with the physical output. Set with_imports: true per plugin when imported contracts also need generated code; this is independent of descriptor export.
+
+## Check policy
+
+easyp.yaml:
+
+~~~yaml
+version: v1
+linters:
+ default: BASIC
+breaking:
+ baseline: git:main
+ categories: [FILE]
+~~~
+
+Map individual checks by their actual identifiers and results; similarly named presets in different tools do not prove equivalence. breaking.ignore contains paths, not rule names.
+
+## Dependencies and result verification
+
+Declare external dependencies with easyp get or manifest require directives. An arbitrary proto import does not uniquely identify a Git source. Run mod tidy for initial resolution and commit the lock; subsequent checks use mod download, not an implicit version update.
+
+~~~bash
+easyp validate-config
+easyp mod tidy
+easyp lint
+easyp breaking --against main
+easyp generate
+~~~
+
+The selected baseline must exist locally. Compare filenames, import paths and contents with the old generator, then build and test the consumer. Keep the old scripts until this comparison succeeds. Multiple projects require repeated --project or explicit --all.
+
+For an existing EasyP v0 project, start with the [migration preview](/docs/migration/easyp-v0).
diff --git a/content/docs/migration/prototool.ru.mdx b/content/docs/migration/prototool.ru.mdx
index eafeaae..747b982 100644
--- a/content/docs/migration/prototool.ru.mdx
+++ b/content/docs/migration/prototool.ru.mdx
@@ -1,242 +1,64 @@
---
-title: "Prototool"
+title: "Переход с prototool на EasyP v1"
---
-## Состояние
-Этот раздел был помечен как “Work in progress” в оригинальной английской версии. Ниже — переведённое и дополненное практическое руководство по миграции с Prototool на EasyP. Имя инструмента Prototool не переводится.
+Это ручное сопоставление существующих исходников, плагинов и правил с v1. Команда easyp migrate принимает конфигурацию EasyP v0, а не произвольные скрипты или конфигурацию другого инструмента. Сохраните исходные файлы и результаты прежней генерации для сравнения.
----
-
-## Цель миграции
-Перейти от конфигурации и рабочих процессов Prototool к эквиваленту на EasyP с минимальными изменениями, сохранив:
-- Линтинг .proto файлов.
-- Генерацию кода через protoc-плагины.
-- Управление зависимостями.
-- Проверку несовместимых изменений (в Prototool это приходилось реализовывать внешними инструментами; в EasyP встроено).
-
----
-
-## Кратко о различиях
-
-| Область | Prototool | EasyP | Комментарий |
-|---------|-----------|-------|-------------|
-| Конфигурация | `prototool.yaml` | `easyp.yaml` | Форматы YAML/JSON поддерживаются; структура отличается. |
-| Линтинг | Встроенные наборы + кастомные правила | Наборы через `lint.use`, тонкая настройка ignore/except | EasyP даёт больше гибкости группировки. |
-| Генерация | Раздел `generate` + плагины через Docker/локально | `generate.plugins` (локальные/WASM/удалённые) | EasyP может выполнять плагины удалённо (API Service). |
-| Зависимости | Обычно через include-пути / внешние git clone вручную | Секция `deps` (Git репозитории) + `mod update` | Более декларативно. |
-| Breaking Changes | Нет встроенного механизма | Секция `breaking` + команда `easyp breaking` | Из коробки. |
-| Lock-in | Зависимость от модели Prototool | Минималистичный формат, «любой Git — пакет» | Облегчает выход / интеграцию с другими экосистемами. |
-
----
-
-## Типовая структура Prototool (упрощённо)
-
-```yaml
-# prototool.yaml (пример)
-protoc:
- include_paths:
- - api
- - third_party
-lint:
- group: basic
- rules:
- add:
- - ENUM_VALUE_PREFIX
-generate:
- plugins:
- - name: go
- out: gen/go
- - name: go-grpc
- out: gen/go
-```
-
-Особенности:
-- `include_paths` задаёт пути поиска импортов.
-- `lint.group` + `rules.add/remove` регулируют активные проверки.
-- `generate.plugins` описывает плагины для protoc.
-
----
-
-## Эквивалент на EasyP
-
-```yaml
-# easyp.yaml (пример)
-deps:
- - github.com/org/common-protos # вместо manual include
- - github.com/org/third-party-protos
-
-lint:
- use:
- - MINIMAL
- - BASIC
- enum_zero_value_suffix: "_NONE"
- service_suffix: "Service"
- ignore:
- - COMMENT_FIELD
- except:
- - ENUM_VALUE_PREFIX
- allow_comment_ignores: true
-
-generate:
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
- - name: go-grpc
- out: gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
-
-breaking:
- against_git_ref: main
- ignore:
- - FIELD_SAME_TYPE
-```
-
-Комментарии:
-- `deps` заменяет необходимость вручную прописывать include paths: EasyP подтянет их через git.
-- `lint.use` активирует наборы правил (MINIMAL/BASIC/DEFAULT и т.д.).
-- Дополнительные настройки (`enum_zero_value_suffix`, `service_suffix`) задают политики нейминга.
-- `breaking` позволяет сразу контролировать несовместимые изменения.
-
----
-
-## Шаги миграции
-
-1. Инвентаризация:
- - Соберите текущий `prototool.yaml`, списки include paths и плагины.
- - Зафиксируйте используемые кастомные правила, если есть.
-
-2. Зависимости:
- - Любые каталоги, которые вы вручную добавляли в `include_paths`, преобразуйте в git-репозитории (если ещё нет).
- - Добавьте их в `deps` (формат: `github.com/owner/repo` или путь к вашей приватной системе Git).
-
-3. Линтинг:
- - Определите какой group использовался (`basic`, `default`, …) → сопоставьте с наборами EasyP (`MINIMAL`, `BASIC`, `DEFAULT`).
- - Индивидуальные добавления (`rules.add`) перенесите в `lint.use` или `except`/`ignore`:
-```
- - Если правило нужно активировать — включите через набор или явно.
- - Если нужно отключить — добавьте в `ignore`.
-```
-
-4. Генерация:
- - Сохраните список плагинов. В большинстве случаев имена совпадут (`go`, `go-grpc`, др.).
- - Если раньше использовали Docker-окружение Prototool — проверьте поддержку удалённых плагинов через API Service EasyP (опционально).
- - Перепишите в секцию `generate.plugins`.
-
-5. Дополнительные опции:
- - Настройки нейминга enum/service перенести в `enum_zero_value_suffix`, `service_suffix`.
- - Если были внешние скрипты для проверки breaking changes — удалите их и включите `breaking` с `against_git_ref`.
+## Модуль и исходники
-6. Верификация:
- - Запустите: `easyp mod update` (скачивание deps).
- - Затем: `easyp lint`.
- - Далее: `easyp generate`.
- - И, если нужно: `easyp breaking --against git-ref=origin/main`.
+protobuf.mod:
-7. CI/CD:
- - Обновите workflow (GitHub Actions / GitLab) — замените вызовы Prototool на EasyP команды.
- - Добавьте шаг проверки несовместимых изменений.
+~~~text
+module github.com/acme/contracts
+roots proto
+~~~
----
-
-## Сопоставление правил (общая идея)
-
-| Prototool концепт | EasyP |
-|-------------------|------|
-| lint.group | lint.use (наборы) |
-| rules.add/remove | except / ignore |
-| include_paths | deps (git источники) |
-| plugins | generate.plugins |
-| (внешние скрипты для breaking) | breaking секция + команда |
+Путь proto/hello/v1/hello.proto имеет import-имя hello/v1/hello.proto. Если прежний запуск выбирал только часть корня, не переносите его механически на весь модуль: v1 генерирует целые выбранные модули.
----
-
-## Приватные репозитории
+## Генерация
-Если ранее Prototool просто видел локальные каталоги, теперь:
-- Добавьте SSH ключи/токены в CI для доступа к приватным Git.
-- Укажите их в `deps` как обычные git-URL (формат зависит от реализации EasyP; для публичных — стандартный).
+easyp.gen.yaml:
----
+~~~yaml
+version: v1
+plugins:
+ - name: go
+ out: gen/go
+ opts: [paths=source_relative]
+ - name: go-grpc
+ out: gen/go
+ opts: [paths=source_relative]
+~~~
-## Типовые проблемы при миграции
+Зафиксируйте версии используемых исполняемых плагинов в окружении. Сохраните прежние go_package и согласуйте их с физическим output. При необходимости генерировать также импорты включите with_imports: true у конкретного плагина. Это не параметр descriptor export.
-| Проблема | Причина | Решение |
-|----------|---------|---------|
-| Правила линтера не совпадают | Неверное сопоставление групп | Проверить документацию EasyP по наборам правил |
-| Импорты не находятся | Забыли добавить репозиторий в deps | Добавить в `deps` и выполнить `easyp mod update` |
-| Генерация падает на опциях | Плагин требует другие flags | Проверить `opts` и документацию плагина |
-| breaking сообщает слишком много | Слишком строгий базовый набор | Добавить конкретные правила в `breaking.ignore` |
-| Долгая генерация | Нет кеша/много deps | Включить кэширование в CI (vendor/.easyp/deps) |
+## Политика проверок
----
+easyp.yaml:
-## Минимальная конфигурация после миграции
-
-```yaml
-lint:
- use:
- - MINIMAL
-generate:
- plugins:
- - name: go
- out: gen/go
- opts:
- paths: source_relative
+~~~yaml
+version: v1
+linters:
+ default: BASIC
breaking:
- against_git_ref: main
-```
-
----
+ baseline: git:main
+ categories: [FILE]
+~~~
-## Рекомендации по упрощению
-
-- Начните с минимального `lint.use` (MINIMAL), затем постепенно включайте дополнительные наборы.
-- Не переносите слепо все ignore — часть правил может уже быть улучшена в EasyP.
-- Сначала настроить deps и генерацию, затем усложнять линт/нейминг.
-- Фиксируйте миграцию по шагам (коммиты: deps → lint → generate → breaking → CI).
-
----
+Сопоставляйте отдельные правила по фактическим именам и результатам; одинаковые названия пресетов разных инструментов не доказывают эквивалентность. breaking.ignore содержит пути, а не имена правил.
-## Проверка результата
+## Зависимости и проверка результата
-Скрипт локальной быстрой проверки (пример):
+Объявите внешние зависимости через easyp get или require в manifest. Git-источник нельзя однозначно угадать по произвольному proto-import. Для первоначального разрешения выполните mod tidy и закоммитьте lock; в последующих проверках используйте mod download, а не обновление версий.
-```bash
-#!/usr/bin/env bash
-set -euo pipefail
-
-echo "[1] deps update"
-easyp mod update
-
-echo "[2] lint"
+~~~bash
+easyp validate-config
+easyp mod tidy
easyp lint
-
-echo "[3] breaking vs main"
-easyp breaking --against git-ref=origin/main || echo "Breaking changes detected (review needed)"
-
-echo "[4] generate"
+easyp breaking --against main
easyp generate
+~~~
-echo "Done."
-```
-
----
-
-## Заключение
-
-Миграция с Prototool на EasyP сводится к:
-1. Переносу путей и внешних каталогов в декларативные `deps`.
-2. Переформатированию линта под `lint.use` + `ignore/except`.
-3. Переносу генерации в `generate.plugins`.
-4. Добавлению встроенного механизма `breaking`.
-5. Адаптации CI.
-
-После этого конфигурация становится более прозрачной, а проверка несовместимых изменений — из коробки.
-
----
+Указанный baseline должен быть доступен локально. Сравните с прежней генерацией имена файлов, import paths и содержимое, затем соберите и протестируйте потребляющий проект. Не удаляйте прежние скрипты до этого сравнения. Для нескольких проектов используйте повторяемый --project или явно разрешённый --all.
-*Готово: базовый перевод и расширенное руководство по миграции с Prototool на EasyP.*
+Если исходный проект уже использует EasyP v0, начните с [предварительного просмотра миграции](/docs/migration/easyp-v0).
diff --git a/content/docs/reference/easyp-gen-yaml.mdx b/content/docs/reference/easyp-gen-yaml.mdx
index c24cc08..119a1f0 100644
--- a/content/docs/reference/easyp-gen-yaml.mdx
+++ b/content/docs/reference/easyp-gen-yaml.mdx
@@ -3,9 +3,9 @@ title: "easyp.gen.yaml Reference"
description: "Complete specification for easyp.gen.yaml, configuring consumer-side code generation, plugin outputs, WASM/remote execution, and managed package options."
---
-The `easyp.gen.yaml` file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules or packages to compile, which plugins to invoke, where generated artifacts should be written, and language-specific managed options (such as `package_prefix`).
+The easyp.gen.yaml file specifies **consumer-side code generation rules**. Residing alongside consuming applications or service projects, it defines which modules to compile, which plugins to invoke, where generated artifacts should be written, and managed options.
-In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never** contains dependency URLs or version numbers for Protobuf schemas—schema sources and versions are resolved strictly through `protobuf.mod` and `protobuf.lock`.
+generate.modules selects module identities or local paths. Schema version requirements are declared in protobuf.mod; selected commits and hashes are recorded in protobuf.lock.
---
@@ -19,15 +19,15 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never
default: "v1"
},
generate: {
- description: "Module and package selection block.",
+ description: "Module and exact protobuf-package selection, with managed descriptor options.",
type: "object"
},
"generate.modules": {
- description: "List of module names or local paths to generate code for.",
+ description: "Module identities or workspace-relative local module paths. Dependencies use the nearest protobuf.mod beside or above this config within the workspace and its lock. If omitted, that module is selected; without a manifest, the project directory is used.",
type: "string[]"
},
"generate.packages": {
- description: "Fine-grained package path filters if full module generation is not required.",
+ description: "Exact protobuf package names among selected modules. Empty selects all sources.",
type: "string[]"
},
plugins: {
@@ -38,29 +38,46 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never
description: "Local executable binary or WASM plugin identifier.",
type: "string"
},
+ "plugins[].path": {
+ description: "Explicit plugin binary path. Relative paths are resolved from the directory where easyp generate runs.",
+ type: "string"
+ },
+ "plugins[].command": {
+ description: "Custom plugin command as an executable followed by its arguments.",
+ type: "string[]"
+ },
"plugins[].remote": {
- description: "gRPC or HTTP remote code generation service URL.",
+ description: "Remote plugin URL for gRPC execution; set the version separately.",
type: "string"
},
"plugins[].version": {
- description: "Strict version tag of the plugin. ':latest' is prohibited for reproducibility.",
+ description: "Required SemVer tag for remote plugins. Local and bundled plugins use the selected executable and reject a separate version field.",
type: "string"
},
"plugins[].out": {
description: "Destination directory relative to easyp.gen.yaml where generated code is written.",
type: "string"
},
+ "plugins[].with_imports": {
+ description: "Generate transitive imports with this plugin only. Independent of descriptor export --include_imports.",
+ type: "boolean",
+ default: "false"
+ },
"plugins[].opts": {
description: "Plugin-specific key-value options or flag strings.",
type: "object | string[]"
},
options: {
- description: "Language-scoped managed options for package prefixes.",
+ description: "Go package-prefix options.",
type: "object"
},
"options.go.package_prefix": {
- description: "Base Go package prefix automatically prepended to generated go_package imports.",
+ description: "Computes go_package, changing Go options only. Full managed mode requires generate.managed.enabled: true.",
type: "string"
+ },
+ "generate.managed": {
+ description: "Existing managed descriptor rules: enabled, disable, and override, including module, package, path, and field selectors.",
+ type: "object"
}
}}
/>
@@ -69,37 +86,39 @@ In accordance with EasyP's zero-duplication principles, `easyp.gen.yaml` **never
## Example Configurations
-### Project-Level Generator (`backend/easyp.gen.yaml`)
+### Project-Level Generator (backend/easyp.gen.yaml)
-```yaml
+~~~yaml
version: v1
-
generate:
- modules:
- - proto/user
- - proto/order
-
+ modules: [proto/user, proto/order]
+ managed:
+ enabled: true
+ override:
+ - file_option: go_package_prefix
+ value: github.com/acme/backend/gen
+ - file_option: go_package_prefix
+ module: github.com/acme/user
+ value: github.com/acme/backend/gen/user
+ - file_option: go_package_prefix
+ module: github.com/acme/order
+ value: github.com/acme/backend/gen/order
plugins:
- name: go
- version: v1.34.2
- out: ./gen/go
- opts:
- paths: source_relative
+ out: .
+ with_imports: true
+ opts: [module=github.com/acme/backend]
- name: go-grpc
- version: v1.4.0
- out: ./gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
+ out: .
+ with_imports: true
+ opts: [module=github.com/acme/backend, require_unimplemented_servers=false]
+~~~
-options:
- go:
- package_prefix: github.com/acme/backend/gen/go
-```
+This example assumes the consumer Go module is github.com/acme/backend. The local modules declare github.com/acme/user and github.com/acme/order, exposing v1/user.proto and v1/order.proto; their shared dependency exposes common/v1/common.proto. Outputs go to separate directories gen/user/v1, gen/order/v1, and gen/common/v1. Different Go packages need different output directories; EasyP does not insert an implicit module-name prefix.
-### Remote Web Generator (`frontend/easyp.gen.yaml`)
+### Remote Web Generator (frontend/easyp.gen.yaml)
-```yaml
+~~~yaml
version: v1
generate:
@@ -112,12 +131,89 @@ plugins:
out: ./src/gen
opts:
target: ts
-```
+~~~
---
-## Managed Options (`options`)
+## Managed Options (options)
+
+Instead of requiring explicit file-level options (like option go_package = "...") inside every individual .proto schema file, EasyP's managed options block groups settings logically by target language.
+
+options.go.package_prefix computes go_package without changing the source. A plain prefix uses the hierarchy of a multi-component protobuf package: common.v1 with prefix github.com/acme/sdk becomes github.com/acme/sdk/common/v1;commonv1. A single-component package keeps the proto file directory. Templates such as `{{file_path}}` and `{{file_dir}}` use the proto path instead.
+
+The prefix changes Go options even when full managed mode is omitted or disabled. It does not enable Java, C#, PHP, Ruby, Objective-C, or C++ defaults. Full managed mode and field-option transformations require explicit generate.managed.enabled: true. Go disable selectors, including go_package, suppress the prefix.
+
+The existing managed-mode rules remain available under generate.managed. For example, a package-specific override can be written as:
+
+~~~yaml
+version: v1
+generate:
+ managed:
+ enabled: true
+ override:
+ - file_option: go_package_prefix
+ package: user.v1
+ value: github.com/acme/backend/gen/user
+plugins:
+ - name: go
+ out: ./gen/go
+~~~
+
+A repository-root easyp.gen.yaml may provide options.go.package_prefix as a default for nested generator files. Nested generate.managed rules take precedence over that inherited default. A prefix declared in the same generator file has the highest priority. Plugin lists stay local to each generator file.
+
+### Go output paths and plugin mappings
+
+With a Go prefix and explicit paths: source_relative, generated Go directories follow the effective import path relative to that prefix. In the common.v1 example, out: gen/go writes gen/go/common/v1/*.go, regardless of the proto file's directory. Marker templates use the complete parent path before the first marker as their output base. Imports outside that base keep the plugin's output path. Default paths, paths: import, and the plugin's module option retain plugin-controlled layouts.
+
+A plugin's Mfile.proto=import/path option overrides the effective import path for that plugin. The last nonempty import mapping wins; alias-only or empty mappings do not erase the descriptor import or a preceding import mapping. These plugin parameters do not change exported descriptors or other plugins' options.
+
+Insertion-point responses follow the output file created by their producer, even when the inserting plugin has different path or mapping options. An ambiguous producer is an error. Comments copied from a proto source do not change which Go or gRPC file receives the generated output.
+
+The generator selects module sources by default. Nonempty generate.packages filters them by exact protobuf package name. Unknown names fail before plugins; required imports remain in the compilation graph.
+
+Remote plugins require a version such as v2.0.0. EasyP sends that exact version to the remote generator. For local protoc-gen-* executables and bundled WASM plugins, the executable selected at runtime determines the version; the separate version field is rejected because EasyP cannot verify it.
+
+For bundled names such as go and go-grpc, a matching protoc-gen-* executable on PATH takes precedence. Otherwise EasyP uses the bundled WASM plugin. Use path or command to select an explicit executable.
+
+Each plugin declares exactly one source: name, path, command, or remote. Use path for a specific binary and command for an executable plus arguments. Both run from the directory where easyp generate starts and, like any Protobuf plugin, must read a CodeGeneratorRequest from stdin and write a CodeGeneratorResponse to stdout.
+
+~~~yaml
+version: v1
+plugins:
+ - path: ./tools/protoc-gen-custom
+ out: ./gen/custom
+ - command: [sh, ./tools/protoc-plugin.sh]
+ out: ./gen/script
+~~~
+
+The separate version field is also unavailable for path and command.
+
+## Project selection and imports
+
+By default, easyp generate selects the closest config in the current directory or a workspace ancestor. Repeat --project to choose multiple consumers explicitly; --all separately opts into recursive selection. --workspace sets the boundary for module paths and inheritance.
+
+plugins[].with_imports defaults to false. True adds transitive imports to that plugin's files to generate. Import descriptors remain available for linking when false. The --descriptor_set_out and --descriptor_set_out_dir flags are mutually exclusive; --include_imports controls exported contents only, independently of with_imports. See [project selection and descriptor export](/docs/cli/generator).
+
+## Managed-option validation
+
+Both configuration validation and generation reject unknown managed file or field options and values of the wrong type. Boolean options such as java_multiple_files require a YAML boolean, not a quoted string. String options require strings. optimize_for accepts SPEED, CODE_SIZE or LITE_RUNTIME; jstype accepts JS_NORMAL, JS_STRING or JS_NUMBER. Invalid rules cannot silently fall back to managed defaults.
+
+Place a remote version in the separate version field, not after a colon in the final plugin path. A server port in the host is allowed. For example, use remote: localhost:8080/go with version: v1.2.3.
+
+## Package selection and imports
+
+~~~yaml
+version: v1
+generate:
+ packages: [api.v1]
+plugins:
+ - name: go
+ out: gen/go
+ with_imports: true
+ - name: python
+ out: gen/python
+~~~
-Instead of requiring explicit file-level options (like `option go_package = "..."`) inside every individual `.proto` schema file, EasyP's managed `options` block groups settings logically by target language.
+Select an existing package in your module. All its files become generation targets, while required imports remain available for compilation. Only the Go plugin above generates those dependencies; the Python plugin generates selected files only. Unrelated packages, including invalid unused declarations, are not compiled. Malformed selected sources and required imports still fail.
-For example, setting `options.go.package_prefix: github.com/acme/backend/gen/go` automatically computes import paths based on the module directory layout without mutating source `.proto` files.
+Matching is exact and evaluated across all modules of the project. An unknown package fails before any plugin runs; duplicate names do not duplicate execution. Descriptor exports respect the same selection. The separate --include_imports switch adds the selected import closure to the descriptor output without changing plugin targets.
diff --git a/content/docs/reference/easyp-gen-yaml.ru.mdx b/content/docs/reference/easyp-gen-yaml.ru.mdx
index 62bb3ea..6ab79af 100644
--- a/content/docs/reference/easyp-gen-yaml.ru.mdx
+++ b/content/docs/reference/easyp-gen-yaml.ru.mdx
@@ -3,9 +3,9 @@ title: "Справочник easyp.gen.yaml"
description: "Полная спецификация файла easyp.gen.yaml, управляющего кодогенерацией на стороне потребителя, выводами плагинов, WASM/remote запуском и managed-опциями."
---
-Файл `easyp.gen.yaml` задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули и пакеты компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции (такие как `package_prefix`) применять.
+Файл easyp.gen.yaml задаёт **правила генерации кода на стороне потребителя**. Находясь рядом с приложением или сервисом, он определяет, какие модули компилировать, какие плагины вызывать, куда записывать сгенерированный код и какие managed-опции применять.
-В соответствии с принципом недублирования источников EasyP, `easyp.gen.yaml` **никогда** не содержит URL репозиториев или версий зависимостей — источники и версии протоколов определяются строго через `protobuf.mod` и `protobuf.lock`.
+Список generate.modules выбирает модули по имени или локальному пути. Требования к версиям схем объявляются в protobuf.mod, а выбранные коммиты и хеши сохраняются в protobuf.lock.
---
@@ -19,15 +19,15 @@ description: "Полная спецификация файла easyp.gen.yaml,
default: "v1"
},
generate: {
- description: "Блок выбора модулей и пакетов для генерации.",
+ description: "Выбор модулей и точных protobuf-пакетов с managed-опциями дескрипторов.",
type: "object"
},
"generate.modules": {
- description: "Список имён модулей или локальных путей для генерации кода.",
+ description: "Идентификаторы модулей или локальные пути относительно workspace. Зависимости используют ближайший protobuf.mod рядом с конфигом или выше в пределах workspace и его lock. Без списка выбирается этот модуль; без манифеста — каталог проекта.",
type: "string[]"
},
"generate.packages": {
- description: "Фильтр конкретных пакетов, если требуется генерация не всего модуля.",
+ description: "Точные имена protobuf-пакетов выбранных модулей. Пустой список выбирает все исходники.",
type: "string[]"
},
plugins: {
@@ -38,29 +38,46 @@ description: "Полная спецификация файла easyp.gen.yaml,
description: "Имя локального бинарного файла или WASM плагина.",
type: "string"
},
+ "plugins[].path": {
+ description: "Явный путь к бинарному плагину. Относительный путь считается от каталога запуска easyp generate.",
+ type: "string"
+ },
+ "plugins[].command": {
+ description: "Команда запуска собственного плагина: список из исполняемого файла и аргументов.",
+ type: "string[]"
+ },
"plugins[].remote": {
- description: "URL удалённого сервиса генерации кода (gRPC или HTTP).",
+ description: "URL удалённого плагина для выполнения через gRPC; версия задаётся отдельно.",
type: "string"
},
"plugins[].version": {
- description: "Строгий тег версии плагина. Использование ':latest' запрещено.",
+ description: "Обязательный SemVer-тег для удалённых плагинов. Локальные и встроенные плагины используют выбранный исполняемый файл и не принимают отдельное поле version.",
type: "string"
},
"plugins[].out": {
description: "Директория назначения относительно easyp.gen.yaml для результатов.",
type: "string"
},
+ "plugins[].with_imports": {
+ description: "Генерирует транзитивные импорты только этим плагином. Независимо от флага экспорта --include_imports.",
+ type: "boolean",
+ default: "false"
+ },
"plugins[].opts": {
description: "Параметры и флаги плагина (словарь или список строк).",
type: "object | string[]"
},
options: {
- description: "Managed-опции пакетов, сгруппированные по целевым языкам.",
+ description: "Настройки префикса Go-пакетов.",
type: "object"
},
"options.go.package_prefix": {
- description: "Базовый префикс Go-пакета, автоматически добавляемый к go_package.",
+ description: "Вычисляет go_package, меняя только Go-опции. Полный managed mode требует generate.managed.enabled: true.",
type: "string"
+ },
+ "generate.managed": {
+ description: "Существующие правила managed mode: enabled, disable и override с селекторами module, package, path и field.",
+ type: "object"
}
}}
/>
@@ -69,37 +86,39 @@ description: "Полная спецификация файла easyp.gen.yaml,
## Примеры конфигураций
-### Проектный генератор (`backend/easyp.gen.yaml`)
+### Проектный генератор (backend/easyp.gen.yaml)
-```yaml
+~~~yaml
version: v1
-
generate:
- modules:
- - proto/user
- - proto/order
-
+ modules: [proto/user, proto/order]
+ managed:
+ enabled: true
+ override:
+ - file_option: go_package_prefix
+ value: github.com/acme/backend/gen
+ - file_option: go_package_prefix
+ module: github.com/acme/user
+ value: github.com/acme/backend/gen/user
+ - file_option: go_package_prefix
+ module: github.com/acme/order
+ value: github.com/acme/backend/gen/order
plugins:
- name: go
- version: v1.34.2
- out: ./gen/go
- opts:
- paths: source_relative
+ out: .
+ with_imports: true
+ opts: [module=github.com/acme/backend]
- name: go-grpc
- version: v1.4.0
- out: ./gen/go
- opts:
- paths: source_relative
- require_unimplemented_servers: false
+ out: .
+ with_imports: true
+ opts: [module=github.com/acme/backend, require_unimplemented_servers=false]
+~~~
-options:
- go:
- package_prefix: github.com/acme/backend/gen/go
-```
+В примере Go-модуль потребителя называется github.com/acme/backend. Локальные модули объявляют имена github.com/acme/user и github.com/acme/order; их import path — v1/user.proto и v1/order.proto. Общая зависимость экспортирует common/v1/common.proto. Результаты попадают в отдельные каталоги gen/user/v1, gen/order/v1 и gen/common/v1. Разным Go-пакетам нужны разные выходные каталоги; EasyP не добавляет неявный префикс имени модуля.
-### Удалённая веб-генерация (`frontend/easyp.gen.yaml`)
+### Удалённая веб-генерация (frontend/easyp.gen.yaml)
-```yaml
+~~~yaml
version: v1
generate:
@@ -112,12 +131,89 @@ plugins:
out: ./src/gen
opts:
target: ts
-```
+~~~
---
-## Managed Options (`options`)
+## Managed Options (options)
+
+Вместо явного прописывания опций вроде option go_package = "..." внутри каждого .proto файла, блок options в EasyP группирует настройки по целевым языкам программирования.
+
+options.go.package_prefix вычисляет go_package без изменения исходника. Обычный префикс использует иерархию protobuf-пакета из нескольких компонентов: common.v1 с префиксом github.com/acme/sdk становится github.com/acme/sdk/common/v1;commonv1. Для пакета из одного компонента сохраняется каталог proto-файла. Шаблоны вроде `{{file_path}}` и `{{file_dir}}` используют путь proto-файла.
+
+Префикс меняет Go-опции, даже когда полный managed mode не задан или выключен. Он не включает значения по умолчанию для Java, C#, PHP, Ruby, Objective-C или C++. Для полного managed mode и преобразований опций полей явно задайте generate.managed.enabled: true. Go-селекторы disable, включая go_package, подавляют префикс.
+
+Существующие правила managed mode доступны в generate.managed. Например, переопределение для конкретного Protobuf-пакета:
+
+~~~yaml
+version: v1
+generate:
+ managed:
+ enabled: true
+ override:
+ - file_option: go_package_prefix
+ package: user.v1
+ value: github.com/acme/backend/gen/user
+plugins:
+ - name: go
+ out: ./gen/go
+~~~
+
+Корневой easyp.gen.yaml может задавать options.go.package_prefix по умолчанию для вложенных генераторов. Локальные правила generate.managed имеют приоритет над унаследованным префиксом. Префикс, заданный в том же файле генератора, имеет наивысший приоритет. Списки плагинов не наследуются.
+
+### Выходные пути Go и параметры M
+
+С Go-префиксом и явным paths: source_relative каталоги Go-кода соответствуют эффективному import path относительно префикса. В примере common.v1 настройка out: gen/go записывает gen/go/common/v1/*.go независимо от каталога proto-файла. Для шаблонов с маркером базой служит полный родительский путь до первого маркера. Импорты за пределами этой базы сохраняют выходной путь плагина. Значение paths по умолчанию, paths: import и параметр плагина module сохраняют расположение, выбранное плагином.
+
+Параметр плагина Mfile.proto=import/path переопределяет эффективный import path только для этого плагина. Последнее непустое значение импорта имеет приоритет; пустое значение или только alias не стирают импорт дескриптора либо предыдущее значение импорта. Эти параметры не меняют экспортируемые дескрипторы или настройки других плагинов.
+
+Ответы с insertion point используют выходной файл создавшего его плагина, даже если у вставляющего плагина другие параметры пути или M. Неоднозначный выбор создателя — ошибка. Скопированные из proto комментарии не меняют выбор выходного Go- или gRPC-файла.
+
+По умолчанию генерируются все исходники выбранных модулей. Непустой generate.packages фильтрует их по точному имени protobuf-пакета. Неизвестные имена отклоняются до запуска плагинов, нужные импорты остаются в графе компиляции.
+
+Удалённому плагину нужен version, например v2.0.0. EasyP передаёт именно эту версию удалённому генератору. Для локального protoc-gen-* и встроенного WASM версию определяет выбранный исполняемый файл; отдельное поле version отклоняется, поскольку EasyP не может его проверить.
+
+Для встроенных имён вроде go и go-grpc приоритет имеет соответствующий protoc-gen-* в PATH. Если его нет, EasyP использует встроенный WASM-плагин. Для явного выбора исполняемого файла задайте path или command.
+
+Для каждого плагина указывают ровно один источник: name, path, command или remote. path запускает конкретный бинарный файл, а command принимает список из программы и её аргументов. Оба варианта работают из каталога запуска easyp generate и, как любой плагин Protobuf, должны принимать CodeGeneratorRequest из stdin и возвращать CodeGeneratorResponse в stdout.
+
+~~~yaml
+version: v1
+plugins:
+ - path: ./tools/protoc-gen-custom
+ out: ./gen/custom
+ - command: [sh, ./tools/protoc-plugin.sh]
+ out: ./gen/script
+~~~
+
+Для path и command отдельное поле version также не указывается.
+
+## Выбор проекта и импорты
+
+По умолчанию easyp generate выбирает ближайший конфиг в текущем или родительском каталоге workspace. Повторяйте --project для явного выбора нескольких потребителей; --all отдельно включает рекурсивный выбор. --workspace задаёт границу для путей модулей и наследования.
+
+plugins[].with_imports по умолчанию равен false. Значение true добавляет транзитивные импорты в список файлов для генерации только этого плагина. Дескрипторы импортов для связывания доступны и при false. Флаги --descriptor_set_out и --descriptor_set_out_dir взаимоисключающие; --include_imports меняет только содержимое экспорта, независимо от with_imports. См. [выбор проектов и экспорт дескрипторов](/ru/docs/cli/generator).
+
+## Проверка managed-опций
+
+Валидация конфигурации и генерация отклоняют неизвестные file/field options и значения неподходящего типа. Булевым опциям вроде java_multiple_files нужен YAML boolean, а не строка в кавычках. Строковым опциям нужны строки. optimize_for принимает SPEED, CODE_SIZE или LITE_RUNTIME; jstype — JS_NORMAL, JS_STRING или JS_NUMBER. Неверное правило не должно незаметно заменяться стандартными managed-настройками.
+
+Версию remote-плагина указывайте отдельным полем version, а не после двоеточия в последнем сегменте пути. Порт сервера в имени хоста допустим. Например, remote: localhost:8080/go вместе с version: v1.2.3.
+
+## Выбор пакетов и импорты
+
+~~~yaml
+version: v1
+generate:
+ packages: [api.v1]
+plugins:
+ - name: go
+ out: gen/go
+ with_imports: true
+ - name: python
+ out: gen/python
+~~~
-Вместо явного прописывания опций вроде `option go_package = "..."` внутри каждого `.proto` файла, блок `options` в EasyP группирует настройки по целевым языкам программирования.
+Укажите существующий пакет модуля. Все его файлы становятся целями генерации, а необходимые импорты сохраняются для компиляции. В примере зависимости генерирует только Go-плагин; Python-плагин генерирует только выбранные файлы. Несвязанные пакеты, включая невалидные неиспользуемые объявления, не компилируются. Ошибки выбранных исходников и нужных импортов по-прежнему останавливают команду.
-Например, указание `options.go.package_prefix: github.com/acme/backend/gen/go` автоматически вычисляет пути импортов на основе структуры директорий модуля без модификации исходных `.proto` файлов.
+Сопоставление точное и выполняется среди всех модулей проекта. Неизвестный пакет отклоняется до запуска любого плагина, повтор имени не дублирует запуск. Экспорт дескрипторов учитывает тот же отбор. Отдельный --include_imports включает достижимые импорты в descriptor set, не меняя цели плагинов.
diff --git a/content/docs/reference/easyp-yaml.mdx b/content/docs/reference/easyp-yaml.mdx
index 456a7de..17e9b16 100644
--- a/content/docs/reference/easyp-yaml.mdx
+++ b/content/docs/reference/easyp-yaml.mdx
@@ -3,9 +3,7 @@ title: "easyp.yaml Reference"
description: "Complete specification for easyp.yaml, configuring producer-side linting rules, breaking change detection, path exclusions, and policy inheritance."
---
-The `easyp.yaml` file defines **producer-side policy configuration** for Protocol Buffer schema repositories. It specifies linting standards, breaking change checks against git baselines, path exclusion rules, and policy inheritance via `extends`.
-
-`easyp.yaml` files cascade hierarchically down directory structures: for any given `.proto` file, EasyP traverses up the directory tree to find the nearest `easyp.yaml` and applies its configuration.
+easyp.yaml defines lint and compatibility policies for protobuf schemas. Each section uses its nearest definition in the directory tree. Explicit linters.extends and breaking.extends inherit section-scoped bases from bounded local files or declared, locked modules. See [shared policies](/docs/guides/organization-lint-style).
---
@@ -19,7 +17,7 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco
default: "v1"
},
linters: {
- description: "Linter presets, explicit rule enable/disable, and inheritance.",
+ description: "Linter presets, rule/group selection, and per-policy comment suppressions.",
type: "object"
},
"linters.default": {
@@ -28,19 +26,24 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco
default: "STANDARD"
},
"linters.enable": {
- description: "List of additional linter rules to enable on top of preset.",
+ description: "Additional implemented rule or group names to enable.",
type: "string[]"
},
"linters.disable": {
- description: "List of linter rules to disable from the active preset.",
+ description: "Implemented rule or group names to disable; disabling wins over enabling.",
type: "string[]"
},
+ "linters.allow_comment_ignores": {
+ description: "Allow scoped easyp:disable/enable and legacy markers within the effective policy.",
+ type: "boolean",
+ default: "true"
+ },
"linters.extends": {
- description: "Remote Git module or policy path to inherit base linter rules from.",
+ description: "Base policy from a local ./ or ../ reference, or a declared locked module with optional #policy-path. Local values override the base.",
type: "string"
},
"linters-settings": {
- description: "Rule-specific settings and custom parameter definitions.",
+ description: "Supported settings: ENUM_ZERO_VALUE_SUFFIX.suffix and SERVICE_SUFFIX.suffix.",
type: "object"
},
issues: {
@@ -48,30 +51,37 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco
type: "object"
},
"issues.exclude-rules": {
- description: "Array of exclusion rules matching file path glob patterns to disabled linters.",
+ description: "Suppress named rules/groups for matching paths. Omitted or empty linters suppress all lint issues in matching files; a completely empty rule explicitly ignores all files covered by the effective issues section.",
type: "object[]"
},
+ "issues.exclude-rules[].path": {
+ description: "Relative to the policy file supplying the issues section. Supports *, ?, [], and complete ** segments; a literal directory covers its subtree.",
+ type: "string"
+ },
breaking: {
description: "Breaking change detection settings for CI verification.",
type: "object"
},
"breaking.baseline": {
- description: "Git ref or tag target to compare schema changes against (e.g. git:main).",
+ description: "Locally available Git branch, tag, full commit SHA, or revision prefixed with git:. Explicit --against wins; otherwise this field applies, then master.",
type: "string",
- default: "git:main"
+ default: "master"
},
"breaking.categories": {
- description: "Enforced breaking change categories: FILE, PACKAGE, WIRE_JSON, WIRE.",
- type: "string[]",
- default: "['WIRE']"
+ description: "FILE, PACKAGE, WIRE_JSON, WIRE: distinct compatibility profiles. Omitted/empty preserves legacy checks; multiple profiles apply their union.",
+ type: "string[]"
},
"breaking.ignore_unstable": {
- description: "When true, unstable proto packages (v1alpha, v1beta) bypass breaking checks.",
+ description: "Skip packages with a supported unstable version in their final component on both sides of comparison. See exact forms below.",
type: "boolean",
- default: "true"
+ default: "false"
+ },
+ "breaking.ignore": {
+ description: "Ignored paths relative to the policy file supplying breaking, not the Git root or --root.",
+ type: "string[]"
},
"breaking.extends": {
- description: "Remote Git policy module to inherit breaking change settings from.",
+ description: "Base policy from a local ./ or ../ reference, or a declared locked module with optional #policy-path. Local values override the base.",
type: "string"
}
}}
@@ -79,55 +89,75 @@ The `easyp.yaml` file defines **producer-side policy configuration** for Protoco
---
-## Example Configuration
+## Example configuration
-```yaml
+~~~yaml
version: v1
-
linters:
default: STANDARD
- enable:
- - ENUM_VALUE_PREFIX
- - RPC_REQUEST_RESPONSE_UNIQUE
- disable:
- - PACKAGE_VERSION_SUFFIX
-
+ enable: [ENUM_VALUE_PREFIX, RPC_REQUEST_RESPONSE_UNIQUE]
+ disable: [PACKAGE_VERSION_SUFFIX]
+ allow_comment_ignores: true
linters-settings:
ENUM_ZERO_VALUE_SUFFIX:
suffix: UNSPECIFIED
SERVICE_SUFFIX:
suffix: Service
-
issues:
exclude-rules:
- - path: "gen/**"
- - path: "**/legacy/**"
- linters:
- - FIELD_LOWER_SNAKE_CASE
- - PACKAGE_DIRECTORY_MATCH
-
+ - path: legacy/**/*.proto
+ linters: [FIELD_LOWER_SNAKE_CASE]
+ - path: generated
breaking:
baseline: git:main
- categories:
- - WIRE
- - WIRE_JSON
+ categories: [FILE]
ignore_unstable: true
-```
+ ignore: [gen]
+~~~
----
+## Section cascading
+
+The linters, linters-settings, issues, and breaking sections each come as a whole from the nearest file defining that section; fields are not partially merged. A child issues: {} clears inherited exclusions. An inherited exclusion path stays relative to the file defining issues, even when the invocation directory or --root is deeper.
+
+Policy discovery searches ancestors within the workspace. If no ancestor policy exists, one unambiguous outermost descendant policy may be selected; multiple independent policies require explicit --cfg. Explicit --cfg takes precedence, and explicit --root supplies the default lookup start.
+
+## Rule selection and exclusions
+
+Repeated rule or group names are idempotent, and disabling wins over enabling. Unknown names in enable, disable, and exclusions are errors even if also listed on the opposite side. The reserved PACKAGE_NO_IMPORT_CYCLE rule is unimplemented and cannot be selected.
+
+issues.exclude-rules[].path uses / separators and is anchored to the directory of the file supplying the effective issues section:
+
+| Pattern | Matches |
+| --- | --- |
+| generated | The directory and its whole subtree |
+| api/file.proto | That file |
+| api/*.proto | Files directly inside api |
+| api/?.proto | One character before .proto |
+| api/[a-c].proto | a.proto, b.proto, or c.proto |
+| api/**/file.proto | Zero or more intermediate directories |
+
+** must occupy an entire segment. Absolute paths, backslashes, .. traversal, and malformed patterns are rejected. A literal path ending in .proto matches that file only; other literal paths cover their subtree. These rules apply to issue exclusions only, not every configuration path.
+
+Without path, the rule applies to all files covered by the effective issues section. linters accepts implemented rule or group names; an omitted or empty list excludes matching files from linting entirely. A completely empty rule {} retains its explicit all-ignore meaning. In the example, the whole generated subtree is excluded, while only the named rule is suppressed in legacy.
+
+## Comment suppressions
+
+linters.allow_comment_ignores defaults to true per effective policy. False disables comment-based suppressions. easyp:disable/easyp:enable provide annotations or bounded regions; legacy nolint:RULE and buf:lint:ignore RULE remain annotations. Unknown names, empty directives, and unmatched enables remain errors even when suppressions are disabled. See the [linter guide](/docs/cli/linter) for examples and scope.
+
+## Breaking checks
+
+Explicit --against wins over breaking.baseline; without either, the default is master. This includes explicit --against master. An empty explicit flag is an error, and a missing Git baseline does not fall back to the configured one.
+
+The baseline can name a local branch, a lightweight or annotated tag, a full commit SHA, or another locally resolvable Git revision such as HEAD. Required refs and objects must already be present in the checkout. A bare branch name takes precedence over an identically named tag; use refs/tags/v1.2.0 to select the tag explicitly. In YAML use git:refs/tags/v1.2.0; for the CLI pass --against refs/tags/v1.2.0 without a git: or git-ref= prefix.
+
+breaking.ignore paths are relative to the file supplying the effective breaking section, not the Git root or --root. For example, ignore: [generated] in api/easyp.yaml excludes api/generated, including when that section is inherited. Entries must be nonempty local relative paths; absolute paths and paths escaping the policy directory or repository are rejected.
+
+Each selected module uses revision-local roots, manifests, and locks for its current and baseline revisions. The baseline is read from an isolated Git snapshot; the caller's checkout, manifest, and lock are unchanged. Policies come from current configuration and may each select a different baseline. See the [breaking guide](/docs/cli/breaking-changes) for local replacement limits.
-## Directory Cascading
+Select FILE for file/source compatibility, PACKAGE to allow moves within a package, WIRE_JSON for binary plus JSON, or WIRE for binary. See the [profile matrix](/docs/cli/breaking-changes). Omitted/empty categories preserve legacy checks. Shared policies remain pinned through the consuming manifest/lock.
-EasyP applies the **nearest file rule**: when evaluating a `.proto` file, EasyP searches upward through parent directories for an `easyp.yaml`.
+## Unstable packages
-```text
-proto/
-├── easyp.yaml # STANDARD policy applies to root & user/
-├── user/
-│ └── v1/user.proto
-└── legacy/
- ├── easyp.yaml # MINIMAL policy override applies strictly to legacy/
- └── old.proto
-```
+breaking.ignore_unstable defaults to false. When true, it filters packages by their final protobuf package-name component on both sides of comparison, including dependency packages. Supported forms are vNtest..., vNalpha, vNbeta, vNpMalpha, and vNpMbeta. Alpha/beta may have a positive sequence number; N, M, and that sequence start with 1–9 followed by digits. Test may have any trailing suffix, including none.
-Sections are inherited as whole units from the nearest declaring file, preventing confusing partial merges.
+For example, acme.v1testFeature, acme.v2alpha3, and acme.v2p3beta are skipped. acme.v1, acme.v0alpha1, acme.v1beta0, and acme.v1beta1.service do not match. Stable packages remain checked, including their references to unstable types. Filtering does not excuse malformed sources: reading and import resolution happen before filtering.
diff --git a/content/docs/reference/easyp-yaml.ru.mdx b/content/docs/reference/easyp-yaml.ru.mdx
index 55306e8..317afee 100644
--- a/content/docs/reference/easyp-yaml.ru.mdx
+++ b/content/docs/reference/easyp-yaml.ru.mdx
@@ -3,9 +3,7 @@ title: "Справочник easyp.yaml"
description: "Полная спецификация файла easyp.yaml, управляющего правилами линтинга продюсера, проверками ломающих изменений, исключениями путей и наследованием политик."
---
-Файл `easyp.yaml` определяет **конфигурацию политик на стороне продюсера** для репозиториев Protobuf-схем. Он задаёт стандарты линтинга, проверки ломающих изменений относительно git-baseline, правила исключения путей и наследование политик через `extends`.
-
-Файлы `easyp.yaml` каскадируются по иерархии директорий: для каждого файла `.proto` EasyP ищет ближайший `easyp.yaml` вверх по дереву каталогов и применяет его правила.
+Файл easyp.yaml задаёт политики линтинга и совместимости для protobuf-схем. Для каждой секции применяется ближайшее определение в дереве каталогов. Секции linters.extends и breaking.extends наследуют базы из локальных файлов или объявленных закреплённых модулей. Подробнее — в [руководстве по общим политикам](/ru/docs/guides/organization-lint-style).
---
@@ -19,7 +17,7 @@ description: "Полная спецификация файла easyp.yaml, уп
default: "v1"
},
linters: {
- description: "Пресеты линтеров, точечное включение/отключение правил и наследование.",
+ description: "Пресеты, выбор правил/групп и подавление замечаний комментариями в пределах политики.",
type: "object"
},
"linters.default": {
@@ -28,19 +26,24 @@ description: "Полная спецификация файла easyp.yaml, уп
default: "STANDARD"
},
"linters.enable": {
- description: "Список дополнительных правил линтера, включаемых поверх пресета.",
+ description: "Дополнительные имена реализованных правил или групп для включения.",
type: "string[]"
},
"linters.disable": {
- description: "Список правил линтера, отключаемых из активного пресета.",
+ description: "Имена реализованных правил или групп для отключения; отключение приоритетнее включения.",
type: "string[]"
},
+ "linters.allow_comment_ignores": {
+ description: "Разрешает easyp:disable/enable и старые маркеры в пределах эффективной политики.",
+ type: "boolean",
+ default: "true"
+ },
"linters.extends": {
- description: "Удалённый модуль Git или путь к политике для наследования правил.",
+ description: "База из локальной ссылки ./ или ../ либо объявленного закреплённого модуля с необязательным #путь-политики. Локальные значения приоритетнее базы.",
type: "string"
},
"linters-settings": {
- description: "Параметры конкретных правил и пользовательские настройки.",
+ description: "Поддерживаются ENUM_ZERO_VALUE_SUFFIX.suffix и SERVICE_SUFFIX.suffix.",
type: "object"
},
issues: {
@@ -48,30 +51,37 @@ description: "Полная спецификация файла easyp.yaml, уп
type: "object"
},
"issues.exclude-rules": {
- description: "Массив правил исключений, сопоставляющих glob-шаблоны путей с линтерами.",
+ description: "Подавляет выбранные правила/группы на совпавших путях. Пустой или отсутствующий linters подавляет все замечания в совпавших файлах; полностью пустое правило явно исключает все файлы эффективной секции issues.",
type: "object[]"
},
+ "issues.exclude-rules[].path": {
+ description: "Путь относительно файла, задающего секцию issues. Поддерживает *, ?, [] и полные сегменты **; буквальный каталог охватывает поддерево.",
+ type: "string"
+ },
breaking: {
description: "Параметры проверки ломающих изменений для CI.",
type: "object"
},
"breaking.baseline": {
- description: "Ссылка на git-ветку или тег для сравнения изменений (например, git:main).",
+ description: "Доступная локально Git-ветка, тег, полный SHA коммита или ревизия с префиксом git:. Явный --against имеет приоритет; далее это поле, затем master.",
type: "string",
- default: "git:main"
+ default: "master"
},
"breaking.categories": {
- description: "Категории ломающих изменений: FILE, PACKAGE, WIRE_JSON, WIRE.",
- type: "string[]",
- default: "['WIRE']"
+ description: "FILE, PACKAGE, WIRE_JSON, WIRE: разные профили совместимости. Отсутствие/пустой список сохраняет прежние проверки; несколько профилей применяются совместно.",
+ type: "string[]"
},
"breaking.ignore_unstable": {
- description: "При true нестабильные пакеты (v1alpha, v1beta) игнорируют breaking-проверки.",
+ description: "Пропускает пакеты с поддерживаемой нестабильной версией в последнем компоненте имени на обеих сторонах сравнения. Точные формы описаны ниже.",
type: "boolean",
- default: "true"
+ default: "false"
+ },
+ "breaking.ignore": {
+ description: "Исключаемые пути относительно файла политики, задающего breaking, а не корня Git или --root.",
+ type: "string[]"
},
"breaking.extends": {
- description: "Удалённый модуль политики для наследования настроек breaking-проверок.",
+ description: "База из локальной ссылки ./ или ../ либо объявленного закреплённого модуля с необязательным #путь-политики. Локальные значения приоритетнее базы.",
type: "string"
}
}}
@@ -81,53 +91,73 @@ description: "Полная спецификация файла easyp.yaml, уп
## Пример конфигурации
-```yaml
+~~~yaml
version: v1
-
linters:
default: STANDARD
- enable:
- - ENUM_VALUE_PREFIX
- - RPC_REQUEST_RESPONSE_UNIQUE
- disable:
- - PACKAGE_VERSION_SUFFIX
-
+ enable: [ENUM_VALUE_PREFIX, RPC_REQUEST_RESPONSE_UNIQUE]
+ disable: [PACKAGE_VERSION_SUFFIX]
+ allow_comment_ignores: true
linters-settings:
ENUM_ZERO_VALUE_SUFFIX:
suffix: UNSPECIFIED
SERVICE_SUFFIX:
suffix: Service
-
issues:
exclude-rules:
- - path: "gen/**"
- - path: "**/legacy/**"
- linters:
- - FIELD_LOWER_SNAKE_CASE
- - PACKAGE_DIRECTORY_MATCH
-
+ - path: legacy/**/*.proto
+ linters: [FIELD_LOWER_SNAKE_CASE]
+ - path: generated
breaking:
baseline: git:main
- categories:
- - WIRE
- - WIRE_JSON
+ categories: [FILE]
ignore_unstable: true
-```
+ ignore: [gen]
+~~~
----
+## Каскадирование секций
+
+Секции linters, linters-settings, issues и breaking берутся целиком из ближайшего определяющего файла без частичного слияния. Вложенная issues: {} очищает унаследованные исключения. Унаследованный путь исключения остаётся относительно файла, где определена секция issues, даже если запуск или --root указывает глубже.
+
+При поиске политики команды идут вверх в пределах workspace. Если политики выше нет, допустима одна однозначная внешняя политика в потомках; несколько независимых политик требуют явного --cfg. Явный --cfg имеет приоритет, а явный --root задаёт начальную точку поиска по умолчанию.
+
+## Выбор правил и исключения
+
+Повторные имена правил или групп не добавляют проверок; отключение приоритетнее включения. Неизвестные имена в enable, disable и исключениях — ошибки, даже если имя есть в противоположном списке. Зарезервированное PACKAGE_NO_IMPORT_CYCLE не реализовано и выбирать его нельзя.
+
+Пути issues.exclude-rules[].path используют разделитель / и привязаны к каталогу файла, предоставившего эффективную секцию issues:
+
+| Шаблон | Совпадение |
+| --- | --- |
+| generated | Весь каталог и его поддерево |
+| api/file.proto | Этот файл |
+| api/*.proto | Файлы непосредственно в api |
+| api/?.proto | Имя из одного символа перед .proto |
+| api/[a-c].proto | a.proto, b.proto или c.proto |
+| api/**/file.proto | Ноль или больше промежуточных каталогов |
+
+** должен занимать целый сегмент. Абсолютные пути, обратные слеши, переходы .. и некорректные шаблоны отклоняются. Путь без шаблонов с окончанием .proto совпадает только с файлом; остальные буквальные пути охватывают поддерево. Эти правила относятся только к исключениям issues, а не ко всем путям конфигурации.
+
+Без path правило действует на все файлы эффективной секции issues. linters может содержать реализованные правила или группы; пустой либо отсутствующий список исключает файл из линтинга целиком. Полностью пустое правило {} сохраняет значение явного исключения всех файлов. В примере исключается всё поддерево generated, а в legacy подавляется только указанное правило.
+
+## Подавление комментариями
+
+linters.allow_comment_ignores по умолчанию равен true для каждой эффективной политики. False отключает подавление через комментарии. Маркеры easyp:disable/easyp:enable задают аннотации или ограниченные регионы; старые nolint:RULE и buf:lint:ignore RULE остаются аннотациями. Неизвестные имена, пустые директивы и непарные enable остаются ошибками даже при отключённом подавлении. Примеры и области действия — в [руководстве линтера](/ru/docs/cli/linter).
+
+## Проверка совместимости
+
+Явный --against имеет приоритет над breaking.baseline; без обоих используется master. Это верно и для явного --against master. Пустой явный флаг вызывает ошибку, а отсутствующая Git-база не заменяется конфигурационной.
+
+База может указывать на локальную ветку, лёгкий или аннотированный тег, полный SHA коммита или другую разрешимую локально Git-ревизию, например HEAD. Нужные ссылки и объекты должны уже присутствовать в checkout. Короткое имя ветки приоритетнее одноимённого тега; для явного выбора тега используйте refs/tags/v1.2.0. В YAML задавайте git:refs/tags/v1.2.0, а в CLI — --against refs/tags/v1.2.0 без префикса git: или git-ref=.
+
+Пути breaking.ignore отсчитываются от файла, задающего эффективную секцию breaking, а не от корня Git или --root. Например, ignore: [generated] в api/easyp.yaml исключает api/generated, в том числе при наследовании этой секции. Допустимы непустые локальные относительные пути; абсолютные пути и выход за каталог политики или репозиторий отклоняются.
+
+Для каждого выбранного модуля текущая и базовая ревизии используют собственные корни, манифесты и lock. База читается из изолированного Git-снимка; рабочее дерево, манифест и lock пользователя не изменяются. Политики берутся из текущей конфигурации; каждая может задавать свою базу. Подробности и ограничения локальных замен — в [руководстве breaking](/ru/docs/cli/breaking-changes).
-## Каскадирование по директориям
+FILE проверяет совместимость файлов и исходного кода, PACKAGE разрешает переносы внутри пакета, WIRE_JSON защищает бинарное и JSON-представление, WIRE — бинарное. См. [матрицу профилей](/ru/docs/cli/breaking-changes). Отсутствие/пустой список categories сохраняет прежний checker. Общие политики закрепляются через manifest/lock потребителя.
-EasyP использует **правило ближайшего файла**: при проверке `.proto` файла EasyP ищет `easyp.yaml` вверх по дереву директорий.
+## Нестабильные пакеты
-```text
-proto/
-├── easyp.yaml # Политика STANDARD применяется к корню и user/
-├── user/
-│ └── v1/user.proto
-└── legacy/
- ├── easyp.yaml # Ослабленная политика MINIMAL только для legacy/
- └── old.proto
-```
+breaking.ignore_unstable по умолчанию равен false. При true фильтруется последний компонент имени protobuf-пакета на обеих сторонах сравнения, включая пакеты зависимостей. Поддерживаются формы vNtest..., vNalpha, vNbeta, vNpMalpha и vNpMbeta. После alpha/beta допустим положительный номер; N, M и этот номер начинаются с 1–9 и продолжаются цифрами. После test допустим любой суффикс, включая пустой.
-Секция берётся целиком из ближайшего определяющего файла без частичного слияния.
+Например, acme.v1testFeature, acme.v2alpha3 и acme.v2p3beta пропускаются. acme.v1, acme.v0alpha1, acme.v1beta0 и acme.v1beta1.service не совпадают. Стабильные пакеты по-прежнему проверяются, включая их ссылки на нестабильные типы. Фильтр не позволяет оставить некорректные исходники: чтение и разрешение импортов происходят до фильтрации.
diff --git a/content/docs/reference/protobuf-lock.mdx b/content/docs/reference/protobuf-lock.mdx
index d6226ba..f0e0681 100644
--- a/content/docs/reference/protobuf-lock.mdx
+++ b/content/docs/reference/protobuf-lock.mdx
@@ -3,7 +3,7 @@ title: "protobuf.lock Reference"
description: "Specification for protobuf.lock, the generated lockfile securing resolved Git commits, versions, and cryptographic hashes for hermetic builds."
---
-The `protobuf.lock` file is an auto-generated artifact created by EasyP dependency commands (`easyp mod tidy`, `easyp mod update`). It locks the exact transitive dependency graph to guarantee **100% hermetic, reproducible builds** across all local developer environments and CI pipelines.
+protobuf.lock is generated by easyp get, easyp mod tidy, and easyp mod update. It records the selected Git dependency graph with exact commits and content hashes, making dependency sources reproducible while the pinned commits remain available and integrity checks succeed.
---
@@ -25,7 +25,7 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen
type: "string"
},
"modules[].version": {
- description: "Resolved Semantic Version tag (e.g. v1.2.3).",
+ description: "Selected SemVer tag or full commit hash for an exact-commit or versionless requirement.",
type: "string"
},
"modules[].commit": {
@@ -33,7 +33,7 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen
type: "string"
},
"modules[].hash": {
- description: "Cryptographic content hash (h1:...) for content integrity validation.",
+ description: "Go dirhash.Hash1 digest (h1:...) of the Git-tracked regular files at the locked commit.",
type: "string"
}
}}
@@ -43,28 +43,37 @@ The `protobuf.lock` file is an auto-generated artifact created by EasyP dependen
## Example Lockfile
-```yaml
-# protobuf.lock - GENERATED FILE, DO NOT EDIT MANUALLY
+~~~yaml
+# Illustrative values only; real entries are written by EasyP.
version: 1
modules:
- - source: github.com/googleapis/googleapis
- version: v1.5.0
- commit: 8f3a1c94b2e10a84e
- hash: h1:a9F8zK9mB20...
- - source: github.com/acme/weather
+ - source: github.com/acme/shared
version: v1.2.3
- commit: 51d2e071c89f33b11
- hash: h1:x7B3mL4k90a...
- - source: github.com/grpc-ecosystem/grpc-gateway
- version: v2.19.0
- commit: c4f88aa91024e12c4
- hash: h1:p0Q1wK97ab1...
-```
+ commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+~~~
---
-## Lifecycle Commands
+## Lifecycle commands
-- `easyp mod tidy`: Resolves required imports, updates indirect dependencies, and regenerates `protobuf.lock`.
-- `easyp mod update`: Upgrades dependencies to latest semver-compatible versions and updates `protobuf.lock`.
-- `easyp mod download`: Populates local cache strictly using `protobuf.lock` without reaching out to remote registries or modifying locked versions.
+- easyp get adds a direct requirement, records transitive requirements as indirect, and updates the lock.
+- easyp mod tidy resolves declared requirements, updates indirect entries and the lock, and preserves an existing lock pin for a requirement that remains unconstrained.
+- easyp mod update refreshes SemVer dependencies within their current major versions, refreshes still-unconstrained requirements to HEAD, and preserves explicit commit pins.
+- easyp mod download downloads exact locked commits and verifies their contents without changing locked versions.
+
+## Immutable versions and cache reuse
+
+During tidy, get, and update, every fetched previously locked SemVer is compared with its recorded commit and hash. A republished tag raises ErrLockedVersionChanged before installing the new graph or writing the manifest or lock. This includes transitive requirements and works independently of a warm installed-module cache. A new version may still be selected; unconstrained versionless requirements still refresh during mod update.
+
+mod download uses the locked commit even after a tag moves, provided that commit remains available.
+
+The hash uses Go's dirhash.Hash1 over all regular files tracked by Git at the commit, with repository-relative paths. EasyP verifies it on download and when reusing an installed module; corrupt installations are rejected.
+
+The v1 cache reuses an object store per Git remote. A known exact commit can be fetched without contacting the remote. A cold request first tries a depth-one fetch of the exact commit; if the server rejects that request, EasyP falls back to advertised reachable history. The original commit is still required: HEAD is never substituted. Tag lookups are refreshed separately so cache reuse cannot hide a retag. A commit absent from cache can still require access to its source.
+
+The source identity and SemVer version must satisfy the [major-version rules](/docs/reference/protobuf-mod): unsuffixed v0/v1, matching /vN for v2+. Invalid suffixes fail before installation. An unsuffixed v2+ +incompatible entry additionally requires the exact revision to have no native manifest, including when installed content is already cached. Commit pins still verify the exact native module identity, including in frozen mode.
+
+## MCP reference
+
+easyp_config_describe describes this format without reading local files. Use file: protobuf.lock and path: modules[].commit. See [configuration reference via MCP](/docs/cli/configuration).
diff --git a/content/docs/reference/protobuf-lock.ru.mdx b/content/docs/reference/protobuf-lock.ru.mdx
index 1b245a9..30cae53 100644
--- a/content/docs/reference/protobuf-lock.ru.mdx
+++ b/content/docs/reference/protobuf-lock.ru.mdx
@@ -3,7 +3,7 @@ title: "Справочник protobuf.lock"
description: "Спецификация файла protobuf.lock, автоматически генерируемого lock-файла для фиксации коммитов Git, версий и криптографических хешей для воспроизводимых сборок."
---
-Файл `protobuf.lock` — это автоматически генерируемый артефакт, создаваемый командами управления зависимостями EasyP (`easyp mod tidy`, `easyp mod update`). Он фиксирует точный транзитивный граф зависимостей для обеспечения **100% герметичных и воспроизводимых сборок** во всех локальных окружениях и в CI.
+Файл protobuf.lock создаётся командами easyp get, easyp mod tidy и easyp mod update. Он фиксирует выбранный граф Git-зависимостей точными коммитами и хешами содержимого. Это делает исходники зависимостей воспроизводимыми при доступности зафиксированных коммитов и успешной проверке целостности.
---
@@ -25,7 +25,7 @@ description: "Спецификация файла protobuf.lock, автомат
type: "string"
},
"modules[].version": {
- description: "Разрешённый тег Semantic Version (например, v1.2.3).",
+ description: "Выбранный SemVer-тег или полный хеш коммита для требования по SHA либо без версии.",
type: "string"
},
"modules[].commit": {
@@ -33,7 +33,7 @@ description: "Спецификация файла protobuf.lock, автомат
type: "string"
},
"modules[].hash": {
- description: "Криптографический хеш содержимого (h1:...) для контроля целостности.",
+ description: "Дайджест Go dirhash.Hash1 (h1:...) для обычных файлов, отслеживаемых Git в зафиксированном коммите.",
type: "string"
}
}}
@@ -43,28 +43,37 @@ description: "Спецификация файла protobuf.lock, автомат
## Пример lock-файла
-```yaml
-# protobuf.lock - СГЕНЕРИРОВАННЫЙ ФАЙЛ, НЕ РЕДАКТИРОВАТЬ РУКАМИ
+~~~yaml
+# Условные значения; реальные записи создаёт EasyP.
version: 1
modules:
- - source: github.com/googleapis/googleapis
- version: v1.5.0
- commit: 8f3a1c94b2e10a84e
- hash: h1:a9F8zK9mB20...
- - source: github.com/acme/weather
+ - source: github.com/acme/shared
version: v1.2.3
- commit: 51d2e071c89f33b11
- hash: h1:x7B3mL4k90a...
- - source: github.com/grpc-ecosystem/grpc-gateway
- version: v2.19.0
- commit: c4f88aa91024e12c4
- hash: h1:p0Q1wK97ab1...
-```
+ commit: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ hash: h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+~~~
---
## Команды жизненного цикла
-- `easyp mod tidy`: Сканирует импорты, дописывает транзитивные зависимости и перегенерирует `protobuf.lock`.
-- `easyp mod update`: Обновляет версии зависимостей до свежих совместимых релизов и обновляет `protobuf.lock`.
-- `easyp mod download`: Наполняет локальный кэш строго по `protobuf.lock` без обращения к внешним реестрам.
+- easyp get добавляет прямое требование, записывает транзитивные требования как indirect и обновляет lock.
+- easyp mod tidy разрешает объявленные требования, обновляет indirect-записи и lock. Для требования, оставшегося без ограничений версии, сохраняет прежний коммит из lock.
+- easyp mod update обновляет SemVer-зависимости в пределах текущей мажорной версии, освежает всё ещё неограниченные требования до HEAD и сохраняет явные хеши коммитов.
+- easyp mod download загружает точные коммиты из lock и проверяет содержимое, не меняя зафиксированные версии.
+
+## Неизменность версий и кеш
+
+При tidy, get и update повторно полученный ранее зафиксированный SemVer сравнивается с его записанными коммитом и хешем. Перепубликованный тег вызывает ErrLockedVersionChanged до установки нового графа и записи манифеста или lock. Проверка действует и для транзитивных требований, независимо от прогретого кеша. Новую версию по-прежнему можно выбрать; неограниченные требования без версии обновляются при mod update.
+
+mod download использует коммит из lock даже после переноса тега, если этот коммит доступен.
+
+hash вычисляется через Go dirhash.Hash1 по всем обычным файлам, отслеживаемым Git в коммите, с путями относительно репозитория. Хеш проверяется и при скачивании, и при повторном использовании установленного модуля; повреждённая установка отклоняется.
+
+Для каждого Git remote кеш v1 повторно использует хранилище объектов. Известный точный коммит можно получить без обращения к remote. При холодном запросе сначала выполняется shallow-загрузка точного коммита с глубиной один; если сервер её отклоняет, используется доступная история объявленных ссылок. Всё равно требуется исходный коммит: HEAD вместо него не подставляется. Проверки тегов обновляются отдельно, поэтому кеш не скрывает перенос тега. Отсутствующий в кеше коммит всё ещё может потребовать доступа к источнику.
+
+Идентификатор source и SemVer в version должны соответствовать [правилам major-версий](/ru/docs/reference/protobuf-mod): v0/v1 без суффикса, v2+ с соответствующим /vN. Некорректные суффиксы отклоняются до установки. Для v2+ без суффикса пути запись +incompatible дополнительно требует отсутствия нативного manifest в точной ревизии, в том числе при уже заполненном кеше. Коммит проверяется по точному нативному имени модуля, включая frozen-режим.
+
+## Справка MCP
+
+easyp_config_describe описывает формат, не читая локальные файлы. Укажите file: protobuf.lock и path: modules[].commit. См. [справку по конфигурации через MCP](/ru/docs/cli/configuration).
diff --git a/content/docs/reference/protobuf-mod.mdx b/content/docs/reference/protobuf-mod.mdx
index f428d89..bce19a0 100644
--- a/content/docs/reference/protobuf-mod.mdx
+++ b/content/docs/reference/protobuf-mod.mdx
@@ -3,7 +3,7 @@ title: "protobuf.mod Reference"
description: "Specification for protobuf.mod, the tool-neutral DSL for defining Protocol Buffer module identities, roots, requirements, and local replace directives."
---
-The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designed as a **tool-neutral standard**, it contains zero tool-specific settings (no linter flags, generator plugins, or vendor extensions). It is strictly focused on module identity, inner root directories, dependency requirements, and local source overrides.
+The protobuf.mod file resides at the root of a Protocol Buffer module. Designed as a **tool-neutral standard**, it contains zero tool-specific settings (no linter flags, generator plugins, or vendor extensions). It is strictly focused on module identity, inner root directories, dependency requirements, and local source overrides.
---
@@ -12,23 +12,23 @@ The `protobuf.mod` file resides at the root of a Protocol Buffer module. Designe
github.com/acme/weather).
+2. **Per-Module Bounds**: Every module maintains its own independent protobuf.mod. MVS operates per-module rather than forcing global monorepo single-version constraints.
+3. **Local replacements**: Only main-module directives apply, including to transitive requirements; dependency-owned replacements are ignored. A replacement alone does not introduce a module. With replace, commands use a local effective graph and preserve protobuf.lock byte-for-byte; a missing lock is not created. mod tidy also leaves the manifest unchanged. get and mod update may edit explicit requirements without adding fork-only transitives. mod download installs only needed unreplaced snapshots. Remove replacements and run mod tidy to produce a publishable lock. See [local replacements](/docs/guides/debugging-replace).
+
+For multiple modules, place a protobuf.mod in each module directory. Module commands and get select the nearest ancestor manifest within the workspace; each module keeps its own protobuf.lock. generate.modules selects local modules by identity or workspace-relative path. A consumer declares each nested Git module separately by its manifest identity.
+
+A version may be omitted, for example require github.com/acme/contracts/proto/user. This adds no constraint if the graph already supplies a SemVer or exact commit. Only a still-unconstrained requirement uses the existing lock pin during tidy, or current HEAD without a pin; mod update refreshes it to HEAD. An explicit full 40- or 64-hex-character commit remains an exact constraint.
+
+SemVer requirements select the maximum requested minimum. SemVer and SHA requirements are compatible only when the selected tag points to that exact commit. Different explicit commits or a selected tag at another commit conflict; SHA values, dates, and commit ancestry are not given a semantic version order. For a nested module in proto/user, version v1.2.3 uses tag proto/user/v1.2.3. Each module has its own lock entry and roots.
+
+A local replace may target a nested module directory. Its native manifest must declare the replaced identity, and its requirements participate in the effective graph. Relative paths always use the main manifest directory, even at transitive depths; absolute paths are used directly. Historical breaking comparisons map in-repository replacements to the corresponding revision snapshot and reject external local paths. Preserving the lock is an explicit EasyP invariant, not a claim that Go never changes go.sum.
+
+For example, with repo/foo/protobuf.mod containing roots proto, EasyP reads files under the physical repository path repo/foo/proto. A file at repo/foo/proto/user/v1/user.proto has the protobuf import path user/v1/user.proto: import paths are relative to the resolved root, so the module directory and the root directory are not repeated in imports. With roots ., the physical root is repo/foo.
+
+## Major version identities
+
+v0 and v1 use the same unsuffixed module path. v2 and later require a final /vN component matching the SemVer major, with no leading zeros: require github.com/acme/weather/v2 v2.1.0. /v0, /v1, /v01 and /v2.0 are invalid module suffixes. Ordinary components such as /2024 and /v2beta are not suffixes. This does not restrict package directories or protobuf import paths. Go's special gopkg.in/name.vN spelling is recognized by the same suffix helpers.
+
+The rule applies to declared module identities, requirements, replacement source identities, fetched native metadata and lock entries. Full commits and omitted versions still require the exact requested native identity. Absolute local Git paths and explicit URLs are supported; the logical URL host/path is checked separately from transport credentials and ports. EasyP preserves the original identity spelling.
+
+| Identity | Physical directory containing protobuf.mod | Tag for the example release |
+|---|---|---|
+| repo | repository root | v1.2.0 |
+| repo/v2 | root or v2/ | v2.0.0 |
+| repo/sub/v2 | sub/ or sub/v2/ | sub/v2.0.0 |
+
+The major suffix is logical and is not included in the tag prefix: v2/v2.0.0 is not the release tag for repo/v2. Both lightweight and annotated tags work. The manifest at an allowed location must declare the exact requested identity; finding a tag alone is insufficient.
+
+repo and repo/v2 can coexist as distinct module, lock and replacement identities. MVS chooses the highest requested minimum per identity. You must provide distinct protobuf import paths yourself: EasyP never renames packages or imports, and duplicate import paths still fail. Same-major updates, exact SHA/tag agreement, immutable tags, local replacement lock preservation and frozen verification continue to apply.
+
+The pre-module +incompatible exception is supported only for unsuffixed v2+ revisions without a native protobuf.mod. EasyP reads the underlying tag without the suffix and verifies metadata on the exact fetched or cached commit before accepting the lock entry. It rejects native manifests even when the marker is present. Legacy updates retain the marker; local replacements remain unversioned overlays and never publish their graph to the lock. Migration never silently renames a source or changes its version.
+
+See [Go major version suffixes](https://go.dev/ref/mod#major-version-suffixes) and [mapping versions to commits](https://go.dev/ref/mod#vcs-version).
+
+As in Go, an unversioned local replacement may contain a native manifest with the same unsuffixed identity while replacing an explicit legacy +incompatible requirement. This does not certify the published revision: the overlay preserves the shared lock, and frozen mode rejects replacements. Published fetches and both cold and warm locked installations still enforce the pre-native metadata check.
+
+## MCP reference
+
+easyp_config_describe describes this format without reading local files. Use file: protobuf.mod and path: require[].version. See [configuration reference via MCP](/docs/cli/configuration).
diff --git a/content/docs/reference/protobuf-mod.ru.mdx b/content/docs/reference/protobuf-mod.ru.mdx
index 01168cb..9418b3e 100644
--- a/content/docs/reference/protobuf-mod.ru.mdx
+++ b/content/docs/reference/protobuf-mod.ru.mdx
@@ -3,7 +3,7 @@ title: "Справочник protobuf.mod"
description: "Спецификация файла protobuf.mod, независимого от инструментов DSL для объявления идентичности модулей Protocol Buffer, корневых каталогов, зависимостей и локальных замен."
---
-Файл `protobuf.mod` располагается в корне proto-модуля. Задуманный как **tool-neutral стандарт**, он не содержит настроек конкретных инструментов (ни флагов линтеров, ни плагинов генерации). Файл сфокусирован исключительно на идентификации модуля, внутренних директориях, объявлениях зависимостей и локальных переопределениях источников.
+Файл protobuf.mod располагается в корне proto-модуля. Задуманный как **tool-neutral стандарт**, он не содержит настроек конкретных инструментов (ни флагов линтеров, ни плагинов генерации). Файл сфокусирован исключительно на идентификации модуля, внутренних директориях, объявлениях зависимостей и локальных переопределениях источников.
---
@@ -12,23 +12,23 @@ description: "Спецификация файла protobuf.mod, независи
github.com/acme/weather).
+2. **Помодульный скоуп**: Каждый модуль имеет собственный protobuf.mod. MVS работает помодульно (per-module), не навязывая глобальных ограничений версий в монорепозитории.
+3. **Локальные замены**: Применяются только директивы главного модуля, включая транзитивные требования; замены в зависимостях игнорируются. Сама замена не добавляет модуль в граф. При наличии replace команды работают с локальным эффективным графом и сохраняют protobuf.lock побайтно; отсутствующий lock не создаётся. mod tidy также не меняет манифест. get и mod update могут менять явные требования, но не добавляют транзитивные зависимости только из форка. mod download устанавливает только нужные незаменённые снимки. Для публикуемого lock удалите замены и выполните mod tidy. Подробнее: [локальные замены](/ru/docs/guides/debugging-replace).
+
+Для нескольких модулей положите protobuf.mod в каталог каждого. Команды mod и get выбирают ближайший манифест в предках в пределах workspace; каждый модуль сохраняет свой protobuf.lock. generate.modules выбирает локальные модули по имени или пути относительно workspace. В потребителе каждый вложенный Git-модуль объявляется отдельно по имени из его манифеста.
+
+Версию можно опустить, например require github.com/acme/contracts/proto/user. Такое требование не добавляет ограничения, если граф уже задаёт SemVer или точный коммит. Только оставшееся неограниченным требование использует прежний коммит lock при tidy либо текущий HEAD без lock; mod update освежает его до HEAD. Явный полный хеш из 40 или 64 hex-символов остаётся точным ограничением.
+
+SemVer-требования выбирают максимум запрошенных минимумов. SemVer и SHA совместимы, только если выбранный тег указывает на этот точный коммит. Разные явные коммиты или выбранный тег на другом коммите вызывают конфликт; порядок версий из SHA, даты или истории коммитов не выводится. Для вложенного модуля в proto/user версия v1.2.3 использует тег proto/user/v1.2.3. У каждого модуля своя запись lock и корни.
+
+Локальный replace может указывать на каталог вложенного модуля. Его нативный манифест должен объявлять заменяемое имя; требования замены участвуют в эффективном графе. Относительные пути всегда считаются от главного манифеста, даже на транзитивной глубине; абсолютные используются напрямую. Для исторических breaking-сравнений пути внутри репозитория отображаются в снимок соответствующей ревизии, внешние локальные пути отклоняются. Сохранение lock — явный инвариант EasyP, а не утверждение, что Go никогда не меняет go.sum.
+
+Например, если в repo/foo/protobuf.mod указано roots proto, EasyP читает файлы из физического пути repo/foo/proto внутри репозитория. У файла repo/foo/proto/user/v1/user.proto protobuf import path будет user/v1/user.proto: путь импорта считается относительно вычисленного root, поэтому каталог модуля и сам root в импорте не повторяются. При roots . физический root — repo/foo.
+
+## Идентичность мажорных версий
+
+v0 и v1 используют один путь без суффикса. Для v2 и выше нужен последний компонент /vN, совпадающий с major в SemVer, без ведущих нулей: require github.com/acme/weather/v2 v2.1.0. Суффиксы модуля /v0, /v1, /v01 и /v2.0 недопустимы. Обычные компоненты /2024 и /v2beta не считаются суффиксами. Правило не ограничивает каталоги пакетов и protobuf import paths. Общие с Go функции проверки также распознают особую запись gopkg.in/name.vN.
+
+Проверяются объявленное имя модуля, требования, исходные имена в replace, загруженные нативные метаданные и записи lock. Полный коммит и отсутствие версии не отменяют точного совпадения нативного имени. Абсолютные локальные Git-пути и явные URL поддерживаются: логический host/path проверяется отдельно от учётных данных и порта транспорта. Исходное написание идентификатора сохраняется.
+
+| Идентификатор | Физический каталог с protobuf.mod | Тег примера релиза |
+|---|---|---|
+| repo | корень репозитория | v1.2.0 |
+| repo/v2 | корень или v2/ | v2.0.0 |
+| repo/sub/v2 | sub/ или sub/v2/ | sub/v2.0.0 |
+
+Мажорный суффикс логический и не входит в префикс тега: v2/v2.0.0 не является тегом релиза repo/v2. Поддерживаются обычные и аннотированные теги. Манифест в допустимом каталоге должен объявлять точный запрошенный идентификатор; одного совпадения тега недостаточно.
+
+repo и repo/v2 могут сосуществовать как разные идентификаторы модулей, записей lock и замен. MVS выбирает максимум запрошенных минимумов для каждого имени отдельно. Различные protobuf import paths задаёт автор: EasyP не переименовывает пакеты и импорты, а совпадение путей импорта остаётся ошибкой. Обновления внутри major, точное согласование SHA/тега, неизменность тегов, сохранение lock при локальных заменах и frozen-проверки сохраняются.
+
+Домодульное исключение +incompatible поддерживается только для v2+ без суффикса пути и без нативного protobuf.mod в выбранной ревизии. EasyP читает исходный Git-тег без этой метки и проверяет метаданные точного скачанного или кешированного коммита до принятия записи lock. При наличии нативного manifest метка не обходит проверку. Обновления старого модуля сохраняют метку; локальные замены остаются неверсионируемым наложением и не записывают свой граф в lock. Миграция не переименовывает источник и не меняет версию молча.
+
+См. [мажорные суффиксы Go](https://go.dev/ref/mod#major-version-suffixes) и [соответствие версий коммитам](https://go.dev/ref/mod#vcs-version).
+
+Как и в Go, локальная замена без опубликованной версии может содержать нативный манифест с тем же именем без суффикса для явного требования +incompatible. Это не подтверждает опубликованную ревизию: локальный граф сохраняет общий lock, а frozen-режим запрещает замены. Загрузка опубликованных версий и установка lock в холодном и прогретом кеше по-прежнему проверяют домодульные метаданные.
+
+## Справка MCP
+
+easyp_config_describe описывает формат, не читая локальные файлы. Укажите file: protobuf.mod и path: require[].version. См. [справку по конфигурации через MCP](/ru/docs/cli/configuration).
diff --git a/lib/github-release.test.mjs b/lib/github-release.test.mjs
new file mode 100644
index 0000000..9eab3ac
--- /dev/null
+++ b/lib/github-release.test.mjs
@@ -0,0 +1,87 @@
+import assert from 'node:assert/strict'
+import test from 'node:test'
+import { getLatestRelease } from './github-release.ts'
+
+const latestURL = 'https://api.github.com/repos/easyp-tech/easyp/releases/latest'
+const releasesURL = 'https://api.github.com/repos/easyp-tech/easyp/releases?per_page=100'
+const release = (tag, flags = {}) => ({
+ tag_name: tag,
+ name: tag,
+ draft: false,
+ prerelease: false,
+ ...flags,
+})
+
+function mockGitHub(t, latest, releases) {
+ t.mock.method(console, 'error', () => {})
+ return t.mock.method(globalThis, 'fetch', async (url) => {
+ const value = url === latestURL ? latest : releases
+ if (value instanceof Error) throw value
+ return value instanceof Response ? value : Response.json(value)
+ })
+}
+
+test('uses the validated published stable latest release and keeps Next cache options', async (t) => {
+ const fetch = mockGitHub(t, release('v0.17.1'), [])
+ assert.equal(await getLatestRelease(), 'v0.17.1')
+ assert.equal(fetch.mock.callCount(), 1)
+ const [url, options] = fetch.mock.calls[0].arguments
+ assert.equal(url, latestURL)
+ assert.equal(options.next.revalidate, 3600)
+ assert.equal(options.headers.Accept, 'application/vnd.github+json')
+})
+
+test('allows a future published stable v1 release without a major-version ceiling', async (t) => {
+ mockGitHub(t, release('v1.0.0'), [])
+ assert.equal(await getLatestRelease(), 'v1.0.0')
+})
+
+for (const [name, latest] of [
+ ['HTTP error', new Response('', { status: 404 })],
+ ['network error', new Error('network unavailable')],
+ ['invalid JSON', new Response('{invalid', { headers: { 'Content-Type': 'application/json' } })],
+ ['malformed JSON shape', { tag_name: 42, draft: false, prerelease: false }],
+ ['nightly tag with false prerelease flag', release('v1.0.0-nightly.20261005.1')],
+ ['stable-shaped prerelease', release('v1.0.0', { prerelease: true })],
+ ['stable-shaped draft', release('v1.0.0', { draft: true })],
+ ['missing publication flags', { tag_name: 'v1.0.0' }],
+ ['non-boolean publication flags', { tag_name: 'v1.0.0', draft: 0, prerelease: 'false' }],
+]) {
+ test(`falls back to published stable releases after latest ${name}`, async (t) => {
+ const fetch = mockGitHub(t, latest, [
+ release('v1.0.0-nightly.20261005.1', { prerelease: true }),
+ release('v0.17.1'),
+ ])
+ assert.equal(await getLatestRelease(), 'v0.17.1')
+ assert.equal(fetch.mock.calls[1].arguments[0], releasesURL)
+ })
+}
+
+test('fallback chooses the highest stable version numerically, independently of list order', async (t) => {
+ mockGitHub(t, new Response('', { status: 503 }), [
+ release('v0.9.9'),
+ release('v2.0.0-nightly.20261005.1'),
+ release('v1.0.0', { draft: true }),
+ release('v1.0.0', { prerelease: true }),
+ release('v0.10.2'),
+ release('v0.10.1'),
+ release('v0.10.3-rc.1'),
+ ])
+ assert.equal(await getLatestRelease(), 'v0.10.2')
+})
+
+for (const [name, releases] of [
+ ['nightlies and prereleases only', [release('v1.0.0-nightly.20261005.1'), release('v1.0.0-rc.1'), release('v1.0.0-beta.2')]],
+ ['drafts and stable-shaped prereleases only', [release('v1.0.0', { draft: true }), release('v0.17.1', { prerelease: true })]],
+ ['unknown and malformed tags only', [release('nightly'), release('v1.0'), release('v01.2.3'), { name: 'v0.17.1' }, null]],
+ ['empty list', []],
+ ['invalid list shape', { tag_name: 'v0.17.1' }],
+ ['fallback HTTP failure', new Response('', { status: 500 })],
+ ['fallback network failure', new Error('network unavailable')],
+ ['fallback invalid JSON', new Response('{invalid')],
+]) {
+ test(`fails closed when fallback contains ${name}`, async (t) => {
+ mockGitHub(t, new Response('', { status: 404 }), releases)
+ assert.equal(await getLatestRelease(), 'unknown version')
+ })
+}
diff --git a/lib/github-release.ts b/lib/github-release.ts
index ec109dd..21a103a 100644
--- a/lib/github-release.ts
+++ b/lib/github-release.ts
@@ -1,32 +1,26 @@
interface GithubRelease {
tag_name: string
-}
-
-interface GithubTag {
- name: string
+ draft: boolean
+ prerelease: boolean
}
const REPO = 'easyp-tech/easyp'
-function isStable(name: string): boolean {
- const v = name.toLowerCase()
+function isPublishedStable(value: unknown): value is GithubRelease {
+ if (typeof value !== 'object' || value === null) return false
+ const release = value as PartialМодульные Protobuf-схемы, фиксированные зависимости, генерация через плагины и проверки API теперь собраны в последовательный workflow. Источник версий — protobuf.mod, воспроизводимость — protobuf.lock.
+ +Каждый шаг использует явно выбранные модули и корни исходников. Изменения версий проходят через менеджер зависимостей, а не через конфиг плагина.
Идентичность модуля, roots, прямые и транзитивные Git-зависимости.
Выбранный коммит и h1-хеш для каждого внешнего модуля.
Какие модули генерировать, какими плагинами и куда писать файлы.
Генерация, lint, breaking, validate-config и CI из одних источников.
В v1.0 больше не нужно смешивать зависимости, плагины и проверки в одном YAML.
Текстовый манифест модуля. Roots считаются относительно каталога самого файла. Поддерживает require и локальный replace.
Создаётся командами EasyP. Сохраняет выбранные версии, точные Git-коммиты и h1-хеши. Редактировать вручную не нужно.
Конфиг потребителя: выбор модулей, локальные/встроенные/удалённые плагины, опции и managed mode.
Конфиг продюсера: пресеты и правила lint, исключения и Git-baseline для проверки совместимости.
Переключайте сценарии: обычный проект, монорепозиторий с вложенными модулями и проект без внешних зависимостей.
Манифест описывает источник proto, генератор выбирает модуль и плагины, политика остаётся рядом со схемами.
module github.com/acme/contracts +roots proto + +require github.com/acme/shared v1.2.3
version: v1 +generate: + modules: [github.com/acme/contracts] +plugins: + - name: go + out: gen/go + opts: + paths: source_relative + - name: go-grpc + out: gen/go + opts: + paths: source_relative
version: v1 +linters: + default: STANDARD +breaking: + baseline: git:main
easyp mod tidy +easyp mod download +easyp generate +easyp lint --path proto +easyp breaking --path proto --against main
Каждый вложенный модуль объявляется отдельным require. Отдельные теги не нужны: требование без версии разрешается по Git HEAD и фиксируется в lock.
contracts/
+├── foo/
+│ ├── protobuf.mod
+│ └── schemas/proto/user/v1/foo.proto
+└── bar/
+ ├── protobuf.mod
+ └── schemas/proto/order/v1/bar.proto
+
+# В каждом модуле roots schemas/protomodule github.com/acme/app + +require ( + github.com/acme/contracts/foo + github.com/acme/contracts/bar +)
Физический файл: contracts/foo/schemas/proto/user/v1/foo.proto +Proto import: user/v1/foo.proto + +Физический файл: contracts/bar/schemas/proto/order/v1/bar.proto +Proto import: order/v1/bar.proto
После easyp mod tidy появятся две записи lock. Каждый модуль имеет собственный roots относительно своего protobuf.mod. EasyP добавляет путь к вложенному модулю для поиска файла, а import path считает уже относительно root.
Если Git-зависимостей нет, манифест не обязателен: каталог проекта становится локальным root для генерации и списка proto-файлов.
project/
+├── api/v1/user.proto
+├── easyp.gen.yaml
+└── easyp.yaml
+
+# protobuf.mod и protobuf.lock отсутствуютversion: v1 +plugins: + - name: python + out: gen/python
easyp generate +easyp ls-files --include-imports=false
Когда появятся внешние импорты, добавьте protobuf.mod и требуемые модули через easyp get.
Версия может быть SemVer-тегом, полным коммитом или отсутствовать. В последнем случае EasyP выбирает HEAD и записывает точный коммит в lock.
easyp get module[@version|@commit] добавляет прямой require. Найденные транзитивные зависимости записываются с // indirect.
mod tidy разрешает требования и обновляет lock. Неразрешённый импорт не превращается в ложный пустой lock.
mod download берёт точные коммиты из lock и проверяет h1-хеш содержимого, включая повторное использование кеша.
mod update обновляет совместимые версии по тегам и требования без версии до HEAD; явно закреплённый коммит сохраняет выбор.
mod vendor копирует proto-файлы из lock в easyp_vendor. Повторяющиеся import path вызывают ошибку.
Git-зависимость может описывать roots через Buf v1/v2 или старый EasyP. Потребителю достаточно собственного v1-манифеста.
У каждого вложенного protobuf.mod своя identity и roots. EasyP читает метаданные зависимости в её каталоге; если подходящего конфига нет, источником считается корень репозитория.
replace module => ../local-copy помогает при генерации и lint. Перед записью воспроизводимого lock через get, tidy или update локальную замену нужно убрать.
easyp generate обнаруживает consumer-конфиги, компилирует выбранные модули целиком и запускает плагины. Версии proto-зависимостей не дублируются в YAML генератора.
plugins[].name выбирает локальный protoc-gen-* или встроенный WASM-плагин через существующий resolver. Можно задать несколько плагинов и разные out.
plugins[].path запускает конкретный исполняемый файл. Относительный путь считается от каталога запуска easyp generate.
plugins[].command принимает список из программы и аргументов, например [sh, ./tools/plugin.sh]. Это поле называлось command и в старом конфиге.
plugins[].remote подключает удалённый генератор. Отдельное поле version требует зафиксированный SemVer; эта версия передаётся исполнителю.
generate.managed сохраняет правила disable/override для file и field options с селекторами module, package, path и field.
options.go.package_prefix вычисляет Go-импорты без редактирования proto. Корневой generator может дать вложенным значение по умолчанию.
У каждого сервиса может быть свой easyp.gen.yaml. --project запускает один выбранный consumer. Plugins не наследуются из корня.
--descriptor_set_out пишет набор дескрипторов; --include_imports добавляет транзитивные импорты. Результат можно использовать в других инструментах.
version: v1 +plugins: + - path: ./tools/protoc-gen-custom + out: ./gen/custom + - command: [sh, ./tools/protoc-plugin.sh] + out: ./gen/script
Для каждого плагина указывается один источник: name, path, command или remote. Собственный плагин читает CodeGeneratorRequest из stdin и пишет CodeGeneratorResponse в stdout.
protobuf.mod рядом с собой; если его нет — корневой манифест проекта. Зависимости выбранного модуля берутся оттуда же.Одни и те же proto-файлы можно проверять локально и в CI. Политики действуют по дереву каталогов, а breaking сравнивает API с Git baseline.
Пресеты MINIMAL, BASIC, STANDARD, COMMENTS; выборочные enable/disable и настройки отдельных правил. Ближайший easyp.yaml задаёт секцию для своего поддерева. Исключение без path может подавить выбранные правила.
breaking.baseline: git:main выбирает Git-ветку для существующего checker. Вложенная политика может выбрать другой baseline; breaking.ignore исключает указанные пути.
version: v1 +linters: + default: STANDARD + enable: [RPC_REQUEST_RESPONSE_UNIQUE] + disable: [PACKAGE_VERSION_SUFFIX] +issues: + exclude-rules: + - linters: [FIELD_LOWER_SNAKE_CASE] +breaking: + baseline: git:main
Рекурсивно проверяет все четыре типа файлов. Можно указать один файл или каталог; JSON-ошибки содержат путь, ошибки структуры YAML — строку и столбец.
Генерирует отдельные JSON Schema для easyp.yaml, easyp.gen.yaml и protobuf.lock. YAML-валидация CLI использует тот же источник схемы.
Экспортируемый Go-пакет mcp/easypconfig регистрирует easyp_config_describe в своём MCP-сервере. Инструмент описывает редактируемые YAML-файлы.
В двух YAML-конфигах работают ${NAME}, ${NAME:-default} и экранирование $${NAME}. Комментарии YAML подстановке не мешают.
Показывает локальные proto и доступные импорты из зависимостей и встроенных схем. --include-imports=false оставляет только локальные файлы.
init создаёт стартовые v1-файлы, умеет выводить identity из Git origin и учитывает подтверждение перезаписи. completion помогает работать из shell.
easyp initСоздать стартовый набор конфигов и manifest.easyp get MODULE[@REF]Добавить прямую Git-зависимость и записать транзитивные как indirect.easyp mod tidyРазрешить граф из protobuf.mod и обновить lock.easyp mod downloadПолучить ровно те коммиты, которые указаны в lock, с проверкой хеша.easyp mod updateОбновить совместимые версии и lock.easyp mod vendorСкопировать зафиксированные proto-зависимости в easyp_vendor.easyp generate [--project DIR]Сгенерировать код по обнаруженным consumer-конфигам или одному выбранному проекту.easyp lint --path DIRПроверить стиль и структуру proto по ближайшим политикам.easyp breaking --against mainНайти несовместимые изменения относительно Git baseline.easyp ls-filesПоказать исходники и reachable imports; доступен text/JSON формат.easyp validate-configРекурсивно проверить конфиги, manifest и lock.easyp schema-gen --out-dir schemasСоздать JSON Schema для редактора и CI.easyp completionНастроить shell completion.Эти ограничения отмечены явно: конфиг не должен молча создавать впечатление, что неподдерживаемая настройка сработала.
categories, ignore_unstable: true и extends не включены в текущий checker и вызывают ошибку.linters.extends и issues.exclude-rules.path пока не реализованы; исключения без path работают.easyp_config_describe объясняет только редактируемые YAML-файлы. protobuf.mod и protobuf.lock остаются за CLI.Откройте вкладку «Несколько модулей», выполните easyp mod tidy, затем easyp ls-files и easyp generate. Коллеги увидят отдельные записи lock для вложенных модулей и import path без префикса каталога модуля.