diff --git a/docs/work-items/ORCH-017/01-brd.md b/docs/work-items/ORCH-017/01-brd.md
new file mode 100644
index 0000000..f4e1f2d
--- /dev/null
+++ b/docs/work-items/ORCH-017/01-brd.md
@@ -0,0 +1,91 @@
+# 01-BRD — ORCH-017: Прямые ссылки на BRD и Plane-таску в Telegram-уведомлении об апруве
+
+Work Item: **ORCH-017**
+Repo: `orchestrator` · Branch: `feature/ORCH-017-brd-plane-telegram`
+Тип: косметическая правка (UX уведомлений). Парная с ORCH-016.
+
+## 1. Бизнес-контекст и проблема
+Когда оркестратор завершает стадию `analysis` и просит подтвердить BRD, в Telegram уходит
+отдельное «пингующее» уведомление (`notify_approve_requested` в `src/notifications.py`).
+Сейчас в этом сообщении **нет ссылок**: владелец (Слава) вынужден вручную зайти в Plane,
+найти нужную issue, открыть комментарий аналитика, оттуда перейти к BRD-документу. Это
+лишние ручные шаги на каждой задаче.
+
+Текущий текст уведомления:
+> 📋 {WI}: BRD/ТЗ/AC готовы. Переведите задачу в статус Approved в Plane для продолжения.
+
+## 2. Цель
+В **этом же** уведомлении дать две прямые кликабельные ссылки, чтобы весь сценарий
+прохождения апрува выполнялся из Telegram, без ручной навигации в Plane:
+1. **Ссылка на BRD** — открывает `01-brd.md` в Gitea (прочитать документ).
+2. **Ссылка на Plane-issue** — открывает задачу в Plane (перевести в Approved / отклонить с комментом).
+
+## 3. Целевой сценарий (Слава)
+Получил уведомление → кликнул «📄 BRD» → прочитал → кликнул «✅ Задача» → перевёл в
+Approved (или отклонил с комментарием). Всё из Telegram.
+
+## 4. Объём (Scope)
+### В объёме (выбранный по умолчанию минимальный вариант — см. §8 открытые вопросы)
+- Доработка **только** функции `notify_approve_requested(task_id)` в `src/notifications.py`
+ (стадия `analysis`, запрос статуса Approved).
+- Формирование двух ссылок и встраивание их в текст того же отдельного уведомления.
+- Формат — HTML-ссылки в тексте (`label`), т.к. `send_telegram` уже шлёт
+ `parse_mode="HTML"`. Альтернатива (inline-кнопки) — открытый вопрос §8.
+- Новая конфиг-настройка для внешнего web-URL Plane (см. §6, риск №1).
+- Обновление документации (`CLAUDE.md` env-карта при необходимости, `CHANGELOG.md`,
+ `.env.example`) в том же PR.
+
+### Вне объёма (НЕ трогать)
+- Логика апрува: `:approved:`-handler, `check_analysis_approved`, переходы стадий.
+- Живой Telegram-трекер (`update_task_tracker` / `render_task_tracker`, PR #21/#22) — его
+ текст и поведение не меняем; новое уведомление остаётся ОТДЕЛЬНЫМ сообщением, дубли
+ трекера не создаём.
+- Содержимое комментариев в Plane (это смежная задача ORCH-016).
+- Ссылки в других уведомлениях (deploy-failed, agent-failed, error) — вне объёма по
+ умолчанию (см. открытый вопрос §8.2).
+
+## 5. Заинтересованные стороны
+- **Owner / получатель уведомления:** Слава.
+- **Поставщик данных:** оркестратор (БД `tasks`: repo, branch, work_item_id, plane_issue_id).
+
+## 6. Функциональные требования
+| # | Требование |
+|---|------------|
+| FR-1 | Уведомление об апруве BRD содержит кликабельную ссылку на документ `docs/work-items//01-brd.md` в Gitea. |
+| FR-2 | То же уведомление содержит кликабельную ссылку на соответствующую Plane-issue. |
+| FR-3 | Существующий текст-призыв («Переведите задачу в статус Approved …») сохраняется. |
+| FR-4 | Уведомление остаётся ОДНИМ отдельным пингующим сообщением (без дублей, без второго сообщения). |
+| FR-5 | Ссылка на BRD строится на внешнем `gitea_public_url` (фоллбэк `gitea_url`), формат branch-view: `{base}/{owner}/{repo}/src/branch/{branch}/docs/work-items/{WI}/01-brd.md`. Переиспользовать существующий паттерн из `src/usage.py`. |
+| FR-6 | Ссылка на Plane-issue строится на внешнем web-URL Plane + workspace + project + issue. |
+
+## 7. Нефункциональные требования
+| # | Требование |
+|---|------------|
+| NFR-1 | **Никогда не ронять оркестратор** из-за уведомления: построение ссылок обёрнуто в защиту, при отсутствии данных (нет branch / нет plane_issue_id / не задан web-URL) — сообщение всё равно отправляется, просто без соответствующей ссылки (graceful degradation). |
+| NFR-2 | Не нарушать self-hosting: правка не требует рестарта прод-контейнера сверх обычного деплоя; не меняет реестр гейтов/стадий. |
+| NFR-3 | Сохранить `parse_mode="HTML"`; экранировать динамические подписи (`html.escape`), URL формировать из доверенных конфиг-значений. |
+
+## 8. Открытые вопросы (требуют решения Owner; в документах принят безопасный дефолт)
+1. **Формат ссылок.** Дефолт BRD: HTML-ссылки в тексте (минимальная правка). Альтернатива —
+ inline-кнопки «📄 Открыть BRD» / «✅ К задаче в Plane», что требует доработки `send_telegram`
+ (параметр `reply_markup`/`inline_keyboard`). → решение к стадии architecture.
+2. **Охват.** Дефолт: только BRD-апрув (`notify_approve_requested`). Альтернатива — все точки,
+ требующие решения Славы (напр. согласование макета ORCH-14). → если «все точки», объём
+ расширяется, нужен отдельный перечень событий.
+3. **Внешний web-URL Plane.** В конфиге сейчас только внутренний `plane_api_url`
+ (`http://localhost:8091`) — он НЕ годится для браузерной ссылки. Дефолт: завести новую
+ env-настройку `ORCH_PLANE_WEB_URL` (внешний адрес Plane) с фоллбэком на `plane_api_url`.
+ Точное значение URL должен подтвердить Owner/INFRA.
+4. **Формат Plane-ссылки.** `…/{workspace}/projects/{project_id}/issues/{issue_id}/` (надёжно,
+ issue_id есть в `tasks.plane_issue_id`) vs короткий `…/{workspace}/browse//`
+ (зависит от соответствия `work_item_id` ↔ Plane identifier, что не гарантировано из-за
+ zero-padding ORCH-017 vs ORCH-17). → решение к стадии architecture.
+
+## 9. Зависимости и связки
+- **PR #14** — `gitea_public_url`: переиспользуем для кликабельных ссылок на доки.
+- **PR #21/#22** — живой Telegram-трекер: новое сообщение остаётся отдельным, трекер не трогаем.
+- **ORCH-016** — единые коммент-артефакты в Plane (парная задача про навигацию к документам).
+
+## 10. Критерий бизнес-успеха
+Слава из одного Telegram-уведомления одним кликом открывает BRD и одним кликом — задачу в
+Plane, не заходя в Plane вручную и не ища комментарий.
diff --git a/docs/work-items/ORCH-017/02-trz.md b/docs/work-items/ORCH-017/02-trz.md
new file mode 100644
index 0000000..eac7f8d
--- /dev/null
+++ b/docs/work-items/ORCH-017/02-trz.md
@@ -0,0 +1,87 @@
+# 02-ТЗ — ORCH-017: Прямые ссылки в Telegram-уведомлении об апруве BRD
+
+Work Item: **ORCH-017** · Repo: `orchestrator`
+Опирается на 01-brd.md. Уточняет конкретные изменения кода/конфигурации.
+
+> Примечание по канону: ТЗ фиксирует ТРЕБОВАНИЯ к изменениям, а не готовое
+> архитектурное решение. Выбор формата (текст vs inline-кнопки) и точного формата
+> Plane-URL — за стадией architecture (см. открытые вопросы 01-brd.md §8). Если по
+> ходу разработки ТЗ окажется неполным/неверным — возврат на стадию Анализ, без
+> правок ТЗ задним числом.
+
+## 1. Задействованные модули `src/`
+| Модуль | Роль в задаче |
+|--------|---------------|
+| `src/notifications.py` | **Основной.** Функция `notify_approve_requested(task_id)` (≈ строки 547–566) — единственная точка отправки пингующего уведомления об апруве BRD. Сюда добавляются ссылки. |
+| `src/config.py` | Класс `Settings`. Добавить настройку внешнего web-URL Plane (`plane_web_url`, env `ORCH_PLANE_WEB_URL`) с дефолтом-фоллбэком. |
+| `src/projects.py` | (Чтение) `get_project_by_repo(repo)` → `plane_project_id` для построения Plane-URL. |
+| `src/usage.py` | (Референс, не править) Эталонный паттерн branch-view ссылки на доки (`{base}/{owner}/{repo}/src/branch/{branch}/`), строки ≈483–503 — переиспользовать тот же формат. |
+| `src/db.py` | (Чтение) Таблица `tasks`: поля `work_item_id`, `repo`, `branch`, `plane_issue_id`. Источник данных для ссылок. |
+
+## 2. Источники данных (из `tasks` по `task_id`)
+- `work_item_id` — путь к BRD-документу и (опц.) идентификатор issue.
+- `repo`, `branch` — построение Gitea branch-view URL.
+- `plane_issue_id` — uuid issue в Plane для прямой ссылки.
+- `project_id` — через `projects.get_project_by_repo(repo).plane_project_id`.
+
+`notify_approve_requested` сейчас принимает только `task_id` и тянет лишь `work_item_id`
+через `_get_work_item_id`. Требуется дополнительно прочитать `repo`, `branch`,
+`plane_issue_id` из `tasks` (один SELECT, в защищённом try/except).
+
+## 3. Требуемые изменения
+
+### 3.1 `src/notifications.py`
+- Построить **BRD-ссылку** (FR-1/FR-5):
+ `{base}/{owner}/{repo}/src/branch/{branch}/docs/work-items/{work_item_id}/01-brd.md`,
+ где `base = (settings.gitea_public_url or settings.gitea_url).rstrip('/')`,
+ `owner = settings.gitea_owner`. Если нет `base`/`repo`/`branch`/`work_item_id` — ссылку
+ опустить (NFR-1).
+- Построить **Plane-ссылку** (FR-2/FR-6):
+ `{plane_web_base}/{workspace_slug}/projects/{project_id}/issues/{plane_issue_id}/`
+ (точный формат — решение architecture, см. 01-brd §8.4). Если нет данных — опустить.
+- Встроить обе ссылки в текст того же сообщения (FR-3/FR-4), формат HTML-`` по умолчанию.
+ Сохранить существующий призыв «Переведите задачу в статус Approved …».
+- Сохранить вызов как **одно** `send_telegram(msg)` (пингующее, не silent). Порядок
+ существующих действий не менять: старт BRD-часов (`mark_brd_review_started`) →
+ `update_task_tracker(task_id)` → `send_telegram(msg)`.
+- Динамические подписи экранировать `html.escape` (NFR-3).
+
+### 3.2 `src/config.py`
+- Добавить в `Settings` поле `plane_web_url: str = ""` (env `ORCH_PLANE_WEB_URL`).
+- Семантика фоллбэка: `plane_web_base = (settings.plane_web_url or settings.plane_api_url).rstrip('/')`.
+
+### 3.3 Опционально (если выбран вариант inline-кнопок — открытый вопрос 01-brd §8.1)
+- Расширить `send_telegram(text, disable_notification=False, reply_markup=None)`:
+ при наличии `reply_markup` прокидывать его в payload `sendMessage`. Обратная
+ совместимость — обязательна (текущие вызовы без аргумента работают как раньше).
+- ⚠️ Это РАСШИРЯЕТ объём; включается только по явному решению Owner на стадии architecture.
+
+## 4. Изменения API
+Нет. Публичные HTTP-эндпоинты (`/webhook/*`, `/status`, `/queue`, `/health`) не затрагиваются.
+
+## 5. Изменения схемы БД
+Нет. Все нужные поля (`repo`, `branch`, `work_item_id`, `plane_issue_id`) уже существуют в `tasks`.
+
+## 6. Изменения конфигурации / окружения
+- Новая env-переменная `ORCH_PLANE_WEB_URL` (внешний web-адрес Plane). Прописать в
+ `.env.example` (канон секретов/настроек), описать в env-карте (`CLAUDE.md` /
+ `docs/operations/INFRA.md`). Реальное значение задаётся в `.env`/`.env.staging` на хосте.
+- Существующие `ORCH_GITEA_PUBLIC_URL`, `ORCH_GITEA_OWNER`, `ORCH_PLANE_WORKSPACE_SLUG`
+ переиспользуются как есть.
+
+## 7. Требования к новым QG checks
+Нет. Реестр `QG_CHECKS`, стадии и машинные вердикты не меняются (правка — отображение,
+не управление конвейером).
+
+## 8. Артефакты pipeline, которые должны быть обновлены в ЭТОМ PR
+- `CHANGELOG.md` — запись о фиче.
+- `.env.example` — новая `ORCH_PLANE_WEB_URL`.
+- При добавлении настройки — env-карта в `CLAUDE.md` / `docs/operations/INFRA.md`.
+- ADR (стадия architecture): `docs/work-items/ORCH-017/06-adr/ADR-001-*.md` — фиксирует выбор
+ формата (текст vs кнопки) и формат Plane-URL.
+
+## 9. Ограничения
+- Не трогать `:approved:`-handler и `check_analysis_approved` (только текст/формат уведомления).
+- Не плодить сообщения: одно отдельное пингующее сообщение; живой трекер (PR #21/#22) не дублировать.
+- Соблюдать self-hosting: не ронять/не рестартить прод сверх штатного деплоя; обязательная
+ страховка `deploy-staging` (8501) перед прод-деплоем орка.
diff --git a/docs/work-items/ORCH-017/03-acceptance-criteria.md b/docs/work-items/ORCH-017/03-acceptance-criteria.md
new file mode 100644
index 0000000..d26d3f2
--- /dev/null
+++ b/docs/work-items/ORCH-017/03-acceptance-criteria.md
@@ -0,0 +1,64 @@
+# 03-Acceptance Criteria — ORCH-017
+
+Work Item: **ORCH-017** · Repo: `orchestrator`
+Каждый критерий формулирует условие PASS/FAIL. Источник — 01-brd.md / 02-trz.md.
+
+## AC-1 — Ссылка на BRD присутствует в уведомлении
+- **PASS:** Текст, сформированный `notify_approve_requested`, содержит кликабельную ссылку
+ на `docs/work-items//01-brd.md` вида
+ `{gitea_public_url|gitea_url}/{owner}/{repo}/src/branch/{branch}/docs/work-items/{WI}/01-brd.md`.
+- **FAIL:** Ссылки на BRD нет, либо она ведёт не на `01-brd.md`/не на нужный WI.
+
+## AC-2 — Ссылка на Plane-issue присутствует в уведомлении
+- **PASS:** Тот же текст содержит кликабельную ссылку на issue в Plane, построенную на
+ внешнем web-URL Plane + workspace + project + `plane_issue_id` (или согласованный браузер-формат).
+- **FAIL:** Ссылки на issue нет, либо она указывает на внутренний `localhost`/неверную issue.
+
+## AC-3 — Базовый URL берётся из внешних настроек
+- **PASS:** BRD-ссылка использует `gitea_public_url`, при его пустоте — `gitea_url`; Plane-ссылка
+ использует `plane_web_url` (env `ORCH_PLANE_WEB_URL`), при пустоте — `plane_api_url`.
+- **FAIL:** Захардкожен хост, либо ссылка нерабочая снаружи деплой-хоста.
+
+## AC-4 — Существующий призыв сохранён
+- **PASS:** Текст по-прежнему содержит призыв перевести задачу в статус Approved (смысл строки
+ «Переведите задачу в статус Approved … для продолжения» сохранён).
+- **FAIL:** Призыв удалён/искажён.
+
+## AC-5 — Одно отдельное пингующее сообщение, без дублей
+- **PASS:** `notify_approve_requested` отправляет ровно одно сообщение через `send_telegram`
+ (пингующее, не silent). Живой трекер (`update_task_tracker`) обновляется как раньше и не
+ дублируется новым сообщением.
+- **FAIL:** Появляется второе/дубль-сообщение, либо трекер шлётся повторно как новое сообщение.
+
+## AC-6 — Graceful degradation (никогда не ронять оркестратор)
+- **PASS:** При отсутствии `branch` / `plane_issue_id` / незаданном Plane web-URL функция НЕ
+ бросает исключение: уведомление уходит с доступными ссылками (или без отсутствующей), орк жив.
+- **FAIL:** Отсутствие данных приводит к исключению/падению потока уведомлений.
+
+## AC-7 — HTML-безопасность
+- **PASS:** Сохранён `parse_mode="HTML"`; динамические подписи экранируются (`html.escape`),
+ URL валиден и не ломает разметку сообщения.
+- **FAIL:** Сообщение приходит с битой HTML-разметкой или с неэкранированным пользовательским текстом.
+
+## AC-8 — Логика апрува не затронута
+- **PASS:** `:approved:`-handler, `check_analysis_approved`, переходы стадий и реестр `QG_CHECKS`
+ без изменений; правка касается только текста/формата уведомления.
+- **FAIL:** Изменена логика гейта/перехода стадий.
+
+## AC-9 — Документация обновлена в том же PR
+- **PASS:** Обновлены `CHANGELOG.md` и `.env.example` (новая `ORCH_PLANE_WEB_URL`); если добавлена
+ настройка — отражено в env-карте (`CLAUDE.md`/`docs/operations/INFRA.md`); заведён ADR на
+ выбранный формат. (Reviewer проверяет доку → нет обновления = REQUEST_CHANGES.)
+- **FAIL:** Код изменён, документация — нет.
+
+## AC-10 — Тесты зелёные
+- **PASS:** Новые/затронутые тесты (`tests/test_notify_approve_links.py` и существующие
+ `tests/test_telegram_tracker.py`, `tests/test_notify_done_regression.py`) проходят; `pytest tests/ -q` зелёный.
+- **FAIL:** Любой связанный тест падает.
+
+---
+### Зависит от решений Owner (open questions 01-brd §8)
+- Если выбран вариант **inline-кнопок** — AC-1/AC-2 считаются выполненными при наличии кнопок
+ «📄 Открыть BRD» / «✅ К задаче в Plane» с теми же URL; дополнительно AC: обратная совместимость
+ `send_telegram` (старые вызовы без `reply_markup` работают).
+- Если охват расширен до **всех точек решения** — AC-1/AC-2 проверяются для каждой такой точки.
diff --git a/docs/work-items/ORCH-017/04-test-plan.yaml b/docs/work-items/ORCH-017/04-test-plan.yaml
new file mode 100644
index 0000000..ab66a42
--- /dev/null
+++ b/docs/work-items/ORCH-017/04-test-plan.yaml
@@ -0,0 +1,99 @@
+work_item: ORCH-017
+title: "Прямые ссылки на BRD и Plane-таску в Telegram-уведомлении об апруве"
+notes: >
+ Тесты изолируют сеть: send_telegram/httpx мокируются, проверяется СФОРМИРОВАННЫЙ текст
+ (и/или reply_markup, если выбран вариант кнопок), а не реальная отправка. БД tasks
+ наполняется фикстурой (work_item_id, repo, branch, plane_issue_id). Маппинг на критерии — в поле acceptance.
+
+tests:
+ - id: TC-01
+ type: unit
+ description: "notify_approve_requested формирует текст с кликабельной ссылкой на 01-brd.md (Gitea branch-view)"
+ module: tests/test_notify_approve_links.py
+ setup: "task в tasks с work_item_id=ORCH-017, repo=orchestrator, branch=feature/ORCH-017-..., gitea_public_url задан; send_telegram замокан"
+ expected: PASS
+ acceptance: [AC-1, AC-3]
+
+ - id: TC-02
+ type: unit
+ description: "Текст содержит ссылку на Plane-issue с внешним web-URL + workspace + project + plane_issue_id"
+ module: tests/test_notify_approve_links.py
+ setup: "plane_web_url(ORCH_PLANE_WEB_URL) и workspace заданы; project резолвится по repo; plane_issue_id в tasks"
+ expected: PASS
+ acceptance: [AC-2, AC-3]
+
+ - id: TC-03
+ type: unit
+ description: "При пустом gitea_public_url BRD-ссылка строится на gitea_url (фоллбэк); при пустом plane_web_url — на plane_api_url"
+ module: tests/test_notify_approve_links.py
+ expected: PASS
+ acceptance: [AC-3]
+
+ - id: TC-04
+ type: unit
+ description: "Сохранён призыв перевести задачу в статус Approved (подстрока 'Approved' присутствует)"
+ module: tests/test_notify_approve_links.py
+ expected: PASS
+ acceptance: [AC-4]
+
+ - id: TC-05
+ type: unit
+ description: "send_telegram вызван ровно один раз (пингующее сообщение), без disable_notification=True"
+ module: tests/test_notify_approve_links.py
+ setup: "mock send_telegram, assert call_count == 1 и аргумент disable_notification не True"
+ expected: PASS
+ acceptance: [AC-5]
+
+ - id: TC-06
+ type: unit
+ description: "Graceful: branch=None / plane_issue_id=None — функция не бросает исключение, сообщение всё равно отправляется"
+ module: tests/test_notify_approve_links.py
+ setup: "task без branch и без plane_issue_id; убедиться что send_telegram всё равно вызван, отсутствующая ссылка опущена"
+ expected: PASS
+ acceptance: [AC-6]
+
+ - id: TC-07
+ type: unit
+ description: "Plane web-URL не задан и plane_api_url пуст — Plane-ссылка опускается, BRD-ссылка остаётся, орк не падает"
+ module: tests/test_notify_approve_links.py
+ expected: PASS
+ acceptance: [AC-6]
+
+ - id: TC-08
+ type: unit
+ description: "Сохранён parse_mode=HTML; динамические подписи экранированы, HTML-разметка ссылок валидна"
+ module: tests/test_notify_approve_links.py
+ expected: PASS
+ acceptance: [AC-7]
+
+ - id: TC-09
+ type: unit
+ description: "Регрессия трекера: update_task_tracker по-прежнему работает (silent edit), новое сообщение его не дублирует"
+ module: tests/test_telegram_tracker.py
+ expected: PASS
+ acceptance: [AC-5, AC-8]
+
+ - id: TC-10
+ type: integration
+ description: "Поток analysis-approved: _handle_analysis_approved_flow при готовых артефактах вызывает notify_approve_requested; БД tasks даёт корректные repo/branch/plane_issue_id для ссылок"
+ module: tests/test_analysis_approve_flow_links.py
+ setup: "замокать сетевые вызовы Plane/Gitea/Telegram; убедиться, что check_analysis_approved/переходы стадий не изменены"
+ expected: PASS
+ acceptance: [AC-1, AC-2, AC-8]
+
+ # Условные тесты — включаются ТОЛЬКО если Owner выбрал вариант inline-кнопок (01-brd §8.1)
+ - id: TC-11
+ type: unit
+ description: "(Условный) Вариант кнопок: payload содержит reply_markup.inline_keyboard с кнопками '📄 Открыть BRD' и '✅ К задаче в Plane' с верными url"
+ module: tests/test_notify_approve_links.py
+ expected: PASS
+ condition: "only if inline-buttons variant chosen"
+ acceptance: [AC-1, AC-2]
+
+ - id: TC-12
+ type: unit
+ description: "(Условный) Обратная совместимость send_telegram: вызовы без reply_markup работают как раньше (payload без поля reply_markup)"
+ module: tests/test_telegram_tracker.py
+ expected: PASS
+ condition: "only if inline-buttons variant chosen"
+ acceptance: [AC-5]