diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c97bff..4bd4e07 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,9 +6,3 @@
### Features
* add dialog engine core library ([3f5c89a](https://github.com/k0te1ch/DialogEngine/commit/3f5c89aece8cd3a16d09618571c2f01ef5ddd98e))
-* dialog engine library with poetry, CI and release-please ([1e74a7a](https://github.com/k0te1ch/DialogEngine/commit/1e74a7a07fff484beeb299e7b76a4e2097845a77))
-
-
-### Documentation
-
-* add README, usage example and workflow guide ([0c630e7](https://github.com/k0te1ch/DialogEngine/commit/0c630e7cae1fde2125e594366daefab4bf811d51))
diff --git a/README.md b/README.md
index 6043606..0c7fba1 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ Commits follow [Conventional Commits](https://www.conventionalcommits.org/);
the format is enforced by the `commitizen` hook. Releases, tags, and
`CHANGELOG.md` are fully automated via
[release-please](https://github.com/googleapis/release-please). See the full
-guide with diagrams in [docs/WORKFLOW.md](docs/WORKFLOW.md).
+guide with diagrams: [English](docs/WORKFLOW.en.md) · [Русский](docs/WORKFLOW.md).
## Project layout
diff --git a/docs/WORKFLOW.en.md b/docs/WORKFLOW.en.md
new file mode 100644
index 0000000..947fdb5
--- /dev/null
+++ b/docs/WORKFLOW.en.md
@@ -0,0 +1,272 @@
+# Workflow: how it all works
+
+> 🌐 **Languages:** [Русский](WORKFLOW.md) · English (current)
+
+This document describes the full cycle — from the first `git commit` to a GitHub
+Release — and how to organize work through feature branches.
+
+> All diagrams are written in [Mermaid](https://mermaid.js.org/). GitHub renders
+> them automatically.
+
+---
+
+## 1. The big picture
+
+```mermaid
+flowchart TD
+ A[Local changes] --> B[git commit]
+ B --> C{pre-commit hooks}
+ C -- ruff / ruff-format --> C
+ C -- commit-msg commitizen --> D{Conventional Commits?}
+ D -- no --> X[Commit rejected fix the message]
+ D -- yes --> E[Commit created locally]
+ E --> F[git push to feature branch]
+ F --> G[Pull Request on GitHub]
+ G --> H[CI: python-app.yml pre-commit + pytest]
+ H -- green --> I[Squash-merge into main PR title = commit]
+ I --> J[CI: release-please.yml]
+ J --> K[release-please opens/ updates the Release PR]
+ K -- merge Release PR --> L[Tag vX.Y.Z + GitHub Release + CHANGELOG.md]
+
+ classDef bad fill:#fee,stroke:#c33;
+ class X bad;
+```
+
+The key idea: **commit messages are the "source" of the changelog**. That is why
+their format is strictly checked at `git commit` time, before the code even
+reaches the server, and release-please turns them into a version and a CHANGELOG.
+
+---
+
+## 2. Conventional Commits — message format
+
+```
+()!:
+
+
+
+
+```
+
+`type` is required, the rest is optional. A `!` after the type/scope marks a
+breaking change.
+
+| Type | When to use | In CHANGELOG / release |
+|------------|---------------------------------------------------|------------------------------|
+| `feat` | New functionality | **Features** · minor |
+| `fix` | Bug fix | **Bug Fixes** · patch |
+| `perf` | Performance improvement | **Performance** · patch |
+| `revert` | Revert of a previous commit | **Reverts** · patch |
+| `docs` | Documentation only | hidden, no release |
+| `refactor` | Refactoring without behavior change | hidden, no release |
+| `test` | Adding/updating tests | hidden, no release |
+| `build` | Build, dependencies (pyproject.toml, poetry.lock) | hidden, no release |
+| `ci` | GitHub Actions, pre-commit | hidden, no release |
+| `style` | Formatting, no logic change | hidden, no release |
+| `chore` | Chores with no impact on the code | hidden, no release |
+
+> Which types appear in the CHANGELOG and trigger a release is configured via
+> `changelog-sections` in [release-please-config.json](../release-please-config.json).
+> Currently a release is cut only for `feat` / `fix` / `perf` / `revert`; the
+> rest is hidden.
+
+**Examples:**
+
+```bash
+git commit -m "feat(engine): add conditional step routing"
+git commit -m "fix(validators): trim whitespace before length check"
+git commit -m "feat(engine)!: drop sync submit() in favour of async" # breaking
+git commit -m "refactor: extract session store into module"
+```
+
+For a breaking change use either `!` or a footer:
+
+```
+feat(engine): switch to async validators
+
+BREAKING CHANGE: validators must now be coroutines.
+```
+
+**How the commit type affects the version** (release-please counts commits since
+the last release):
+
+- `BREAKING CHANGE` → **minor** while on `0.x` (major after `1.0.0`);
+- `feat:` → **minor** (0.1.0 → 0.2.0);
+- `fix:` / `perf:` → **patch** (0.1.0 → 0.1.1);
+- everything else → no version change.
+
+> While the project is on `0.x`, a breaking change bumps minor rather than major —
+> which is normal for a library that has not shipped `1.0.0` yet
+> (`bump-minor-pre-major` in `release-please-config.json`).
+
+---
+
+## 3. Local development loop
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Dev as Developer
+ participant Git as git (local)
+ participant PC as pre-commit
+ participant CZ as commitizen
+ Dev->>Git: git add .
+ Dev->>Git: git commit -m "feat: ..."
+ Git->>PC: run pre-commit hooks
+ PC->>PC: ruff, ruff-format, end-of-file-fixer
+ alt a hook modified files
+ PC-->>Dev: commit rejected, re-run git add + commit
+ end
+ Git->>CZ: run commit-msg hook
+ CZ->>CZ: parse the message
+ alt does not match the format
+ CZ-->>Dev: error with an example of a valid message
+ else all good
+ CZ-->>Git: ok
+ Git-->>Dev: commit created
+ end
+```
+
+Install the hooks (once, after `poetry install`):
+
+```bash
+poetry run pre-commit install --hook-type pre-commit --hook-type commit-msg
+```
+
+If you are unsure about the format, there is an interactive mode:
+
+```bash
+poetry run cz commit # walks you through and assembles the message
+```
+
+---
+
+## 4. Branches — GitHub Flow
+
+```mermaid
+gitGraph
+ commit id: "init"
+ commit id: "feat: engine"
+ branch feat/conditional-steps
+ checkout feat/conditional-steps
+ commit id: "feat: routing"
+ commit id: "test: cover routing"
+ checkout main
+ merge feat/conditional-steps tag: "squash PR #12"
+ commit id: "chore(main): release 0.2.0" tag: "v0.2.0"
+```
+
+- A single long-lived branch: `main`, always green and releasable.
+- All work happens on short feature branches `feat/...`, `fix/...`, `chore/...`.
+- **Squash-merge** via a PR with green CI: the atomic commits stay in the PR, and
+ `main` gets a single commit with the PR title — so history stays linear and the
+ changelog stays clean (one entry per PR).
+- Releases are handled by release-please through a dedicated Release PR (see §6).
+
+### A few rules
+
+1. **Small PRs.** Three 200-line PRs beat one 600-line PR.
+2. **One topic per branch.** Don't mix refactoring with a feature.
+3. **The PR title is a valid Conventional Commit.** On squash it becomes the
+ commit on `main` and lands in the changelog.
+4. **Branch names:** `feat/`, `fix/`, `chore/`.
+5. **Never push --force to main.** To your own feature branch — fine after a
+ rebase, via `--force-with-lease`.
+
+---
+
+## 5. Step-by-step team loop
+
+```bash
+# 1. Fresh main
+git switch main
+git pull --ff-only
+
+# 2. New branch
+git switch -c feat/conditional-steps
+
+# 3. Work + atomic commits (they live in the PR)
+git add dialog_engine/
+git commit -m "feat(engine): add conditional step routing"
+git commit -m "test(engine): cover conditional routing"
+
+# 4. Push and open a PR (PR title = the future squash commit)
+git push -u origin feat/conditional-steps
+gh pr create --title "feat(engine): conditional step routing" --body "Closes #42"
+
+# 5. After green CI — squash-merge, delete the branch
+gh pr merge --squash --delete-branch
+
+# 6. Cleanup
+git switch main && git pull --ff-only
+```
+
+### Rebase or merge?
+
+The rule: **rebase for your own branches, squash to land on `main`**. After a
+rebase use `git push --force-with-lease` (safer than `--force`).
+
+---
+
+## 6. Releases — release-please
+
+Versions, tags, GitHub Releases, and `CHANGELOG.md` are fully automated — you do
+not bump or tag anything by hand.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Main as origin/main
+ participant RP as release-please.yml
+ participant PR as Release PR
+ participant Rel as GitHub Releases
+
+ Main->>RP: push (after merging a feature PR)
+ RP->>RP: read Conventional Commits since the last release
+ RP->>RP: compute the next version
+ RP->>PR: open/update the Release PR (version bump + CHANGELOG.md)
+ Note over PR: the PR accumulates while new commits land
+ PR->>Main: you merge the Release PR
+ Main->>RP: push
+ RP->>Rel: create tag vX.Y.Z and a GitHub Release
+```
+
+How it looks in practice:
+
+1. You merge regular feature PRs into `main` with Conventional messages.
+2. release-please opens (and keeps up to date) a **Release PR** named
+ `chore(main): release X.Y.Z` — it bumps the version in `pyproject.toml` and
+ `dialog_engine/__init__.py` and generates `CHANGELOG.md`.
+3. When you are ready to ship — **merge the Release PR**. release-please creates
+ the `vX.Y.Z` tag and publishes the GitHub Release.
+
+> release-please never pushes to `main` directly — only through a Release PR, so a
+> protected `main` keeps working.
+
+**One-time repository setup** (so the action can open PRs): Settings → Actions →
+General → Workflow permissions → enable *Read and write permissions* and *Allow
+GitHub Actions to create and approve pull requests*.
+
+---
+
+## 7. What backs this in the repo
+
+| File | What it does |
+|------|--------------|
+| [.pre-commit-config.yaml](../.pre-commit-config.yaml) | ruff + ruff-format + commitizen on every `git commit` |
+| [pyproject.toml](../pyproject.toml) (`[tool.commitizen]`) | Commit-message validation config |
+| [.github/workflows/python-app.yml](../.github/workflows/python-app.yml) | CI on every PR: pre-commit + pytest |
+| [.github/workflows/release-please.yml](../.github/workflows/release-please.yml) | Releases: Release PR → tag + GitHub Release |
+| [release-please-config.json](../release-please-config.json) | Release type, version files, bump rules and `changelog-sections` |
+| [.release-please-manifest.json](../.release-please-manifest.json) | Current released version (release-please state) |
+| [CHANGELOG.md](../CHANGELOG.md) | Auto-generated by release-please. **Do not** edit by hand. |
+
+---
+
+## TL;DR
+
+1. Commit messages follow Conventional Commits, otherwise the commit is rejected.
+2. Each task is a short `feat/...` branch, landed via a **squash PR** into `main`.
+3. `main` always has green CI and is always releasable.
+4. A release = merging the Release PR driven by release-please. Versions, tags,
+ and the CHANGELOG are generated from commit history — nobody writes them by hand.
diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md
index 420e618..c989e6e 100644
--- a/docs/WORKFLOW.md
+++ b/docs/WORKFLOW.md
@@ -1,5 +1,7 @@
# Workflow: как это всё работает
+> 🌐 **Языки:** Русский (текущий) · [English](WORKFLOW.en.md)
+
Документ описывает полный цикл — от первого `git commit` до GitHub Release — и
как организовать работу через feature-ветки.
@@ -21,7 +23,7 @@ flowchart TD
E --> F[git push в feature-ветку]
F --> G[Pull Request на GitHub]
G --> H[CI: python-app.yml pre-commit + pytest]
- H -- зелёный --> I[Merge в main]
+ H -- зелёный --> I[Squash-merge в main заголовок PR = коммит]
I --> J[CI: release-please.yml]
J --> K[release-please открывает/ обновляет Release PR]
K -- merge Release PR --> L[Tag vX.Y.Z + GitHub Release + CHANGELOG.md]
@@ -49,18 +51,23 @@ flowchart TD
`type` обязателен, остальное опционально. `!` после типа/скоупа означает
breaking change.
-| Type | Когда использовать | Попадает в CHANGELOG как |
-|------------|--------------------------------------------------|--------------------------|
-| `feat` | Новая функциональность | **Features** |
-| `fix` | Исправление бага | **Bug Fixes** |
-| `perf` | Улучшение производительности | **Performance** |
-| `refactor` | Рефакторинг без изменения поведения | (скрыто по умолчанию) |
-| `docs` | Только документация | **Documentation** |
-| `test` | Добавление/правка тестов | (скрыто по умолчанию) |
-| `build` | Сборка, зависимости (pyproject.toml, poetry.lock)| **Build System** |
-| `ci` | GitHub Actions, pre-commit | (скрыто по умолчанию) |
-| `chore` | Рутина, без влияния на код | (скрыто по умолчанию) |
-| `revert` | Откат прошлого коммита | **Reverts** |
+| Type | Когда использовать | В CHANGELOG / релиз |
+|------------|--------------------------------------------------|-------------------------------|
+| `feat` | Новая функциональность | **Features** · minor |
+| `fix` | Исправление бага | **Bug Fixes** · patch |
+| `perf` | Улучшение производительности | **Performance** · patch |
+| `revert` | Откат прошлого коммита | **Reverts** · patch |
+| `docs` | Только документация | скрыто, без релиза |
+| `refactor` | Рефакторинг без изменения поведения | скрыто, без релиза |
+| `test` | Добавление/правка тестов | скрыто, без релиза |
+| `build` | Сборка, зависимости (pyproject.toml, poetry.lock)| скрыто, без релиза |
+| `ci` | GitHub Actions, pre-commit | скрыто, без релиза |
+| `style` | Форматирование, без изменения логики | скрыто, без релиза |
+| `chore` | Рутина, без влияния на код | скрыто, без релиза |
+
+> Какие типы попадают в CHANGELOG и триггерят релиз, задаётся `changelog-sections`
+> в [release-please-config.json](../release-please-config.json). Сейчас релиз
+> выпускается только на `feat` / `fix` / `perf` / `revert`; остальное скрыто.
**Примеры:**
@@ -144,21 +151,24 @@ gitGraph
commit id: "feat: routing"
commit id: "test: cover routing"
checkout main
- merge feat/conditional-steps tag: "PR #12"
+ merge feat/conditional-steps tag: "squash PR #12"
commit id: "chore(main): release 0.2.0" tag: "v0.2.0"
```
- Одна долгоживущая ветка: `main`, всегда зелёная и релизуемая.
- Любая работа — короткая feature-ветка `feat/...`, `fix/...`, `chore/...`.
-- Merge через PR с зелёным CI.
+- **Squash-merge** через PR с зелёным CI: атомарные коммиты остаются в PR, а на
+ `main` ложится один коммит с заголовком PR — поэтому история линейная, а
+ changelog чистый (одна запись на PR).
- Релиз делает release-please через отдельный Release PR (см. §6).
### Несколько правил
1. **Маленькие PR.** Лучше три PR по 200 строк, чем один на 600.
2. **Одна тема на ветку.** Не смешивай рефакторинг с фичей.
-3. **Имена веток:** `feat/<кратко>`, `fix/<кратко>`, `chore/<кратко>`.
-4. **Защити main.** Settings → Branches: require PR, require CI green.
+3. **Заголовок PR — валидный Conventional Commit.** При squash он становится
+ коммитом на `main` и попадает в changelog.
+4. **Имена веток:** `feat/<кратко>`, `fix/<кратко>`, `chore/<кратко>`.
5. **Никогда не push --force в main.** В свою feature-ветку — можно после
rebase, через `--force-with-lease`.
@@ -174,17 +184,17 @@ git pull --ff-only
# 2. Новая ветка
git switch -c feat/conditional-steps
-# 3. Работа + атомарные коммиты
+# 3. Работа + атомарные коммиты (живут в PR)
git add dialog_engine/
git commit -m "feat(engine): add conditional step routing"
git commit -m "test(engine): cover conditional routing"
-# 4. Пуш и PR
+# 4. Пуш и PR (заголовок PR = будущий squash-коммит)
git push -u origin feat/conditional-steps
gh pr create --title "feat(engine): conditional step routing" --body "Closes #42"
-# 5. После зелёного CI — merge, удалить ветку
-gh pr merge --merge --delete-branch
+# 5. После зелёного CI — squash-merge, удалить ветку
+gh pr merge --squash --delete-branch
# 6. Уборка
git switch main && git pull --ff-only
@@ -192,7 +202,7 @@ git switch main && git pull --ff-only
### Rebase или merge?
-Правило: **rebase для своих веток, merge для общих**. После rebase —
+Правило: **rebase для своих веток, squash для вливания в `main`**. После rebase —
`git push --force-with-lease` (безопаснее `--force`).
---
@@ -247,7 +257,7 @@ requests*.
| [pyproject.toml](../pyproject.toml) (`[tool.commitizen]`) | Конфиг валидации формата коммитов |
| [.github/workflows/python-app.yml](../.github/workflows/python-app.yml) | CI на каждый PR: pre-commit + pytest |
| [.github/workflows/release-please.yml](../.github/workflows/release-please.yml) | Релизы: Release PR → тег + GitHub Release |
-| [release-please-config.json](../release-please-config.json) | Тип релиза, файлы с версией, правила bump |
+| [release-please-config.json](../release-please-config.json) | Тип релиза, файлы с версией, правила bump и `changelog-sections` |
| [.release-please-manifest.json](../.release-please-manifest.json) | Текущая выпущенная версия (состояние release-please) |
| [CHANGELOG.md](../CHANGELOG.md) | Авто-генерируется release-please. Руками **не редактировать**. |
@@ -256,7 +266,7 @@ requests*.
## TL;DR
1. Commit-сообщения — по Conventional Commits, иначе коммит не пройдёт.
-2. Каждая задача — короткая ветка `feat/...`, через PR в `main`.
+2. Каждая задача — короткая ветка `feat/...`, через **squash-PR** в `main`.
3. На `main` всегда зелёный CI и всегда релизуемо.
4. Релиз = смержить Release PR, который ведёт release-please. Версии, теги и
CHANGELOG генерируются из истории коммитов — руками их никто не пишет.