From 06caeaa8d9436ae32692614f8ea0a7572cd2824d Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:12:52 +0300 Subject: [PATCH 01/20] feat(i18n): add Ukrainian localization infrastructure - uk/README.md: Ukrainian landing page with module index - uk/TRANSLATION_NOTES.md: glossary and style guide - uk/TRANSLATION_QUEUE.md: progress tracker (0/67 files) - Directory structure for all 10 modules Ref: luongnv89/claude-howto#63 --- uk/README.md | 79 +++++++++++ uk/TRANSLATION_NOTES.md | 286 ++++++++++++++++++++++++++++++++++++++++ uk/TRANSLATION_QUEUE.md | 113 ++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 uk/README.md create mode 100644 uk/TRANSLATION_NOTES.md create mode 100644 uk/TRANSLATION_QUEUE.md diff --git a/uk/README.md b/uk/README.md new file mode 100644 index 0000000..c622b73 --- /dev/null +++ b/uk/README.md @@ -0,0 +1,79 @@ + + + + +# Посібник Claude Code + +🌐 **Language / Мова:** [English](../README.md) | [Tiếng Việt](../vi/README.md) | [中文](../zh/README.md) | [Українська](README.md) + +> **Опануй Claude Code за вихідні** + +Це українська версія документації [Claude Code How-To Guide](../README.md). + +## 📖 Про що це + +Цей посібник допоможе вам: + +- Зрозуміти та ефективно використовувати Claude Code +- Автоматизувати завдання з розробки програмного забезпечення +- Інтегрувати Claude Code у ваш щоденний робочий процес + +## 🚀 Швидкий старт + +### Вимоги + +- Встановлений Claude Code +- Базові знання роботи з терміналом +- Базові знання програмування + +### Встановлення + +```bash +# Клонувати репозиторій +git clone https://github.com/luongnv89/claude-howto.git +cd claude-howto + +# Скопіювати слеш-команди до вашого проекту +mkdir -p .claude/commands +cp 01-slash-commands/*.md .claude/commands/ +``` + +## 📚 Структура документації + +Документація поділена на 10 модулів у порядку вивчення: + +1. **[01 — Слеш-команди](01-slash-commands/)** — Ярлики для підвищення продуктивності +2. **[02 — Пам'ять](02-memory/)** — Збереження контексту між сесіями +3. **[03 — Навички (Skills)](03-skills/)** — Багаторазові можливості +4. **[04 — Субагенти](04-subagents/)** — Спеціалізовані AI-помічники +5. **[05 — MCP](05-mcp/)** — Model Context Protocol +6. **[06 — Хуки](06-hooks/)** — Автоматизація на основі подій +7. **[07 — Плагіни](07-plugins/)** — Пакетні розширення +8. **[08 — Контрольні точки](08-checkpoints/)** — Знімки сесій +9. **[09 — Розширені функції](09-advanced-features/)** — Планування, мислення, фонові завдання +10. **[10 — CLI](10-cli/)** — Довідник командного рядка + +## 🔗 Посилання + +- [Англійська версія](../README.md) +- [Офіційна документація Claude Code](https://code.claude.com/docs) +- [GitHub-репозиторій](https://github.com/luongnv89/claude-howto) + +## 🤝 Як долучитися + +Див. [CONTRIBUTING.md](../CONTRIBUTING.md) для деталей. + +## 📝 Примітки до перекладу + +Див. [TRANSLATION_NOTES.md](TRANSLATION_NOTES.md) для: + +- Глосарію технічних термінів +- Правил стилю перекладу +- Правил роботи з кодом та командами + +--- + +**Переклад у процесі.** Див. [TRANSLATION_QUEUE.md](TRANSLATION_QUEUE.md) для відстеження прогресу. + +**Останнє оновлення:** 2026-04-09 +**Мова:** Українська (uk-UA) diff --git a/uk/TRANSLATION_NOTES.md b/uk/TRANSLATION_NOTES.md new file mode 100644 index 0000000..c11688f --- /dev/null +++ b/uk/TRANSLATION_NOTES.md @@ -0,0 +1,286 @@ +# Глосарій та Стайлгайд перекладу + +# Translation Glossary & Style Guide + +> **Важливо:** Цей документ визначає правила перекладу документації Claude Code українською мовою. Прочитайте перед початком роботи. + +## Технічна термінологія + +Таблиця термінів для єдності перекладу у всіх файлах: + +| English | Українська | Примітка | +|---------|-----------|----------| +| slash command | слеш-команда | "Слеш" зберігаємо — це назва фічі | +| hook | хук | Усталений термін в UA IT-спільноті | +| skill | навичка | Назва фічі Claude Code, перекладаємо | +| subagent | субагент | Або "підагент" — обидва прийнятні | +| agent | агент | Перекладаємо | +| memory | пам'ять | Перекладаємо | +| checkpoint | контрольна точка | Перекладаємо для ясності | +| plugin | плагін | Усталений термін | +| pull request / PR | pull request / PR | Зберігаємо (GitHub-термін) | +| commit | коміт | Усталена транслітерація | +| branch | гілка | Перекладаємо | +| merge | мердж | Або "злиття" — залежить від контексту | +| MCP (Model Context Protocol) | MCP | Зберігаємо (назва протоколу) | +| CLAUDE.md | CLAUDE.md | Зберігаємо (ім'я файлу) | +| prompt | промпт | Усталена транслітерація | +| workflow | воркфлов | Або "робочий процес" | +| repository | репозиторій | Скорочено "репо" | +| issue | issue | Зберігаємо (GitHub-термін) | +| release | реліз | Усталена транслітерація | +| API | API | Зберігаємо | +| CLI | CLI | Зберігаємо (Command-Line Interface) | +| CI/CD | CI/CD | Зберігаємо | +| pre-commit hook | pre-commit хук | Зберігаємо "pre-commit" як назву інструмента | +| environment variable | змінна оточення | Перекладаємо | +| dependencies | залежності | Перекладаємо | +| template | шаблон | Перекладаємо | +| worktree | робоче дерево | Git-термін, перекладаємо | +| frontmatter | фронтматер | YAML-блок на початку файлу | +| token | токен | Усталена транслітерація | +| context window | контекстне вікно | Перекладаємо | +| fork | форк | Усталена транслітерація | +| clone | клонувати | Перекладаємо дієслово | +| sandbox | пісочниця | Перекладаємо | +| boilerplate | шаблонний код | Перекладаємо | +| debugging | налагодження | Перекладаємо | +| linting | лінтинг | Транслітерація | +| refactoring | рефакторинг | Усталена транслітерація | + +## Правила перекладу + +### 1. Код та команди + +**ЗОЛОТЕ ПРАВИЛО:** Зберігаємо 100% виконуваного коду. Перекладаємо лише коментарі та пояснення. + +**Правильно (✅):** + +````markdown +Щоб запустити цю команду: + +```bash +/optimize +``` + +Ця команда проаналізує ваш код. +```` + +**Неправильно (❌):** + +````markdown +Щоб запустити цю команду: + +```bash +/оптимізувати # НІКОЛИ не перекладайте команди +``` +```` + +### 2. Коментарі в коді + +Перекладаємо коментарі українською: + +```python +# ✅ ПРАВИЛЬНО — коментар перекладено +# Ця слеш-команда оптимізує ваш код +def optimize_code(): + pass + +# ❌ НЕПРАВИЛЬНО — не перекладайте назви функцій +def оптимізувати_код(): # НЕ перекладаємо імена функцій + pass +``` + +### 3. Назви функцій, змінних та класів + +Зберігаємо англійською: + +```python +# ✅ ПРАВИЛЬНО +def create_subagent(name: str, system_prompt: str): + pass + +# ❌ НЕПРАВИЛЬНО +def створити_субагент(імя: str, системний_промпт: str): + pass +``` + +### 4. Діаграми Mermaid + +**Зберігаємо 100% без змін.** Не перекладаємо жодного тексту в блоках mermaid. + +````markdown + +```mermaid +graph TD + A[Користувач] --> B[Агент] +``` + + +```mermaid +graph TD + A[User] --> B[Agent] +``` +```` + +**Важливо:** Коментарі в Mermaid використовують `%%`, а не `#`. Символ `#` спричиняє помилку парсера. + +````markdown + +```mermaid +graph TD + %% Це коментар у Mermaid + A[User] --> B[Agent] +``` + + +```mermaid +graph TD + # Це зламає парсер! + A[User] --> B[Agent] +``` +```` + +### 5. Шляхи до файлів та URL + +Зберігаємо без змін: + +```markdown + +Див. файл `.claude/settings.json` для конфігурації. + + +Див. файл `.claude/налаштування.json` для конфігурації. +``` + +### 6. Таблиці + +Зберігаємо структуру та кількість стовпців/рядків. Перекладаємо текстовий вміст, залишаємо технічні значення: + +```markdown +| Команда | Опис | Приклад | +|---------|------|---------| +| `/help` | Показати довідку | `/help memory` | +| `/clear` | Очистити сесію | `/clear` | +``` + +### 7. Посилання між файлами + +Використовуємо відносні шляхи всередині `uk/`: + +```markdown + +[Пам'ять](../02-memory/) + + +[English version](../../README.md) + + +[`format-code.sh`](../../06-hooks/format-code.sh) +``` + +### 8. Фронтматер для трекінгу версії + +Кожен перекладений файл починається з HTML-коментарів для відстеження версії оригіналу: + +```markdown + + + + +# Заголовок перекладеного файлу +``` + +SHA — це коротка хеш-сума коміту англійського файлу, з якого робився переклад. Отримати: `git log --oneline -1 -- <шлях-до-англійського-файлу>`. + +### 9. Стиль тексту + +- Звертання до читача: **"ви"** (не "ти", не "Ви") +- Уникайте канцеляризмів: "запустіть" замість "здійсніть запуск" +- Технічні абревіатури при першому згадуванні: розшифровка + абревіатура в дужках, далі — лише абревіатура +- Числівники: до 10 — словами, від 11 — цифрами + +## DO / DON'T + +### ✅ DO: Перекладайте описовий текст + +```markdown +Слеш-команди — це ярлики, які керують поведінкою Claude під час інтерактивної сесії. +``` + +### ✅ DO: Перекладайте коментарі в коді + +```python +# ✅ ПРАВИЛЬНО +# Ця функція створює нового субагента +def create_subagent(): + pass +``` + +### ❌ DON'T: Не перекладайте назви функцій + +```python +# ❌ НЕПРАВИЛЬНО +def створити_субагент(): + pass + +# ✅ ПРАВИЛЬНО +def create_subagent(): + pass +``` + +### ❌ DON'T: Не перекладайте діаграми Mermaid + +````markdown + +```mermaid +graph TD + A[Користувач] --> B[Агент] +``` + + +```mermaid +graph TD + A[User] --> B[Agent] +``` +```` + +### ❌ DON'T: Не довіряйте машинному перекладу без перевірки + +Машинний переклад (Google Translate, DeepL) часто: + +- Неправильно перекладає технічні терміни +- Не розуміє контекст коду +- Спотворює значення команд +- Ламає Markdown-форматування + +**Завжди перевіряйте та редагуйте після машинного перекладу!** + +## Чекліст перед комітом + +- [ ] Технічна точність збережена +- [ ] Текст звучить природно українською +- [ ] Термінологія відповідає глосарію +- [ ] Код залишено без змін (100%) +- [ ] Діаграми Mermaid не змінені +- [ ] Внутрішні посилання працюють +- [ ] Зовнішні посилання збережені +- [ ] Markdown-форматування коректне +- [ ] Коментарі в коді перекладені +- [ ] Назви функцій/змінних/класів — англійською +- [ ] Шляхи до файлів та URL без змін +- [ ] Фронтматер `i18n-source-sha` додано +- [ ] Pre-commit перевірки пройдені + +## Допомога + +Якщо виникли питання під час перекладу: + +1. Перевірте цей глосарій +2. Подивіться як перекладені аналогічні файли в інших модулях +3. Створіть GitHub issue для обговорення + +--- + +**Останнє оновлення:** 2026-04-09 +**Мова:** Українська (uk-UA) diff --git a/uk/TRANSLATION_QUEUE.md b/uk/TRANSLATION_QUEUE.md new file mode 100644 index 0000000..9787084 --- /dev/null +++ b/uk/TRANSLATION_QUEUE.md @@ -0,0 +1,113 @@ + + +# Прогрес перекладу українською + +**Загальний прогрес:** 0/67 файлів (0%) + +**Статус:** 🚧 В ПРОЦЕСІ + +## Пріоритет 1 — Ядро (5 файлів) + +| Файл | Статус | Дата | Перекладач | +|------|--------|------|------------| +| README.md | ✅ Готово | 2026-04-09 | edocltd | +| INDEX.md | ⏳ Очікує | | | +| CATALOG.md | ⏳ Очікує | | | +| QUICK_REFERENCE.md | ⏳ Очікує | | | +| LEARNING-ROADMAP.md | ⏳ Очікує | | | + +**Прогрес P1:** 1/5 (20%) + +## Пріоритет 2 — Модулі README (10 файлів) + +| Модуль | Файл | Статус | Дата | +|--------|------|--------|------| +| 01 | 01-slash-commands/README.md | ⏳ Очікує | | +| 02 | 02-memory/README.md | ⏳ Очікує | | +| 03 | 03-skills/README.md | ⏳ Очікує | | +| 04 | 04-subagents/README.md | ⏳ Очікує | | +| 05 | 05-mcp/README.md | ⏳ Очікує | | +| 06 | 06-hooks/README.md | ⏳ Очікує | | +| 07 | 07-plugins/README.md | ⏳ Очікує | | +| 08 | 08-checkpoints/README.md | ⏳ Очікує | | +| 09 | 09-advanced-features/README.md | ⏳ Очікує | | +| 10 | 10-cli/README.md | ⏳ Очікує | | + +**Прогрес P2:** 0/10 (0%) + +## Пріоритет 3 — Приклади модулів (47 файлів) + +### Модуль 01 — Слеш-команди (8 файлів) + +| Файл | Статус | Дата | +|------|--------|------| +| commit.md | ⏳ | | +| doc-refactor.md | ⏳ | | +| generate-api-docs.md | ⏳ | | +| optimize.md | ⏳ | | +| pr.md | ⏳ | | +| push-all.md | ⏳ | | +| setup-ci-cd.md | ⏳ | | +| unit-test-expand.md | ⏳ | | + +### Модуль 02 — Пам'ять (3 файли) + +| Файл | Статус | Дата | +|------|--------|------| +| directory-api-CLAUDE.md | ⏳ | | +| personal-CLAUDE.md | ⏳ | | +| project-CLAUDE.md | ⏳ | | + +### Модуль 03 — Навички (6 файлів) + +| Файл | Статус | Дата | +|------|--------|------| +| blog-draft/SKILL.md | ⏳ | | +| brand-voice/SKILL.md | ⏳ | | +| brand-voice/tone-examples.md | ⏳ | | +| claude-md/SKILL.md | ⏳ | | +| code-review/SKILL.md | ⏳ | | +| doc-generator/SKILL.md | ⏳ | | +| refactor/SKILL.md | ⏳ | | + +### Модуль 04 — Субагенти (8 файлів) + +| Файл | Статус | Дата | +|------|--------|------| +| clean-code-reviewer.md | ⏳ | | +| code-reviewer.md | ⏳ | | +| data-scientist.md | ⏳ | | +| debugger.md | ⏳ | | +| documentation-writer.md | ⏳ | | +| implementation-agent.md | ⏳ | | +| performance-optimizer.md | ⏳ | | +| secure-reviewer.md | ⏳ | | +| test-engineer.md | ⏳ | | + +### Модуль 05-10 — Приклади + +Код-файли (`.sh`, `.py`, `.json`) **не копіюються** — посилаємося на оригінали. +Файли прикладів перекладаються за потреби. + +| Файл | Статус | Дата | +|------|--------|------| +| 08-checkpoints/checkpoint-examples.md | ⏳ | | +| 09-advanced-features/planning-mode-examples.md | ⏳ | | + +**Прогрес P3:** 0/47 (0%) + +## Пріоритет 4 — Допоміжні документи (5 файлів) + +| Файл | Статус | Дата | +|------|--------|------| +| CONTRIBUTING.md | ⏳ Очікує | | +| SECURITY.md | ⏳ Очікує | | +| CODE_OF_CONDUCT.md | ⏳ Очікує | | +| STYLE_GUIDE.md | ⏳ Очікує | | +| CHANGELOG.md | ⏳ Очікує | | + +**Прогрес P4:** 0/5 (0%) + +--- + +**Останнє оновлення:** 2026-04-09 From a80b980bb6a163c94df764ad5b988e63ddaedb22 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:16:35 +0300 Subject: [PATCH 02/20] feat(uk): translate INDEX.md to Ukrainian Complete Ukrainian translation of INDEX.md - the comprehensive index of all example files in the repository. Translation follows uk/TRANSLATION_NOTES.md guidelines: - Technical terms per glossary - File paths and code blocks preserved in English - Table structure and formatting maintained - All 883 lines translated - i18n-source-sha frontmatter added for version tracking Progress: 2/67 files (P1: 2/5 core documents) Ref: luongnv89/claude-howto#63 --- uk/INDEX.md | 935 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 935 insertions(+) create mode 100644 uk/INDEX.md diff --git a/uk/INDEX.md b/uk/INDEX.md new file mode 100644 index 0000000..c50b3c7 --- /dev/null +++ b/uk/INDEX.md @@ -0,0 +1,935 @@ + + + + + + + Claude How To + + +# Приклади Claude Code — Повний покажчик + +Цей документ містить повний покажчик усіх файлів-прикладів, упорядкований за типом функціональності. + +## Загальна статистика + +- **Файлів**: 100+ +- **Категорій**: 10 функціональних категорій +- **Плагінів**: 3 повних плагіни +- **Навичок (Skills)**: 6 повних навичок +- **Хуків**: 8 прикладів хуків +- **Готові до використання**: Усі приклади + +--- + +## 01. Слеш-команди (10 файлів) + +Ярлики для типових робочих процесів, які викликає користувач. + +| Файл | Опис | Сценарій використання | +|------|------|----------------------| +| `optimize.md` | Аналізатор оптимізації коду | Пошук проблем продуктивності | +| `pr.md` | Підготовка pull request | Автоматизація PR-процесу | +| `generate-api-docs.md` | Генератор API-документації | Створення документації API | +| `commit.md` | Помічник з коміт-повідомлень | Стандартизовані коміти | +| `setup-ci-cd.md` | Налаштування CI/CD-пайплайну | DevOps-автоматизація | +| `push-all.md` | Відправити всі зміни | Швидкий push | +| `unit-test-expand.md` | Розширення покриття тестами | Автоматизація тестування | +| `doc-refactor.md` | Рефакторинг документації | Покращення документації | +| `pr-slash-command.png` | Скріншот-приклад | Візуальний довідник | +| `README.md` | Документація | Керівництво з налаштування | + +**Шлях встановлення**: `.claude/commands/` + +**Використання**: `/optimize`, `/pr`, `/generate-api-docs`, `/commit`, `/setup-ci-cd`, `/push-all`, `/unit-test-expand`, `/doc-refactor` + +--- + +## 02. Пам'ять (6 файлів) + +Постійний контекст та стандарти проекту. + +| Файл | Опис | Область | Розташування | +|------|------|---------|-------------| +| `project-CLAUDE.md` | Командні стандарти проекту | Проект | `./CLAUDE.md` | +| `directory-api-CLAUDE.md` | Правила для API | Каталог | `./src/api/CLAUDE.md` | +| `personal-CLAUDE.md` | Персональні налаштування | Користувач | `~/.claude/CLAUDE.md` | +| `memory-saved.png` | Скріншот: пам'ять збережено | - | Візуальний довідник | +| `memory-ask-claude.png` | Скріншот: запит до Claude | - | Візуальний довідник | +| `README.md` | Документація | - | Довідник | + +**Встановлення**: Скопіюйте у відповідне розташування + +**Використання**: Автоматично завантажується Claude + +--- + +## 03. Навички (Skills) (28 файлів) + +Автоматично викликані можливості зі скриптами та шаблонами. + +### Навичка Code Review (5 файлів) + +``` +code-review/ +├── SKILL.md # Визначення навички +├── scripts/ +│ ├── analyze-metrics.py # Аналізатор метрик коду +│ └── compare-complexity.py # Порівняння складності +└── templates/ + ├── review-checklist.md # Чекліст ревʼю + └── finding-template.md # Шаблон знахідок +``` + +**Призначення**: Комплексне ревʼю коду з аналізом безпеки, продуктивності та якості + +**Автовиклик**: При перегляді коду + +--- + +### Навичка Brand Voice (4 файли) + +``` +brand-voice/ +├── SKILL.md # Визначення навички +├── templates/ +│ ├── email-template.txt # Формат електронного листа +│ └── social-post-template.txt # Формат соцмедіа +└── tone-examples.md # Приклади повідомлень +``` + +**Призначення**: Забезпечення єдиного стилю бренду в комунікаціях + +**Автовиклик**: При створенні маркетингових текстів + +--- + +### Навичка Documentation Generator (2 файли) + +``` +doc-generator/ +├── SKILL.md # Визначення навички +└── generate-docs.py # Python-генератор документації +``` + +**Призначення**: Генерація комплексної API-документації з вихідного коду + +**Автовиклик**: При створенні/оновленні API-документації + +--- + +### Навичка Refactor (5 файлів) + +``` +refactor/ +├── SKILL.md # Визначення навички +├── scripts/ +│ ├── analyze-complexity.py # Аналізатор складності +│ └── detect-smells.py # Детектор code smells +├── references/ +│ ├── code-smells.md # Каталог code smells +│ └── refactoring-catalog.md # Патерни рефакторингу +└── templates/ + └── refactoring-plan.md # Шаблон плану рефакторингу +``` + +**Призначення**: Систематичний рефакторинг коду з аналізом складності + +**Автовиклик**: При рефакторингу коду + +--- + +### Навичка Claude MD (1 файл) + +``` +claude-md/ +└── SKILL.md # Визначення навички +``` + +**Призначення**: Управління та оптимізація файлів CLAUDE.md + +--- + +### Навичка Blog Draft (3 файли) + +``` +blog-draft/ +├── SKILL.md # Визначення навички +└── templates/ + ├── draft-template.md # Шаблон чернетки блогу + └── outline-template.md # Шаблон плану блогу +``` + +**Призначення**: Створення чернеток блог-постів зі стандартною структурою + +**Додатково**: `README.md` — огляд навичок та керівництво з використання + +**Шлях встановлення**: `~/.claude/skills/` або `.claude/skills/` + +--- + +## 04. Субагенти (9 файлів) + +Спеціалізовані AI-помічники з налаштованими можливостями. + +| Файл | Опис | Інструменти | Сценарій | +|------|------|-------------|----------| +| `code-reviewer.md` | Аналіз якості коду | read, grep, diff, lint_runner | Комплексне ревʼю | +| `test-engineer.md` | Аналіз покриття тестами | read, write, bash, grep | Автоматизація тестування | +| `documentation-writer.md` | Створення документації | read, write, grep | Генерація документації | +| `secure-reviewer.md` | Ревʼю безпеки (лише читання) | read, grep | Аудит безпеки | +| `implementation-agent.md` | Повна реалізація | read, write, bash, grep, edit, glob | Розробка функцій | +| `debugger.md` | Спеціаліст з налагодження | read, bash, grep | Дослідження помилок | +| `data-scientist.md` | Спеціаліст з аналізу даних | read, write, bash | Робота з даними | +| `clean-code-reviewer.md` | Стандарти чистого коду | read, grep | Якість коду | +| `README.md` | Документація | - | Керівництво | + +**Шлях встановлення**: `.claude/agents/` + +**Використання**: Автоматичне делегування головним агентом + +--- + +## 05. Протокол MCP (5 файлів) + +Інтеграції із зовнішніми інструментами та API. + +| Файл | Опис | Інтеграція з | Сценарій | +|------|------|-------------|----------| +| `github-mcp.json` | Інтеграція з GitHub | GitHub API | Управління PR/issue | +| `database-mcp.json` | Запити до бази даних | PostgreSQL/MySQL | Запити до даних | +| `filesystem-mcp.json` | Файлові операції | Локальна файлова система | Управління файлами | +| `multi-mcp.json` | Кілька серверів | GitHub + DB + Slack | Комплексна інтеграція | +| `README.md` | Документація | - | Керівництво | + +**Шлях встановлення**: `.mcp.json` (рівень проекту) або `~/.claude.json` (рівень користувача) + +**Використання**: `/mcp__github__list_prs` тощо + +--- + +## 06. Хуки (9 файлів) + +Скрипти автоматизації, що виконуються при певних подіях. + +| Файл | Опис | Подія | Сценарій | +|------|------|-------|----------| +| `format-code.sh` | Автоформатування коду | PreToolUse:Write | Форматування коду | +| `pre-commit.sh` | Тести перед комітом | PreToolUse:Bash | Автоматизація тестів | +| `security-scan.sh` | Сканування безпеки | PostToolUse:Write | Перевірка безпеки | +| `log-bash.sh` | Логування bash-команд | PostToolUse:Bash | Журналювання команд | +| `validate-prompt.sh` | Валідація промптів | PreToolUse | Валідація вводу | +| `notify-team.sh` | Надсилання сповіщень | Notification | Сповіщення команди | +| `context-tracker.py` | Відстеження контекстного вікна | PostToolUse | Моніторинг контексту | +| `context-tracker-tiktoken.py` | Підрахунок токенів | PostToolUse | Точний підрахунок токенів | +| `README.md` | Документація | - | Керівництво | + +**Шлях встановлення**: Конфігурація в `~/.claude/settings.json` + +**Використання**: Налаштовуються в settings, виконуються автоматично + +**Типи хуків** (4 типи, 25 подій): + +- Хуки інструментів: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest +- Хуки сесії: SessionStart, SessionEnd, Stop, StopFailure, SubagentStart, SubagentStop +- Хуки завдань: UserPromptSubmit, TaskCompleted, TaskCreated, TeammateIdle +- Хуки життєвого циклу: ConfigChange, CwdChanged, FileChanged, PreCompact, PostCompact, WorktreeCreate, WorktreeRemove, Notification, InstructionsLoaded, Elicitation, ElicitationResult + +--- + +## 07. Плагіни (3 повних плагіни, 40 файлів) + +Пакетні набори функціональності. + +### Плагін PR Review (10 файлів) + +``` +pr-review/ +├── .claude-plugin/ +│ └── plugin.json # Маніфест плагіна +├── commands/ +│ ├── review-pr.md # Комплексне ревʼю +│ ├── check-security.md # Перевірка безпеки +│ └── check-tests.md # Перевірка покриття тестами +├── agents/ +│ ├── security-reviewer.md # Спеціаліст з безпеки +│ ├── test-checker.md # Спеціаліст з тестування +│ └── performance-analyzer.md # Спеціаліст з продуктивності +├── mcp/ +│ └── github-config.json # Інтеграція з GitHub +├── hooks/ +│ └── pre-review.js # Валідація перед ревʼю +└── README.md # Документація плагіна +``` + +**Можливості**: Аналіз безпеки, покриття тестами, вплив на продуктивність + +**Команди**: `/review-pr`, `/check-security`, `/check-tests` + +**Встановлення**: `/plugin install pr-review` + +--- + +### Плагін DevOps Automation (15 файлів) + +``` +devops-automation/ +├── .claude-plugin/ +│ └── plugin.json # Маніфест плагіна +├── commands/ +│ ├── deploy.md # Розгортання +│ ├── rollback.md # Відкат +│ ├── status.md # Статус системи +│ └── incident.md # Реагування на інциденти +├── agents/ +│ ├── deployment-specialist.md # Експерт з розгортання +│ ├── incident-commander.md # Координатор інцидентів +│ └── alert-analyzer.md # Аналізатор сповіщень +├── mcp/ +│ └── kubernetes-config.json # Інтеграція з Kubernetes +├── hooks/ +│ ├── pre-deploy.js # Перевірки перед розгортанням +│ └── post-deploy.js # Дії після розгортання +├── scripts/ +│ ├── deploy.sh # Автоматизація розгортання +│ ├── rollback.sh # Автоматизація відкату +│ └── health-check.sh # Перевірка стану +└── README.md # Документація плагіна +``` + +**Можливості**: Розгортання Kubernetes, відкат, моніторинг, реагування на інциденти + +**Команди**: `/deploy`, `/rollback`, `/status`, `/incident` + +**Встановлення**: `/plugin install devops-automation` + +--- + +### Плагін Documentation (14 файлів) + +``` +documentation/ +├── .claude-plugin/ +│ └── plugin.json # Маніфест плагіна +├── commands/ +│ ├── generate-api-docs.md # Генерація API-документації +│ ├── generate-readme.md # Створення README +│ ├── sync-docs.md # Синхронізація документації +│ └── validate-docs.md # Валідація документації +├── agents/ +│ ├── api-documenter.md # Спеціаліст з API-документації +│ ├── code-commentator.md # Спеціаліст з коментарів +│ └── example-generator.md # Генератор прикладів +├── mcp/ +│ └── github-docs-config.json # Інтеграція з GitHub +├── templates/ +│ ├── api-endpoint.md # Шаблон API-ендпоінту +│ ├── function-docs.md # Шаблон документації функцій +│ └── adr-template.md # Шаблон ADR +└── README.md # Документація плагіна +``` + +**Можливості**: API-документація, генерація README, синхронізація, валідація + +**Команди**: `/generate-api-docs`, `/generate-readme`, `/sync-docs`, `/validate-docs` + +**Встановлення**: `/plugin install documentation` + +**Додатково**: `README.md` — огляд плагінів та керівництво + +--- + +## 08. Контрольні точки та відкат (2 файли) + +Збереження стану розмови та дослідження альтернативних підходів. + +| Файл | Опис | Вміст | +|------|------|-------| +| `README.md` | Документація | Повний посібник з контрольних точок | +| `checkpoint-examples.md` | Практичні приклади | Міграція БД, оптимізація, UI-ітерації, налагодження | + +**Ключові поняття**: + +- **Контрольна точка (Checkpoint)**: Знімок стану розмови +- **Відкат (Rewind)**: Повернення до попередньої контрольної точки +- **Точка розгалуження (Branch Point)**: Дослідження кількох підходів + +**Використання**: + +``` +# Контрольні точки створюються автоматично з кожним промптом +# Для відкату натисніть Esc двічі або скористайтеся: +/rewind +# Потім оберіть: Відновити код і розмову, Відновити розмову, +# Відновити код, Підсумувати звідси, або Скасувати +``` + +**Сценарії**: + +- Спробувати різні реалізації +- Відновитися після помилок +- Безпечне експериментування +- Порівняння рішень +- A/B-тестування + +--- + +## 09. Розширені функції (3 файли) + +Просунуті можливості для складних робочих процесів. + +| Файл | Опис | Функції | +|------|------|---------| +| `README.md` | Повний посібник | Документація всіх розширених функцій | +| `config-examples.json` | Приклади конфігурації | 10+ конфігурацій для різних сценаріїв | +| `planning-mode-examples.md` | Приклади планування | REST API, міграція БД, рефакторинг | +| Заплановані завдання | Повторювані завдання з `/loop` та cron | Автоматичні повторювані процеси | +| Інтеграція з Chrome | Автоматизація браузера через headless Chromium | Веб-тестування та скрейпінг | +| Віддалене керування (розширено) | Методи підключення, безпека, порівняння | Управління віддаленими сесіями | +| Налаштування клавіатури | Кастомні клавіші, акорди, контексти | Персоналізовані ярлики | +| Десктопний застосунок (розширено) | Конектори, launch.json, Enterprise | Десктопна інтеграція | + +**Розширені функції**: + +### Режим планування (Planning Mode) + +- Створення детальних планів реалізації +- Оцінка часу та ризиків +- Систематичний розподіл завдань + +### Розширене мислення (Extended Thinking) + +- Глибокий аналіз складних проблем +- Аналіз архітектурних рішень +- Оцінка компромісів + +### Фонові завдання (Background Tasks) + +- Тривалі операції без блокування +- Паралельні робочі процеси +- Управління завданнями та моніторинг + +### Режими дозволів (Permission Modes) + +- **default**: Запитувати дозвіл на ризиковані дії +- **acceptEdits**: Автоматично приймати редагування, запитувати інше +- **plan**: Лише аналіз, без змін (тільки читання) +- **auto**: Автоматично схвалювати безпечні дії, запитувати ризиковані +- **dontAsk**: Приймати всі дії, крім ризикованих +- **bypassPermissions**: Приймати все (потребує `--dangerously-skip-permissions`) + +### Headless-режим (`claude -p`) + +- Інтеграція з CI/CD +- Автоматичне виконання завдань +- Пакетна обробка + +### Управління сесіями + +- Кілька робочих сесій +- Перемикання та збереження сесій +- Постійність сесій + +### Інтерактивні функції + +- Клавіатурні скорочення +- Історія команд +- Автодоповнення (Tab) +- Багаторядковий ввід + +### Конфігурація + +- Комплексне управління налаштуваннями +- Конфігурації для різних середовищ +- Налаштування на рівні проекту + +### Заплановані завдання + +- Повторювані завдання з командою `/loop` +- Інструменти cron: CronCreate, CronList, CronDelete +- Автоматичні повторювані процеси + +### Інтеграція з Chrome + +- Автоматизація браузера через headless Chromium +- Веб-тестування та скрейпінг +- Взаємодія зі сторінками та витяг даних + +### Віддалене керування (розширено) + +- Методи та протоколи підключення +- Безпека та найкращі практики +- Порівняльна таблиця варіантів віддаленого доступу + +### Налаштування клавіатури + +- Конфігурація кастомних клавіш +- Підтримка акордів (комбінацій клавіш) +- Контекстно-залежна активація + +### Десктопний застосунок (розширено) + +- Конектори для IDE-інтеграції +- Конфігурація launch.json +- Enterprise-функції та розгортання + +--- + +## 10. Використання CLI (1 файл) + +Патерни використання та довідник командного рядка. + +| Файл | Опис | Вміст | +|------|------|-------| +| `README.md` | Документація CLI | Прапорці, опції та патерни використання | + +**Ключові можливості CLI**: + +- `claude` — Запуск інтерактивної сесії +- `claude -p "prompt"` — Headless/неінтерактивний режим +- `claude web` — Запуск веб-сесії +- `claude --model` — Вибір моделі (Sonnet 4.6, Opus 4.6) +- `claude --permission-mode` — Встановлення режиму дозволів +- `claude --remote` — Увімкнення віддаленого керування через WebSocket + +--- + +## Файли документації (13 файлів) + +| Файл | Розташування | Опис | +|------|-------------|------| +| `README.md` | `/` | Головний огляд прикладів | +| `INDEX.md` | `/` | Цей повний покажчик | +| `QUICK_REFERENCE.md` | `/` | Картка швидкого довідника | +| `README.md` | `/01-slash-commands/` | Посібник зі слеш-команд | +| `README.md` | `/02-memory/` | Посібник з пам'яті | +| `README.md` | `/03-skills/` | Посібник з навичок | +| `README.md` | `/04-subagents/` | Посібник із субагентів | +| `README.md` | `/05-mcp/` | Посібник з MCP | +| `README.md` | `/06-hooks/` | Посібник з хуків | +| `README.md` | `/07-plugins/` | Посібник з плагінів | +| `README.md` | `/08-checkpoints/` | Посібник з контрольних точок | +| `README.md` | `/09-advanced-features/` | Посібник з розширених функцій | +| `README.md` | `/10-cli/` | Посібник з CLI | + +--- + +## Повне дерево файлів + +``` +claude-howto/ +├── README.md # Головний огляд +├── INDEX.md # Цей файл +├── QUICK_REFERENCE.md # Картка довідника +├── claude_concepts_guide.md # Оригінальний посібник +│ +├── 01-slash-commands/ # Слеш-команди +│ ├── optimize.md +│ ├── pr.md +│ ├── generate-api-docs.md +│ ├── commit.md +│ ├── setup-ci-cd.md +│ ├── push-all.md +│ ├── unit-test-expand.md +│ ├── doc-refactor.md +│ ├── pr-slash-command.png +│ └── README.md +│ +├── 02-memory/ # Пам'ять +│ ├── project-CLAUDE.md +│ ├── directory-api-CLAUDE.md +│ ├── personal-CLAUDE.md +│ ├── memory-saved.png +│ ├── memory-ask-claude.png +│ └── README.md +│ +├── 03-skills/ # Навички +│ ├── code-review/ +│ │ ├── SKILL.md +│ │ ├── scripts/ +│ │ │ ├── analyze-metrics.py +│ │ │ └── compare-complexity.py +│ │ └── templates/ +│ │ ├── review-checklist.md +│ │ └── finding-template.md +│ ├── brand-voice/ +│ │ ├── SKILL.md +│ │ ├── templates/ +│ │ │ ├── email-template.txt +│ │ │ └── social-post-template.txt +│ │ └── tone-examples.md +│ ├── doc-generator/ +│ │ ├── SKILL.md +│ │ └── generate-docs.py +│ ├── refactor/ +│ │ ├── SKILL.md +│ │ ├── scripts/ +│ │ │ ├── analyze-complexity.py +│ │ │ └── detect-smells.py +│ │ ├── references/ +│ │ │ ├── code-smells.md +│ │ │ └── refactoring-catalog.md +│ │ └── templates/ +│ │ └── refactoring-plan.md +│ ├── claude-md/ +│ │ └── SKILL.md +│ ├── blog-draft/ +│ │ ├── SKILL.md +│ │ └── templates/ +│ │ ├── draft-template.md +│ │ └── outline-template.md +│ └── README.md +│ +├── 04-subagents/ # Субагенти +│ ├── code-reviewer.md +│ ├── test-engineer.md +│ ├── documentation-writer.md +│ ├── secure-reviewer.md +│ ├── implementation-agent.md +│ ├── debugger.md +│ ├── data-scientist.md +│ ├── clean-code-reviewer.md +│ └── README.md +│ +├── 05-mcp/ # Протокол MCP +│ ├── github-mcp.json +│ ├── database-mcp.json +│ ├── filesystem-mcp.json +│ ├── multi-mcp.json +│ └── README.md +│ +├── 06-hooks/ # Хуки +│ ├── format-code.sh +│ ├── pre-commit.sh +│ ├── security-scan.sh +│ ├── log-bash.sh +│ ├── validate-prompt.sh +│ ├── notify-team.sh +│ ├── context-tracker.py +│ ├── context-tracker-tiktoken.py +│ └── README.md +│ +├── 07-plugins/ # Плагіни +│ ├── pr-review/ +│ │ ├── .claude-plugin/ +│ │ │ └── plugin.json +│ │ ├── commands/ +│ │ │ ├── review-pr.md +│ │ │ ├── check-security.md +│ │ │ └── check-tests.md +│ │ ├── agents/ +│ │ │ ├── security-reviewer.md +│ │ │ ├── test-checker.md +│ │ │ └── performance-analyzer.md +│ │ ├── mcp/ +│ │ │ └── github-config.json +│ │ ├── hooks/ +│ │ │ └── pre-review.js +│ │ └── README.md +│ ├── devops-automation/ +│ │ ├── .claude-plugin/ +│ │ │ └── plugin.json +│ │ ├── commands/ +│ │ │ ├── deploy.md +│ │ │ ├── rollback.md +│ │ │ ├── status.md +│ │ │ └── incident.md +│ │ ├── agents/ +│ │ │ ├── deployment-specialist.md +│ │ │ ├── incident-commander.md +│ │ │ └── alert-analyzer.md +│ │ ├── mcp/ +│ │ │ └── kubernetes-config.json +│ │ ├── hooks/ +│ │ │ ├── pre-deploy.js +│ │ │ └── post-deploy.js +│ │ ├── scripts/ +│ │ │ ├── deploy.sh +│ │ │ ├── rollback.sh +│ │ │ └── health-check.sh +│ │ └── README.md +│ ├── documentation/ +│ │ ├── .claude-plugin/ +│ │ │ └── plugin.json +│ │ ├── commands/ +│ │ │ ├── generate-api-docs.md +│ │ │ ├── generate-readme.md +│ │ │ ├── sync-docs.md +│ │ │ └── validate-docs.md +│ │ ├── agents/ +│ │ │ ├── api-documenter.md +│ │ │ ├── code-commentator.md +│ │ │ └── example-generator.md +│ │ ├── mcp/ +│ │ │ └── github-docs-config.json +│ │ ├── templates/ +│ │ │ ├── api-endpoint.md +│ │ │ ├── function-docs.md +│ │ │ └── adr-template.md +│ │ └── README.md +│ └── README.md +│ +├── 08-checkpoints/ # Контрольні точки +│ ├── checkpoint-examples.md +│ └── README.md +│ +├── 09-advanced-features/ # Розширені функції +│ ├── config-examples.json +│ ├── planning-mode-examples.md +│ └── README.md +│ +└── 10-cli/ # Використання CLI + └── README.md +``` + +--- + +## Швидкий старт за сценарієм + +### Якість коду та ревʼю + +```bash +# Встановити слеш-команду +cp 01-slash-commands/optimize.md .claude/commands/ + +# Встановити субагента +cp 04-subagents/code-reviewer.md .claude/agents/ + +# Встановити навичку +cp -r 03-skills/code-review ~/.claude/skills/ + +# Або встановити повний плагін +/plugin install pr-review +``` + +### DevOps та розгортання + +```bash +# Встановити плагін (включає все) +/plugin install devops-automation +``` + +### Документація + +```bash +# Встановити слеш-команду +cp 01-slash-commands/generate-api-docs.md .claude/commands/ + +# Встановити субагента +cp 04-subagents/documentation-writer.md .claude/agents/ + +# Встановити навичку +cp -r 03-skills/doc-generator ~/.claude/skills/ + +# Або встановити повний плагін +/plugin install documentation +``` + +### Командні стандарти + +```bash +# Налаштувати пам'ять проекту +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Відредагуйте під стандарти вашої команди +``` + +### Зовнішні інтеграції + +```bash +# Встановити змінні оточення +export GITHUB_TOKEN="your_token" +export DATABASE_URL="postgresql://..." + +# Встановити конфігурацію MCP (рівень проекту) +cp 05-mcp/multi-mcp.json .mcp.json +``` + +### Автоматизація та валідація + +```bash +# Встановити хуки +mkdir -p ~/.claude/hooks +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh + +# Налаштувати хуки в settings (~/.claude/settings.json) +# Див. 06-hooks/README.md +``` + +### Безпечне експериментування + +```bash +# Контрольні точки створюються автоматично з кожним промптом +# Для відкату: натисніть Esc+Esc або скористайтесь /rewind +# Потім оберіть, що відновити, з меню відкату + +# Див. 08-checkpoints/README.md для прикладів +``` + +### Розширені робочі процеси + +```bash +# Налаштувати розширені функції +# Див. 09-advanced-features/config-examples.json + +# Використати режим планування +/plan Implement feature X + +# Використати режими дозволів +claude --permission-mode plan # Для ревʼю коду (тільки читання) +claude --permission-mode acceptEdits # Автоматично приймати редагування +claude --permission-mode auto # Автоматично схвалювати безпечні дії + +# Запустити в headless-режимі для CI/CD +claude -p "Run tests and report results" + +# Запустити фонові завдання +Run tests in background + +# Див. 09-advanced-features/README.md для повного посібника +``` + +--- + +## Матриця покриття функцій + +| Категорія | Команди | Агенти | MCP | Хуки | Скрипти | Шаблони | Доки | Зображення | Разом | +|-----------|---------|--------|-----|------|---------|---------|------|------------|-------| +| **01 Слеш-команди** | 8 | - | - | - | - | - | 1 | 1 | **10** | +| **02 Пам'ять** | - | - | - | - | - | 3 | 1 | 2 | **6** | +| **03 Навички** | - | - | - | - | 5 | 9 | 1 | - | **28** | +| **04 Субагенти** | - | 8 | - | - | - | - | 1 | - | **9** | +| **05 MCP** | - | - | 4 | - | - | - | 1 | - | **5** | +| **06 Хуки** | - | - | - | 8 | - | - | 1 | - | **9** | +| **07 Плагіни** | 11 | 9 | 3 | 3 | 3 | 3 | 4 | - | **40** | +| **08 Контрольні точки** | - | - | - | - | - | - | 1 | 1 | **2** | +| **09 Розширені** | - | - | - | - | - | - | 1 | 2 | **3** | +| **10 CLI** | - | - | - | - | - | - | 1 | - | **1** | + +--- + +## Навчальний шлях + +### Початківець (Тиждень 1) + +1. ✅ Прочитати `README.md` +2. ✅ Встановити 1-2 слеш-команди +3. ✅ Створити файл пам'яті проекту +4. ✅ Спробувати базові команди + +### Середній рівень (Тижні 2-3) + +1. ✅ Налаштувати GitHub MCP +2. ✅ Встановити субагента +3. ✅ Спробувати делегувати завдання +4. ✅ Встановити навичку + +### Просунутий (Тиждень 4+) + +1. ✅ Встановити повний плагін +2. ✅ Створити власні слеш-команди +3. ✅ Створити власного субагента +4. ✅ Створити власну навичку +5. ✅ Створити власний плагін + +### Експерт (Тиждень 5+) + +1. ✅ Налаштувати хуки для автоматизації +2. ✅ Використовувати контрольні точки для експериментів +3. ✅ Налаштувати режим планування +4. ✅ Ефективно використовувати режими дозволів +5. ✅ Налаштувати headless-режим для CI/CD +6. ✅ Опанувати управління сесіями + +--- + +## Пошук за ключовим словом + +### Продуктивність + +- `01-slash-commands/optimize.md` — Аналіз продуктивності +- `04-subagents/code-reviewer.md` — Ревʼю продуктивності +- `03-skills/code-review/` — Метрики продуктивності +- `07-plugins/pr-review/agents/performance-analyzer.md` — Спеціаліст з продуктивності + +### Безпека + +- `04-subagents/secure-reviewer.md` — Ревʼю безпеки +- `03-skills/code-review/` — Аналіз безпеки +- `07-plugins/pr-review/` — Перевірки безпеки + +### Тестування + +- `04-subagents/test-engineer.md` — Інженер з тестування +- `07-plugins/pr-review/commands/check-tests.md` — Покриття тестами + +### Документація + +- `01-slash-commands/generate-api-docs.md` — Команда генерації API-документації +- `04-subagents/documentation-writer.md` — Агент-документатор +- `03-skills/doc-generator/` — Навичка генерації документації +- `07-plugins/documentation/` — Повний плагін документації + +### Розгортання + +- `07-plugins/devops-automation/` — Повне DevOps-рішення + +### Автоматизація + +- `06-hooks/` — Автоматизація на основі подій +- `06-hooks/pre-commit.sh` — Автоматизація pre-commit +- `06-hooks/format-code.sh` — Автоформатування +- `09-advanced-features/` — Headless-режим для CI/CD + +### Валідація + +- `06-hooks/security-scan.sh` — Валідація безпеки +- `06-hooks/validate-prompt.sh` — Валідація промптів + +### Експериментування + +- `08-checkpoints/` — Безпечне експериментування з відкатом +- `08-checkpoints/checkpoint-examples.md` — Практичні приклади + +### Планування + +- `09-advanced-features/planning-mode-examples.md` — Приклади режиму планування +- `09-advanced-features/README.md` — Розширене мислення + +### Конфігурація + +- `09-advanced-features/config-examples.json` — Приклади конфігурації + +--- + +## Примітки + +- Усі приклади готові до використання +- Модифікуйте під ваші конкретні потреби +- Приклади дотримуються найкращих практик Claude Code +- Кожна категорія має власний README з детальними інструкціями +- Скрипти включають обробку помилок +- Шаблони можна налаштовувати + +--- + +## Як долучитися + +Хочете додати більше прикладів? Дотримуйтесь структури: + +1. Створіть відповідний підкаталог +2. Додайте README.md з інструкціями +3. Дотримуйтесь конвенцій назв +4. Ретельно протестуйте +5. Оновіть цей покажчик + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Прикладів**: 100+ файлів +**Категорій**: 10 функцій +**Хуків**: 8 скриптів автоматизації +**Прикладів конфігурації**: 10+ сценаріїв +**Готові до використання**: Усі приклади From c343be62f5a26981a825979a6bc66b2f3812591c Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:21:40 +0300 Subject: [PATCH 03/20] feat(uk): translate CATALOG.md to Ukrainian Complete Ukrainian translation of CATALOG.md - the quick reference guide to all Claude Code features. - 55+ built-in commands reference with Ukrainian descriptions - Permission modes, subagents, skills, plugins sections - MCP servers, hooks (25 events), memory types - New features (March 2026) - 20+ features - Quick reference matrix and installation priority - i18n-source-sha frontmatter for version tracking Progress: 3/67 files (P1: 3/5 core documents) Ref: luongnv89/claude-howto#63 --- uk/CATALOG.md | 528 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 uk/CATALOG.md diff --git a/uk/CATALOG.md b/uk/CATALOG.md new file mode 100644 index 0000000..c51d10a --- /dev/null +++ b/uk/CATALOG.md @@ -0,0 +1,528 @@ + + + + + + + Claude How To + + +# Каталог функцій Claude Code + +> Швидкий довідник усіх функцій Claude Code: команди, агенти, навички, плагіни та хуки. + +**Навігація**: [Команди](#слеш-команди) | [Режими дозволів](#режими-дозволів) | [Субагенти](#субагенти) | [Навички](#навички-skills) | [Плагіни](#плагіни) | [MCP-сервери](#mcp-сервери) | [Хуки](#хуки) | [Пам'ять](#файли-памяті) | [Нові функції](#нові-функції-березень-2026) + +--- + +## Підсумок + +| Функція | Вбудовані | Приклади | Разом | Довідник | +|---------|-----------|----------|-------|----------| +| **Слеш-команди** | 55+ | 8 | 63+ | [01-slash-commands/](../01-slash-commands/) | +| **Субагенти** | 6 | 11 | 17 | [04-subagents/](../04-subagents/) | +| **Навички (Skills)** | 5 вбудованих | 4 | 9 | [03-skills/](../03-skills/) | +| **Плагіни** | - | 3 | 3 | [07-plugins/](../07-plugins/) | +| **MCP-сервери** | 1 | 8 | 9 | [05-mcp/](../05-mcp/) | +| **Хуки** | 25 подій | 8 | 8 | [06-hooks/](../06-hooks/) | +| **Пам'ять** | 7 типів | 3 | 3 | [02-memory/](../02-memory/) | +| **Разом** | **99** | **45** | **119** | | + +--- + +## Слеш-команди + +Команди — це ярлики, які викликає користувач для виконання конкретних дій. + +### Вбудовані команди + +| Команда | Опис | Коли використовувати | +|---------|------|---------------------| +| `/help` | Показати довідку | Початок роботи, вивчення команд | +| `/btw` | Побічне запитання без додавання в контекст | Швидкі відступи | +| `/chrome` | Налаштувати інтеграцію з Chrome | Автоматизація браузера | +| `/clear` | Очистити історію розмови | Почати заново, зменшити контекст | +| `/diff` | Інтерактивний перегляд змін | Перегляд змін | +| `/config` | Переглянути/змінити конфігурацію | Налаштування поведінки | +| `/status` | Показати статус сесії | Перевірка поточного стану | +| `/agents` | Список доступних агентів | Перегляд варіантів делегування | +| `/skills` | Список доступних навичок | Перегляд автовикликів | +| `/hooks` | Список налаштованих хуків | Налагодження автоматизації | +| `/insights` | Аналіз патернів сесії | Оптимізація сесії | +| `/install-slack-app` | Встановити Slack-застосунок Claude | Інтеграція зі Slack | +| `/keybindings` | Налаштувати клавіатурні скорочення | Кастомізація клавіш | +| `/mcp` | Список MCP-серверів | Перевірка зовнішніх інтеграцій | +| `/memory` | Переглянути завантажені файли пам'яті | Налагодження контексту | +| `/mobile` | Згенерувати QR-код для мобільного | Мобільний доступ | +| `/passes` | Переглянути використання пропусків | Інформація про підписку | +| `/plugin` | Управління плагінами | Встановлення/видалення розширень | +| `/plan` | Увійти в режим планування | Складні реалізації | +| `/rewind` | Відкат до контрольної точки | Скасування змін, дослідження альтернатив | +| `/checkpoint` | Управління контрольними точками | Збереження/відновлення станів | +| `/cost` | Показати витрати на токени | Моніторинг витрат | +| `/context` | Показати використання контекстного вікна | Управління довжиною розмови | +| `/export` | Експортувати розмову | Збереження для довідки | +| `/extra-usage` | Налаштувати ліміти використання | Управління лімітами | +| `/feedback` | Надіслати відгук або баг-репорт | Повідомлення про проблеми | +| `/login` | Автентифікація в Anthropic | Доступ до функцій | +| `/logout` | Вийти з облікового запису | Зміна акаунту | +| `/sandbox` | Перемкнути режим пісочниці | Безпечне виконання команд | +| `/doctor` | Запустити діагностику | Усунення неполадок | +| `/reload-plugins` | Перезавантажити плагіни | Управління плагінами | +| `/release-notes` | Показати нотатки до релізу | Перевірка нових функцій | +| `/remote-control` | Увімкнути віддалене керування | Віддалений доступ | +| `/permissions` | Управління дозволами | Контроль доступу | +| `/session` | Управління сесіями | Багатосесійні процеси | +| `/rename` | Перейменувати поточну сесію | Організація сесій | +| `/resume` | Відновити попередню сесію | Продовження роботи | +| `/todo` | Переглянути/управляти списком завдань | Відстеження завдань | +| `/tasks` | Переглянути фонові завдання | Моніторинг асинхронних операцій | +| `/copy` | Скопіювати останню відповідь у буфер | Швидке поширення | +| `/teleport` | Перенести сесію на інший комп'ютер | Продовження роботи віддалено | +| `/desktop` | Відкрити десктопний застосунок Claude | Перехід на десктопний інтерфейс | +| `/theme` | Змінити колірну тему | Кастомізація вигляду | +| `/usage` | Показати статистику API | Моніторинг квот і витрат | +| `/fork` | Розгалужити поточну розмову | Дослідження альтернатив | +| `/stats` | Показати статистику сесії | Перегляд метрик сесії | +| `/statusline` | Налаштувати рядок стану | Кастомізація відображення | +| `/stickers` | Переглянути стікери сесії | Ігрові нагороди | +| `/fast` | Перемкнути швидкий режим | Прискорення відповідей | +| `/terminal-setup` | Налаштувати інтеграцію з терміналом | Налаштування терміналу | +| `/upgrade` | Перевірити оновлення | Управління версіями | + +### Кастомні команди (приклади) + +| Команда | Опис | Коли використовувати | Область | Встановлення | +|---------|------|---------------------|---------|-------------| +| `/optimize` | Аналіз коду для оптимізації | Покращення продуктивності | Проект | `cp 01-slash-commands/optimize.md .claude/commands/` | +| `/pr` | Підготовка pull request | Перед відправкою PR | Проект | `cp 01-slash-commands/pr.md .claude/commands/` | +| `/generate-api-docs` | Генерація API-документації | Документування API | Проект | `cp 01-slash-commands/generate-api-docs.md .claude/commands/` | +| `/commit` | Створення git-коміту з контекстом | Фіксація змін | Користувач | `cp 01-slash-commands/commit.md .claude/commands/` | +| `/push-all` | Stage, commit та push | Швидке розгортання | Користувач | `cp 01-slash-commands/push-all.md .claude/commands/` | +| `/doc-refactor` | Реструктуризація документації | Покращення документації | Проект | `cp 01-slash-commands/doc-refactor.md .claude/commands/` | +| `/setup-ci-cd` | Налаштування CI/CD-пайплайну | Нові проекти | Проект | `cp 01-slash-commands/setup-ci-cd.md .claude/commands/` | +| `/unit-test-expand` | Розширення покриття тестами | Покращення тестування | Проект | `cp 01-slash-commands/unit-test-expand.md .claude/commands/` | + +> **Область**: `Користувач` = персональні процеси (`~/.claude/commands/`), `Проект` = спільні для команди (`.claude/commands/`) + +**Довідник**: [01-slash-commands/](../01-slash-commands/) | [Офіційна документація](https://code.claude.com/docs/en/interactive-mode) + +**Швидке встановлення (усі кастомні команди)**: + +```bash +cp 01-slash-commands/*.md .claude/commands/ +``` + +--- + +## Режими дозволів + +Claude Code підтримує 6 режимів дозволів, що контролюють авторизацію використання інструментів. + +| Режим | Опис | Коли використовувати | +|-------|------|---------------------| +| `default` | Запитувати дозвіл на кожен виклик | Стандартна інтерактивна робота | +| `acceptEdits` | Автоприйняття редагувань, запит на інше | Довірені процеси редагування | +| `plan` | Лише інструменти читання, без запису | Планування та дослідження | +| `auto` | Приймати всі інструменти без запиту | Повністю автономна робота (Research Preview) | +| `bypassPermissions` | Пропустити всі перевірки дозволів | CI/CD, headless-середовища | +| `dontAsk` | Пропустити інструменти, що потребують дозволу | Неінтерактивне скриптування | + +> **Примітка**: Режим `auto` — це Research Preview (березень 2026). Використовуйте `bypassPermissions` лише в довірених ізольованих середовищах. + +**Довідник**: [Офіційна документація](https://code.claude.com/docs/en/permissions) + +--- + +## Субагенти + +Спеціалізовані AI-помічники з ізольованими контекстами для конкретних завдань. + +### Вбудовані субагенти + +| Агент | Опис | Інструменти | Модель | Коли використовувати | +|-------|------|-------------|--------|---------------------| +| **general-purpose** | Багатокрокові завдання, дослідження | Усі інструменти | Успадкована | Складні дослідження, багатофайлові завдання | +| **Plan** | Планування реалізації | Read, Glob, Grep, Bash | Успадкована | Проєктування архітектури, планування | +| **Explore** | Дослідження кодової бази | Read, Glob, Grep | Haiku 4.5 | Швидкий пошук, розуміння коду | +| **Bash** | Виконання команд | Bash | Успадкована | Git-операції, термінальні завдання | +| **statusline-setup** | Налаштування рядка стану | Bash, Read, Write | Sonnet 4.6 | Конфігурація рядка стану | +| **Claude Code Guide** | Довідка та документація | Read, Glob, Grep | Haiku 4.5 | Отримання допомоги, вивчення функцій | + +### Поля конфігурації субагентів + +| Поле | Тип | Опис | +|------|-----|------| +| `name` | string | Ідентифікатор агента | +| `description` | string | Що робить агент | +| `model` | string | Перевизначення моделі (наприклад, `haiku-4.5`) | +| `tools` | array | Список дозволених інструментів | +| `effort` | string | Рівень зусиль міркування (`low`, `medium`, `high`) | +| `initialPrompt` | string | Системний промпт при старті агента | +| `disallowedTools` | array | Інструменти, явно заборонені для цього агента | + +### Кастомні субагенти (приклади) + +| Агент | Опис | Коли використовувати | Область | Встановлення | +|-------|------|---------------------|---------|-------------| +| `code-reviewer` | Комплексний аналіз якості коду | Сесії ревʼю коду | Проект | `cp 04-subagents/code-reviewer.md .claude/agents/` | +| `code-architect` | Проєктування архітектури функцій | Планування нових функцій | Проект | `cp 04-subagents/code-architect.md .claude/agents/` | +| `code-explorer` | Глибокий аналіз кодової бази | Розуміння існуючих функцій | Проект | `cp 04-subagents/code-explorer.md .claude/agents/` | +| `clean-code-reviewer` | Ревʼю за принципами Clean Code | Ревʼю підтримуваності | Проект | `cp 04-subagents/clean-code-reviewer.md .claude/agents/` | +| `test-engineer` | Стратегія тестування та покриття | Планування тестів | Проект | `cp 04-subagents/test-engineer.md .claude/agents/` | +| `documentation-writer` | Технічна документація | API-документація, посібники | Проект | `cp 04-subagents/documentation-writer.md .claude/agents/` | +| `secure-reviewer` | Ревʼю з фокусом на безпеку | Аудит безпеки | Проект | `cp 04-subagents/secure-reviewer.md .claude/agents/` | +| `implementation-agent` | Повна реалізація функцій | Розробка функцій | Проект | `cp 04-subagents/implementation-agent.md .claude/agents/` | +| `debugger` | Аналіз першопричин | Дослідження помилок | Користувач | `cp 04-subagents/debugger.md .claude/agents/` | +| `data-scientist` | SQL-запити, аналіз даних | Робота з даними | Користувач | `cp 04-subagents/data-scientist.md .claude/agents/` | +| `performance-optimizer` | Профілювання та оптимізація | Дослідження вузьких місць | Проект | `cp 04-subagents/performance-optimizer.md .claude/agents/` | + +> **Область**: `Користувач` = персональні (`~/.claude/agents/`), `Проект` = спільні для команди (`.claude/agents/`) + +**Довідник**: [04-subagents/](../04-subagents/) | [Офіційна документація](https://code.claude.com/docs/en/sub-agents) + +**Швидке встановлення (усі кастомні агенти)**: + +```bash +cp 04-subagents/*.md .claude/agents/ +``` + +--- + +## Навички (Skills) + +Автоматично викликані можливості з інструкціями, скриптами та шаблонами. + +### Приклади навичок + +| Навичка | Опис | Коли автоматично викликається | Область | Встановлення | +|---------|------|------------------------------|---------|-------------| +| `code-review` | Комплексне ревʼю коду | "Review this code", "Check quality" | Проект | `cp -r 03-skills/code-review .claude/skills/` | +| `brand-voice` | Перевірка стилю бренду | Написання маркетингових текстів | Проект | `cp -r 03-skills/brand-voice .claude/skills/` | +| `doc-generator` | Генератор API-документації | "Generate docs", "Document API" | Проект | `cp -r 03-skills/doc-generator .claude/skills/` | +| `refactor` | Систематичний рефакторинг (за Мартіном Фаулером) | "Refactor this", "Clean up code" | Користувач | `cp -r 03-skills/refactor ~/.claude/skills/` | + +> **Область**: `Користувач` = персональні (`~/.claude/skills/`), `Проект` = спільні (`.claude/skills/`) + +### Структура навички + +``` +~/.claude/skills/skill-name/ +├── SKILL.md # Визначення та інструкції +├── scripts/ # Допоміжні скрипти +└── templates/ # Шаблони виводу +``` + +### Поля фронтматеру навичок + +Навички підтримують YAML-фронтматер у `SKILL.md` для конфігурації: + +| Поле | Тип | Опис | +|------|-----|------| +| `name` | string | Відображуване ім'я навички | +| `description` | string | Що робить навичка | +| `autoInvoke` | array | Фрази-тригери для автовиклику | +| `effort` | string | Рівень зусиль міркування (`low`, `medium`, `high`) | +| `shell` | string | Оболонка для скриптів (`bash`, `zsh`, `sh`) | + +**Довідник**: [03-skills/](../03-skills/) | [Офіційна документація](https://code.claude.com/docs/en/skills) + +**Швидке встановлення (усі навички)**: + +```bash +cp -r 03-skills/* ~/.claude/skills/ +``` + +### Вбудовані навички + +| Навичка | Опис | Коли автоматично викликається | +|---------|------|------------------------------| +| `/simplify` | Ревʼю коду на якість | Після написання коду | +| `/batch` | Запуск промптів для кількох файлів | Пакетні операції | +| `/debug` | Налагодження помилок/тестів | Сесії налагодження | +| `/loop` | Запуск промптів за інтервалом | Повторювані завдання | +| `/claude-api` | Створення застосунків з Claude API | Розробка з API | + +--- + +## Плагіни + +Пакетні набори команд, агентів, MCP-серверів та хуків. + +### Приклади плагінів + +| Плагін | Опис | Компоненти | Коли використовувати | Область | Встановлення | +|--------|------|------------|---------------------|---------|-------------| +| `pr-review` | Процес ревʼю PR | 3 команди, 3 агенти, GitHub MCP | Ревʼю коду | Проект | `/plugin install pr-review` | +| `devops-automation` | Розгортання та моніторинг | 4 команди, 3 агенти, K8s MCP | DevOps-завдання | Проект | `/plugin install devops-automation` | +| `documentation` | Набір генерації документації | 4 команди, 3 агенти, шаблони | Документація | Проект | `/plugin install documentation` | + +> **Область**: `Проект` = спільні для команди, `Користувач` = персональні процеси + +### Структура плагіна + +``` +.claude-plugin/ +├── plugin.json # Файл маніфесту +├── commands/ # Слеш-команди +├── agents/ # Субагенти +├── skills/ # Навички +├── mcp/ # Конфігурації MCP +├── hooks/ # Скрипти хуків +└── scripts/ # Допоміжні скрипти +``` + +**Довідник**: [07-plugins/](../07-plugins/) | [Офіційна документація](https://code.claude.com/docs/en/plugins) + +**Команди управління плагінами**: + +```bash +/plugin list # Список встановлених плагінів +/plugin install # Встановити плагін +/plugin remove # Видалити плагін +/plugin update # Оновити плагін +``` + +--- + +## MCP-сервери + +Сервери Model Context Protocol для доступу до зовнішніх інструментів та API. + +### Поширені MCP-сервери + +| Сервер | Опис | Коли використовувати | Область | Встановлення | +|--------|------|---------------------|---------|-------------| +| **GitHub** | Управління PR, issues, код | Процеси з GitHub | Проект | `claude mcp add github -- npx -y @modelcontextprotocol/server-github` | +| **Database** | SQL-запити, доступ до даних | Операції з БД | Проект | `claude mcp add db -- npx -y @modelcontextprotocol/server-postgres` | +| **Filesystem** | Розширені файлові операції | Складна робота з файлами | Користувач | `claude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem` | +| **Slack** | Комунікація команди | Сповіщення, оновлення | Проект | Налаштування в settings | +| **Google Docs** | Доступ до документів | Редагування, ревʼю документів | Проект | Налаштування в settings | +| **Asana** | Управління проектами | Відстеження завдань | Проект | Налаштування в settings | +| **Stripe** | Платіжні дані | Фінансовий аналіз | Проект | Налаштування в settings | +| **Memory** | Постійна пам'ять | Згадування між сесіями | Користувач | Налаштування в settings | +| **Context7** | Документація бібліотек | Пошук актуальної документації | Вбудований | Вбудований | + +> **Область**: `Проект` = командний (`.mcp.json`), `Користувач` = персональний (`~/.claude.json`), `Вбудований` = попередньо встановлений + +### Приклад конфігурації MCP + +```json +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} +``` + +**Довідник**: [05-mcp/](../05-mcp/) | [Документація MCP](https://modelcontextprotocol.io) + +**Швидке встановлення (GitHub MCP)**: + +```bash +export GITHUB_TOKEN="your_token" && claude mcp add github -- npx -y @modelcontextprotocol/server-github +``` + +--- + +## Хуки + +Автоматизація на основі подій, що виконує shell-команди при подіях Claude Code. + +### Події хуків + +| Подія | Опис | Коли спрацьовує | Сценарії | +|-------|------|----------------|----------| +| `SessionStart` | Початок/відновлення сесії | Ініціалізація сесії | Завдання налаштування | +| `InstructionsLoaded` | Інструкції завантажені | Завантажено CLAUDE.md або rules | Обробка кастомних інструкцій | +| `UserPromptSubmit` | Перед обробкою промпту | Користувач надсилає повідомлення | Валідація вводу | +| `PreToolUse` | Перед виконанням інструменту | Перед запуском будь-якого інструменту | Валідація, логування | +| `PermissionRequest` | Діалог дозволу | Перед чутливими діями | Кастомні потоки схвалення | +| `PostToolUse` | Після успішного виконання | Після завершення інструменту | Форматування, сповіщення | +| `PostToolUseFailure` | Помилка виконання | Після помилки інструменту | Обробка помилок, логування | +| `Notification` | Надіслано сповіщення | Claude надсилає сповіщення | Зовнішні оповіщення | +| `SubagentStart` | Субагент запущений | Початок завдання субагента | Ініціалізація контексту | +| `SubagentStop` | Субагент завершив | Завдання субагента виконано | Ланцюгові дії | +| `Stop` | Claude завершив відповідь | Відповідь готова | Очищення, звітність | +| `StopFailure` | API-помилка завершила черга | API-помилка | Відновлення, логування | +| `TeammateIdle` | Агент-партнер бездіє | Координація агентів | Розподіл роботи | +| `TaskCompleted` | Завдання позначено як виконане | Завдання завершено | Пост-обробка | +| `TaskCreated` | Завдання створено через TaskCreate | Нове завдання створено | Відстеження, логування | +| `ConfigChange` | Конфігурацію оновлено | Налаштування змінені | Реакція на зміни конфігурації | +| `CwdChanged` | Робочий каталог змінився | Зміна каталогу | Налаштування для каталогу | +| `FileChanged` | Відстежуваний файл змінився | Файл модифіковано | Моніторинг, перебудова | +| `PreCompact` | Перед компактизацією | Стиснення контексту | Збереження стану | +| `PostCompact` | Після компактизації | Компактизація завершена | Дії після стиснення | +| `WorktreeCreate` | Створення worktree | Git worktree створено | Налаштування середовища | +| `WorktreeRemove` | Видалення worktree | Git worktree видалено | Очищення ресурсів | +| `Elicitation` | MCP-сервер запитує ввід | MCP-елісітація | Валідація вводу | +| `ElicitationResult` | Користувач відповідає | Відповідь на елісітацію | Обробка відповіді | +| `SessionEnd` | Завершення сесії | Завершення сесії | Очищення, збереження стану | + +### Приклади хуків + +| Хук | Опис | Подія | Область | Встановлення | +|-----|------|-------|---------|-------------| +| `validate-bash.py` | Валідація команд | PreToolUse:Bash | Проект | `cp 06-hooks/validate-bash.py .claude/hooks/` | +| `security-scan.py` | Сканування безпеки | PostToolUse:Write | Проект | `cp 06-hooks/security-scan.py .claude/hooks/` | +| `format-code.sh` | Автоформатування | PostToolUse:Write | Користувач | `cp 06-hooks/format-code.sh ~/.claude/hooks/` | +| `validate-prompt.py` | Валідація промптів | UserPromptSubmit | Проект | `cp 06-hooks/validate-prompt.py .claude/hooks/` | +| `context-tracker.py` | Відстеження токенів | Stop | Користувач | `cp 06-hooks/context-tracker.py ~/.claude/hooks/` | +| `pre-commit.sh` | Pre-commit валідація | PreToolUse:Bash | Проект | `cp 06-hooks/pre-commit.sh .claude/hooks/` | +| `log-bash.sh` | Логування команд | PostToolUse:Bash | Користувач | `cp 06-hooks/log-bash.sh ~/.claude/hooks/` | +| `dependency-check.sh` | Сканування вразливостей при зміні маніфесту | PostToolUse:Write | Проект | `cp 06-hooks/dependency-check.sh .claude/hooks/` | + +> **Область**: `Проект` = командний (`.claude/settings.json`), `Користувач` = персональний (`~/.claude/settings.json`) + +### Конфігурація хуків + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "command": "~/.claude/hooks/validate-bash.py" + } + ], + "PostToolUse": [ + { + "matcher": "Write", + "command": "~/.claude/hooks/format-code.sh" + } + ] + } +} +``` + +**Довідник**: [06-hooks/](../06-hooks/) | [Офіційна документація](https://code.claude.com/docs/en/hooks) + +**Швидке встановлення (усі хуки)**: + +```bash +mkdir -p ~/.claude/hooks && cp 06-hooks/*.sh ~/.claude/hooks/ && chmod +x ~/.claude/hooks/*.sh +``` + +--- + +## Файли пам'яті + +Постійний контекст, що автоматично завантажується між сесіями. + +### Типи пам'яті + +| Тип | Розташування | Область | Коли використовувати | +|-----|-------------|---------|---------------------| +| **Керована політика** | Політики організації | Організація | Застосування стандартів організації | +| **Проект** | `./CLAUDE.md` | Проект (команда) | Командні стандарти, контекст проекту | +| **Правила проекту** | `.claude/rules/` | Проект (команда) | Модульні правила проекту | +| **Користувач** | `~/.claude/CLAUDE.md` | Користувач (персональні) | Персональні налаштування | +| **Правила користувача** | `~/.claude/rules/` | Користувач (персональні) | Модульні персональні правила | +| **Локальний** | `./CLAUDE.local.md` | Локальний (git-ignored) | Перевизначення для конкретної машини (не в офіційних docs станом на березень 2026; може бути legacy) | +| **Автопам'ять** | Автоматично | Сесія | Автозбережені інсайти та виправлення | + +> **Область**: `Організація` = керується адмінами, `Проект` = спільний через git, `Користувач` = персональні, `Локальний` = не комітиться, `Сесія` = автокерований + +**Довідник**: [02-memory/](../02-memory/) | [Офіційна документація](https://code.claude.com/docs/en/memory) + +**Швидке встановлення**: + +```bash +cp 02-memory/project-CLAUDE.md ./CLAUDE.md +cp 02-memory/personal-CLAUDE.md ~/.claude/CLAUDE.md +``` + +--- + +## Нові функції (березень 2026) + +| Функція | Опис | Як використовувати | +|---------|------|--------------------| +| **Віддалене керування** | Керування сесіями Claude Code віддалено через API | API віддаленого керування для програмної відправки промптів | +| **Веб-сесії** | Запуск Claude Code у браузерному середовищі | Доступ через `claude web` або Anthropic Console | +| **Десктопний застосунок** | Нативний десктопний застосунок Claude Code | `/desktop` або завантаження з сайту Anthropic | +| **Команди агентів** | Координація кількох агентів для пов'язаних завдань | Налаштування агентів-партнерів для співпраці | +| **Список завдань** | Управління та моніторинг фонових завдань | `/tasks` для перегляду та управління | +| **Підказки промптів** | Контекстно-залежні підказки команд | Підказки з'являються автоматично | +| **Git Worktrees** | Ізольовані worktrees для паралельної розробки | Команди worktree для безпечної паралельної роботи | +| **Пісочниця** | Ізольовані середовища виконання для безпеки | `/sandbox` для перемикання | +| **MCP OAuth** | OAuth-автентифікація для MCP-серверів | OAuth-облікові дані в налаштуваннях MCP | +| **MCP Tool Search** | Динамічний пошук MCP-інструментів | Пошук доступних MCP-інструментів | +| **Заплановані завдання** | Повторювані завдання з `/loop` та cron | `/loop 5m /command` або CronCreate | +| **Інтеграція з Chrome** | Автоматизація браузера через headless Chromium | Прапорець `--chrome` або `/chrome` | +| **Кастомізація клавіатури** | Налаштування клавіш з підтримкою акордів | `/keybindings` або `~/.claude/keybindings.json` | +| **Auto Mode** | Повністю автономна робота (Research Preview) | `--mode auto` або `/permissions auto` | +| **Канали** | Багатоканальна комунікація (Telegram, Slack тощо) (Research Preview) | Налаштування канальних плагінів | +| **Голосовий ввід** | Голосове введення промптів | Іконка мікрофона або клавіша | +| **Тип хука Agent** | Хуки, що запускають субагента замість shell-команди | `"type": "agent"` у конфігурації хука | +| **Тип хука Prompt** | Хуки, що вставляють текст промпту в розмову | `"type": "prompt"` у конфігурації хука | +| **MCP Elicitation** | MCP-сервери можуть запитувати ввід користувача | Обробка через події `Elicitation` та `ElicitationResult` | +| **Plugin LSP** | Інтеграція Language Server Protocol через плагіни | LSP-сервери в `plugin.json` | +| **Керовані drop-ins** | Конфігурації, керовані організацією (v2.1.83) | Налаштовуються адмінами через керовані політики | + +--- + +## Матриця швидкого довідника + +### Посібник з вибору функцій + +| Потреба | Рекомендована функція | Чому | +|---------|----------------------|------| +| Швидкий ярлик | Слеш-команда | Ручний, миттєвий | +| Постійний контекст | Пам'ять | Автозавантаження | +| Складна автоматизація | Навичка | Автовиклик | +| Спеціалізоване завдання | Субагент | Ізольований контекст | +| Зовнішні дані | MCP-сервер | Доступ у реальному часі | +| Автоматизація подій | Хук | Тригер на подію | +| Комплексне рішення | Плагін | Все в одному | + +### Пріоритет встановлення + +| Пріоритет | Функція | Команда | +|-----------|---------|---------| +| 1. Необхідне | Пам'ять | `cp 02-memory/project-CLAUDE.md ./CLAUDE.md` | +| 2. Щоденне | Слеш-команди | `cp 01-slash-commands/*.md .claude/commands/` | +| 3. Якість | Субагенти | `cp 04-subagents/*.md .claude/agents/` | +| 4. Автоматизація | Хуки | `cp 06-hooks/*.sh ~/.claude/hooks/ && chmod +x ~/.claude/hooks/*.sh` | +| 5. Зовнішнє | MCP | `claude mcp add github -- npx -y @modelcontextprotocol/server-github` | +| 6. Просунуте | Навички | `cp -r 03-skills/* ~/.claude/skills/` | +| 7. Комплексне | Плагіни | `/plugin install pr-review` | + +--- + +## Встановлення всього однією командою + +Встановлення всіх прикладів з цього репозиторію: + +```bash +# Створити каталоги +mkdir -p .claude/{commands,agents,skills} ~/.claude/{hooks,skills} + +# Встановити всі функції +cp 01-slash-commands/*.md .claude/commands/ && \ +cp 02-memory/project-CLAUDE.md ./CLAUDE.md && \ +cp -r 03-skills/* ~/.claude/skills/ && \ +cp 04-subagents/*.md .claude/agents/ && \ +cp 06-hooks/*.sh ~/.claude/hooks/ && \ +chmod +x ~/.claude/hooks/*.sh +``` + +--- + +## Додаткові ресурси + +- [Офіційна документація Claude Code](https://code.claude.com/docs/en/overview) +- [Специфікація MCP](https://modelcontextprotocol.io) +- [Навчальний план](LEARNING-ROADMAP.md) +- [Головний README](README.md) + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 From 118fd4018391c635c5307ebf899140f32703d1b2 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:28:06 +0300 Subject: [PATCH 04/20] feat(uk): translate QUICK_REFERENCE.md to Ukrainian Complete Ukrainian translation of QUICK_REFERENCE.md - the quick reference card for all Claude Code features. - Installation quick commands for all features - Feature cheat sheet with paths and usage - Common use cases (code review, docs, DevOps, CI/CD) - File locations reference diagram - Learning path (Day 1 through Week 3+) - New features (March 2026) section - Tips, FAQ, and getting started checklist Progress: 4/67 files (P1: 4/5 core documents) Ref: luongnv89/claude-howto#63 --- uk/QUICK_REFERENCE.md | 545 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 uk/QUICK_REFERENCE.md diff --git a/uk/QUICK_REFERENCE.md b/uk/QUICK_REFERENCE.md new file mode 100644 index 0000000..6461f87 --- /dev/null +++ b/uk/QUICK_REFERENCE.md @@ -0,0 +1,545 @@ + + + + + + + Claude How To + + +# Приклади Claude Code — Картка швидкого довідника + +## 🚀 Команди швидкого встановлення + +### Слеш-команди + +```bash +# Встановити всі +cp 01-slash-commands/*.md .claude/commands/ + +# Встановити конкретну +cp 01-slash-commands/optimize.md .claude/commands/ +``` + +### Пам'ять + +```bash +# Пам'ять проекту +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Персональна пам'ять +cp 02-memory/personal-CLAUDE.md ~/.claude/CLAUDE.md +``` + +### Навички (Skills) + +```bash +# Персональні навички +cp -r 03-skills/code-review ~/.claude/skills/ + +# Навички проекту +cp -r 03-skills/code-review .claude/skills/ +``` + +### Субагенти + +```bash +# Встановити всі +cp 04-subagents/*.md .claude/agents/ + +# Встановити конкретного +cp 04-subagents/code-reviewer.md .claude/agents/ +``` + +### MCP + +```bash +# Встановити облікові дані +export GITHUB_TOKEN="your_token" +export DATABASE_URL="postgresql://..." + +# Встановити конфігурацію (рівень проекту) +cp 05-mcp/github-mcp.json .mcp.json + +# Або рівень користувача: додати в ~/.claude.json +``` + +### Хуки + +```bash +# Встановити хуки +mkdir -p ~/.claude/hooks +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh + +# Налаштувати в settings (~/.claude/settings.json) +``` + +### Плагіни + +```bash +# Встановити з прикладів (якщо опубліковані) +/plugin install pr-review +/plugin install devops-automation +/plugin install documentation +``` + +### Контрольні точки + +```bash +# Контрольні точки створюються автоматично з кожним промптом +# Для відкату натисніть Esc двічі або скористайтесь: +/rewind + +# Потім оберіть: Відновити код і розмову, Відновити розмову, +# Відновити код, Підсумувати звідси, або Скасувати +``` + +### Розширені функції + +```bash +# Налаштувати в settings (.claude/settings.json) +# Див. 09-advanced-features/config-examples.json + +# Режим планування +/plan Task description + +# Режими дозволів (прапорець --permission-mode) +# default - Запитувати дозвіл на ризиковані дії +# acceptEdits - Автоприйняття редагувань, запит на інше +# plan - Лише аналіз, без змін (тільки читання) +# dontAsk - Приймати все, крім ризикованого +# auto - Фоновий класифікатор вирішує автоматично +# bypassPermissions - Приймати все (потребує --dangerously-skip-permissions) + +# Управління сесіями +/resume # Відновити попередню розмову +/rename "name" # Назвати поточну сесію +/fork # Розгалужити поточну сесію +claude -c # Продовжити останню розмову +claude -r "session" # Відновити сесію за назвою/ID +``` + +--- + +## 📋 Шпаргалка по функціях + +| Функція | Шлях встановлення | Використання | +|---------|------------------|-------------| +| **Слеш-команди (55+)** | `.claude/commands/*.md` | `/command-name` | +| **Пам'ять** | `./CLAUDE.md` | Автозавантаження | +| **Навички** | `.claude/skills/*/SKILL.md` | Автовиклик | +| **Субагенти** | `.claude/agents/*.md` | Автоделегування | +| **MCP** | `.mcp.json` (проект) або `~/.claude.json` (користувач) | `/mcp__server__action` | +| **Хуки (25 подій)** | `~/.claude/hooks/*.sh` | Тригер на подію (4 типи) | +| **Плагіни** | Через `/plugin install` | Пакет всього | +| **Контрольні точки** | Вбудовано | `Esc+Esc` або `/rewind` | +| **Режим планування** | Вбудовано | `/plan <завдання>` | +| **Режими дозволів (6)** | Вбудовано | `--allowedTools`, `--permission-mode` | +| **Сесії** | Вбудовано | `/session <команда>` | +| **Фонові завдання** | Вбудовано | Run in background | +| **Віддалене керування** | Вбудовано | WebSocket API | +| **Веб-сесії** | Вбудовано | `claude web` | +| **Git Worktrees** | Вбудовано | `/worktree` | +| **Автопам'ять** | Вбудовано | Автозбереження в CLAUDE.md | +| **Список завдань** | Вбудовано | `/task list` | +| **Вбудовані навички (5)** | Вбудовано | `/simplify`, `/loop`, `/claude-api`, `/voice`, `/browse` | + +--- + +## 🎯 Типові сценарії використання + +### Ревʼю коду + +```bash +# Спосіб 1: Слеш-команда +cp 01-slash-commands/optimize.md .claude/commands/ +# Використання: /optimize + +# Спосіб 2: Субагент +cp 04-subagents/code-reviewer.md .claude/agents/ +# Використання: Автоделегування + +# Спосіб 3: Навичка +cp -r 03-skills/code-review ~/.claude/skills/ +# Використання: Автовиклик + +# Спосіб 4: Плагін (найкращий) +/plugin install pr-review +# Використання: /review-pr +``` + +### Документація + +```bash +# Слеш-команда +cp 01-slash-commands/generate-api-docs.md .claude/commands/ + +# Субагент +cp 04-subagents/documentation-writer.md .claude/agents/ + +# Навичка +cp -r 03-skills/doc-generator ~/.claude/skills/ + +# Плагін (комплексне рішення) +/plugin install documentation +``` + +### DevOps + +```bash +# Повний плагін +/plugin install devops-automation + +# Команди: /deploy, /rollback, /status, /incident +``` + +### Командні стандарти + +```bash +# Пам'ять проекту +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Відредагуйте під вашу команду +vim CLAUDE.md +``` + +### Автоматизація та хуки + +```bash +# Встановити хуки (25 подій, 4 типи: command, http, prompt, agent) +mkdir -p ~/.claude/hooks +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh + +# Приклади: +# - Тести перед комітом: pre-commit.sh +# - Автоформатування коду: format-code.sh +# - Сканування безпеки: security-scan.sh + +# Auto Mode для повністю автономних процесів +claude --enable-auto-mode -p "Refactor and test the auth module" +# Або циклічна зміна режимів інтерактивно з Shift+Tab +``` + +### Безпечний рефакторинг + +```bash +# Контрольні точки створюються автоматично перед кожним промптом +# Спробуйте рефакторинг +# Якщо вдалось: продовжуйте +# Якщо не вдалось: натисніть Esc+Esc або /rewind для відкату +``` + +### Складна реалізація + +```bash +# Використайте режим планування +/plan Implement user authentication system + +# Claude створить детальний план +# Перегляньте та затвердіть +# Claude реалізує систематично +``` + +### Інтеграція з CI/CD + +```bash +# Запуск у headless-режимі (неінтерактивно) +claude -p "Run all tests and generate report" + +# З режимом дозволів для CI +claude -p "Run tests" --permission-mode dontAsk + +# З Auto Mode для повністю автономних CI-завдань +claude --enable-auto-mode -p "Run tests and fix failures" + +# З хуками для автоматизації +# Див. 09-advanced-features/README.md +``` + +### Навчання та експериментування + +```bash +# Режим plan для безпечного аналізу +claude --permission-mode plan + +# Експериментуйте безпечно — контрольні точки створюються автоматично +# Для відкату: натисніть Esc+Esc або /rewind +``` + +### Команди агентів + +```bash +# Увімкнути команди агентів +export CLAUDE_AGENT_TEAMS=1 + +# Або в settings.json +{ "agentTeams": { "enabled": true } } + +# Почніть з: "Implement feature X using a team approach" +``` + +### Заплановані завдання + +```bash +# Запускати команду кожні 5 хвилин +/loop 5m /check-status + +# Одноразове нагадування +/loop 30m "remind me to check the deploy" +``` + +--- + +## 📁 Довідник розташування файлів + +``` +Ваш проект/ +├── .claude/ +│ ├── commands/ # Слеш-команди тут +│ ├── agents/ # Субагенти тут +│ ├── skills/ # Навички проекту тут +│ └── settings.json # Налаштування проекту (хуки тощо) +├── .mcp.json # Конфігурація MCP (рівень проекту) +├── CLAUDE.md # Пам'ять проекту +└── src/ + └── api/ + └── CLAUDE.md # Пам'ять для конкретного каталогу + +Домашній каталог/ +├── .claude/ +│ ├── commands/ # Персональні команди +│ ├── agents/ # Персональні агенти +│ ├── skills/ # Персональні навички +│ ├── hooks/ # Скрипти хуків +│ ├── settings.json # Налаштування користувача +│ ├── managed-settings.d/ # Керовані налаштування (enterprise/org) +│ └── CLAUDE.md # Персональна пам'ять +└── .claude.json # Персональна конфігурація MCP (рівень користувача) +``` + +--- + +## 🔍 Пошук прикладів + +### За категорією + +- **Слеш-команди**: `01-slash-commands/` +- **Пам'ять**: `02-memory/` +- **Навички**: `03-skills/` +- **Субагенти**: `04-subagents/` +- **MCP**: `05-mcp/` +- **Хуки**: `06-hooks/` +- **Плагіни**: `07-plugins/` +- **Контрольні точки**: `08-checkpoints/` +- **Розширені функції**: `09-advanced-features/` +- **CLI**: `10-cli/` + +### За сценарієм + +- **Продуктивність**: `01-slash-commands/optimize.md` +- **Безпека**: `04-subagents/secure-reviewer.md` +- **Тестування**: `04-subagents/test-engineer.md` +- **Документація**: `03-skills/doc-generator/` +- **DevOps**: `07-plugins/devops-automation/` + +### За складністю + +- **Просто**: Слеш-команди +- **Середньо**: Субагенти, Пам'ять +- **Просунуто**: Навички, Хуки +- **Комплексно**: Плагіни + +--- + +## 🎓 Навчальний шлях + +### День 1 + +```bash +# Прочитати огляд +cat README.md + +# Встановити команду +cp 01-slash-commands/optimize.md .claude/commands/ + +# Спробувати +/optimize +``` + +### Дні 2-3 + +```bash +# Налаштувати пам'ять +cp 02-memory/project-CLAUDE.md ./CLAUDE.md +vim CLAUDE.md + +# Встановити субагента +cp 04-subagents/code-reviewer.md .claude/agents/ +``` + +### Дні 4-5 + +```bash +# Налаштувати MCP +export GITHUB_TOKEN="your_token" +cp 05-mcp/github-mcp.json .mcp.json + +# Спробувати MCP-команди +/mcp__github__list_prs +``` + +### Тиждень 2 + +```bash +# Встановити навичку +cp -r 03-skills/code-review ~/.claude/skills/ + +# Дозвольте автовиклик +# Просто скажіть: "Review this code for issues" +``` + +### Тиждень 3+ + +```bash +# Встановити повний плагін +/plugin install pr-review + +# Використати вбудовані функції +/review-pr +/check-security +/check-tests +``` + +--- + +## Нові функції (березень 2026) + +| Функція | Опис | Використання | +|---------|------|-------------| +| **Auto Mode** | Повністю автономна робота з фоновим класифікатором | Прапорець `--enable-auto-mode`, `Shift+Tab` для зміни режимів | +| **Канали** | Інтеграція з Discord та Telegram | Прапорець `--channels`, боти Discord/Telegram | +| **Голосовий ввід** | Голосові команди та контекст для Claude | Команда `/voice` | +| **Хуки (26 подій)** | Розширена система хуків з 4 типами | Типи: command, http, prompt, agent | +| **MCP Elicitation** | MCP-сервери можуть запитувати ввід під час виконання | Автозапит при потребі сервера | +| **Plugin LSP** | Підтримка Language Server Protocol для плагінів | `userConfig`, змінна `${CLAUDE_PLUGIN_DATA}` | +| **Віддалене керування** | Керування Claude Code через WebSocket API | `claude --remote` для зовнішніх інтеграцій | +| **Веб-сесії** | Браузерний інтерфейс Claude Code | `claude web` для запуску | +| **Десктопний застосунок** | Нативний десктопний застосунок | Завантаження з claude.ai/download | +| **Список завдань** | Управління фоновими завданнями | `/task list`, `/task status ` | +| **Автопам'ять** | Автоматичне збереження з розмов | Claude автозберігає контекст у CLAUDE.md | +| **Git Worktrees** | Ізольовані робочі простори для паралельної розробки | `/worktree` для створення | +| **Вибір моделі** | Перемикання між Sonnet 4.6 та Opus 4.6 | `/model` або прапорець `--model` | +| **Команди агентів** | Координація кількох агентів | Увімкнути з `CLAUDE_AGENT_TEAMS=1` | +| **Заплановані завдання** | Повторювані завдання з `/loop` | `/loop 5m /command` або CronCreate | +| **Інтеграція з Chrome** | Автоматизація браузера | Прапорець `--chrome` або `/chrome` | +| **Кастомізація клавіатури** | Налаштування клавіш | Команда `/keybindings` | + +--- + +## Поради та хитрощі + +### Кастомізація + +- Почніть з прикладів як є +- Модифікуйте під ваші потреби +- Тестуйте перед поширенням в команді +- Тримайте конфігурації під контролем версій + +### Найкращі практики + +- Використовуйте пам'ять для командних стандартів +- Використовуйте плагіни для комплексних процесів +- Використовуйте субагентів для складних завдань +- Використовуйте слеш-команди для швидких завдань + +### Усунення неполадок + +```bash +# Перевірити розташування файлів +ls -la .claude/commands/ +ls -la .claude/agents/ + +# Перевірити YAML-синтаксис +head -20 .claude/agents/code-reviewer.md + +# Перевірити MCP-з'єднання +echo $GITHUB_TOKEN +``` + +--- + +## 📊 Матриця функцій + +| Потреба | Використовуйте | Приклад | +|---------|---------------|---------| +| Швидкий ярлик | Слеш-команда (55+) | `01-slash-commands/optimize.md` | +| Командні стандарти | Пам'ять | `02-memory/project-CLAUDE.md` | +| Автоматичний процес | Навичка | `03-skills/code-review/` | +| Спеціалізоване завдання | Субагент | `04-subagents/code-reviewer.md` | +| Зовнішні дані | MCP (+ Elicitation) | `05-mcp/github-mcp.json` | +| Автоматизація подій | Хук (26 подій, 4 типи) | `06-hooks/pre-commit.sh` | +| Комплексне рішення | Плагін (+ LSP) | `07-plugins/pr-review/` | +| Безпечний експеримент | Контрольна точка | `08-checkpoints/checkpoint-examples.md` | +| Повна автономія | Auto Mode | `--enable-auto-mode` або `Shift+Tab` | +| Чат-інтеграції | Канали | `--channels` (Discord, Telegram) | +| CI/CD-пайплайн | CLI | `10-cli/README.md` | + +--- + +## 🔗 Швидкі посилання + +- **Головний посібник**: `README.md` +- **Повний покажчик**: `INDEX.md` +- **Каталог**: `CATALOG.md` +- **Оригінальний посібник**: `claude_concepts_guide.md` + +--- + +## 📞 Поширені запитання + +**П: Що обрати?** +В: Почніть зі слеш-команд, додавайте функції за потребою. + +**П: Чи можна комбінувати функції?** +В: Так! Вони працюють разом. Пам'ять + Команди + MCP = потужна зв'язка. + +**П: Як поділитися з командою?** +В: Закомітьте каталог `.claude/` до git. + +**П: А що з секретами?** +В: Використовуйте змінні оточення, ніколи не хардкодьте. + +**П: Чи можна змінювати приклади?** +В: Безумовно! Це шаблони для кастомізації. + +--- + +## ✅ Чекліст + +Чекліст для початку роботи: + +- [ ] Прочитати `README.md` +- [ ] Встановити 1 слеш-команду +- [ ] Спробувати команду +- [ ] Створити `CLAUDE.md` проекту +- [ ] Встановити 1 субагента +- [ ] Налаштувати 1 MCP-інтеграцію +- [ ] Встановити 1 навичку +- [ ] Спробувати повний плагін +- [ ] Кастомізувати під свої потреби +- [ ] Поділитися з командою + +--- + +**Швидкий старт**: `cat README.md` + +**Повний покажчик**: `cat INDEX.md` + +**Ця картка**: Тримайте під рукою для швидкого довідника! + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 From 9efa5dd9b8911468e61cf1a1008aaa023ccdbd7a Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:34:22 +0300 Subject: [PATCH 05/20] feat(uk): translate LEARNING-ROADMAP.md to Ukrainian Complete Ukrainian translation of LEARNING-ROADMAP.md - the guided learning path for Claude Code features. - Self-assessment quiz for level determination - Three learning levels: Beginner, Intermediate, Advanced - All milestones (1A, 1B, 2A, 2B, 3A, 3B) with exercises - Mermaid diagram preserved unchanged - Progress tracking checklists - Quick start paths (15 min, 1 hour, weekend) - Learning tips and common challenges Progress: 5/67 files (P1: 5/5 core documents COMPLETE) Ref: luongnv89/claude-howto#63 --- uk/LEARNING-ROADMAP.md | 800 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 800 insertions(+) create mode 100644 uk/LEARNING-ROADMAP.md diff --git a/uk/LEARNING-ROADMAP.md b/uk/LEARNING-ROADMAP.md new file mode 100644 index 0000000..ff74200 --- /dev/null +++ b/uk/LEARNING-ROADMAP.md @@ -0,0 +1,800 @@ + + + + + + + Claude How To + + +# 📚 Навчальний план Claude Code + +**Новачок у Claude Code?** Цей посібник допоможе вам опанувати функції Claude Code у зручному темпі. Незалежно від того, чи ви абсолютний початківець, чи досвідчений розробник, почніть з тесту самооцінки нижче, щоб знайти свій рівень. + +--- + +## 🧭 Визначте свій рівень + +Не всі починають з однієї точки. Пройдіть швидку самооцінку, щоб знайти правильну відправну точку. + +**Відповідайте чесно:** + +- [ ] Я можу запустити Claude Code та вести розмову (`claude`) +- [ ] Я створював або редагував файл CLAUDE.md +- [ ] Я використовував принаймні 3 вбудовані слеш-команди (наприклад, /help, /compact, /model) +- [ ] Я створював кастомну слеш-команду або навичку (SKILL.md) +- [ ] Я налаштовував MCP-сервер (наприклад, GitHub, база даних) +- [ ] Я налаштовував хуки в ~/.claude/settings.json +- [ ] Я створював або використовував кастомних субагентів (.claude/agents/) +- [ ] Я використовував print mode (`claude -p`) для скриптів або CI/CD + +**Ваш рівень:** + +| Відмічено | Рівень | Почніть з | Час на завершення | +|-----------|--------|-----------|-------------------| +| 0-2 | **Рівень 1: Початківець** — Перші кроки | [Етап 1A](#етап-1a-перші-команди-та-память) | ~3 години | +| 3-5 | **Рівень 2: Середній** — Побудова процесів | [Етап 2A](#етап-2a-автоматизація-навички--хуки) | ~5 годин | +| 6-8 | **Рівень 3: Просунутий** — Досвідчений користувач | [Етап 3A](#етап-3a-розширені-функції) | ~5 годин | + +> **Порада**: Якщо не впевнені, почніть на рівень нижче. Краще швидко переглянути знайомий матеріал, ніж пропустити базові концепції. + +> **Інтерактивна версія**: Запустіть `/self-assessment` у Claude Code для керованого інтерактивного тесту, який оцінить вашу компетенцію за всіма 10 функціональними напрямками та згенерує персоналізований навчальний план. + +--- + +## 🎯 Філософія навчання + +Каталоги в цьому репозиторії пронумеровані у **рекомендованому порядку вивчення** на основі трьох принципів: + +1. **Залежності** — Базові концепції йдуть першими +2. **Складність** — Простіші функції перед складними +3. **Частота використання** — Найпоширеніші функції вивчаються раніше + +Цей підхід забезпечує міцну основу та негайний приріст продуктивності. + +--- + +## 🗺️ Ваш навчальний шлях + +```mermaid +graph TD + Q["🧭 Self-Assessment Quiz
Find Your Level"] --> L1 + Q --> L2 + Q --> L3 + + subgraph L1["🟢 Level 1: Beginner — Getting Started"] + direction LR + A["1A: First Commands & Memory
Slash Commands + Memory"] --> B["1B: Safe Exploration
Checkpoints + CLI Basics"] + end + + subgraph L2["🔵 Level 2: Intermediate — Building Workflows"] + direction LR + C["2A: Automation
Skills + Hooks"] --> D["2B: Integration
MCP + Subagents"] + end + + subgraph L3["🔴 Level 3: Advanced — Power User"] + direction LR + E["3A: Advanced Features
Planning + Permissions"] --> F["3B: Team & Distribution
Plugins + CLI Mastery"] + end + + L1 --> L2 + L2 --> L3 + + style Q fill:#6A1B9A,color:#fff,stroke:#9C27B0,stroke-width:2px + style A fill:#2E7D32,color:#fff + style B fill:#2E7D32,color:#fff + style C fill:#1565C0,color:#fff + style D fill:#F57C00,color:#fff + style E fill:#C62828,color:#fff + style F fill:#B71C1C,color:#fff +``` + +**Легенда кольорів:** + +- 💜 Фіолетовий: Тест самооцінки +- 🟢 Зелений: Рівень 1 — Шлях початківця +- 🔵 Синій / 🟡 Золотий: Рівень 2 — Середній шлях +- 🔴 Червоний: Рівень 3 — Просунутий шлях + +--- + +## 📊 Повна таблиця навчального плану + +| Крок | Функція | Складність | Час | Рівень | Залежності | Чому вивчати | Ключові переваги | +|------|---------|-----------|-----|--------|------------|-------------|-----------------| +| **1** | [Слеш-команди](../01-slash-commands/) | ⭐ Початківець | 30 хв | Рівень 1 | Немає | Швидкий приріст продуктивності (55+ вбудованих + 5 навичок) | Миттєва автоматизація | +| **2** | [Пам'ять](../02-memory/) | ⭐⭐ Початківець+ | 45 хв | Рівень 1 | Немає | Необхідна для всіх функцій | Постійний контекст | +| **3** | [Контрольні точки](../08-checkpoints/) | ⭐⭐ Середній | 45 хв | Рівень 1 | Управління сесіями | Безпечне дослідження | Експериментування, відновлення | +| **4** | [Основи CLI](../10-cli/) | ⭐⭐ Початківець+ | 30 хв | Рівень 1 | Немає | Базове використання CLI | Інтерактивний та print mode | +| **5** | [Навички](../03-skills/) | ⭐⭐ Середній | 1 год | Рівень 2 | Слеш-команди | Автоматична експертиза | Повторювані можливості | +| **6** | [Хуки](../06-hooks/) | ⭐⭐ Середній | 1 год | Рівень 2 | Інструменти, Команди | Автоматизація процесів (25 подій, 4 типи) | Валідація, контроль якості | +| **7** | [MCP](../05-mcp/) | ⭐⭐⭐ Середній+ | 1 год | Рівень 2 | Конфігурація | Доступ до даних у реальному часі | Інтеграція, API | +| **8** | [Субагенти](../04-subagents/) | ⭐⭐⭐ Середній+ | 1.5 год | Рівень 2 | Пам'ять, Команди | Складні завдання (6 вбудованих) | Делегування, спеціалізація | +| **9** | [Розширені функції](../09-advanced-features/) | ⭐⭐⭐⭐⭐ Просунутий | 2-3 год | Рівень 3 | Усі попередні | Інструменти експерта | Планування, Auto Mode, канали | +| **10** | [Плагіни](../07-plugins/) | ⭐⭐⭐⭐ Просунутий | 2 год | Рівень 3 | Усі попередні | Комплексні рішення | Онбординг команди, дистрибуція | +| **11** | [Майстерність CLI](../10-cli/) | ⭐⭐⭐ Просунутий | 1 год | Рівень 3 | Рекомендовано: Усі | Майстерність командного рядка | Скрипти, CI/CD | + +**Загальний час навчання**: ~11-13 годин (або перейдіть на свій рівень і заощадьте час) + +--- + +## 🟢 Рівень 1: Початківець — Перші кроки + +**Для**: Користувачів з 0-2 відмітками в тесті +**Час**: ~3 години +**Фокус**: Негайна продуктивність, розуміння основ +**Результат**: Впевнений щоденний користувач, готовий до Рівня 2 + +### Етап 1A: Перші команди та пам'ять + +**Теми**: Слеш-команди + Пам'ять +**Час**: 1-2 години +**Складність**: ⭐ Початківець +**Мета**: Негайний приріст продуктивності з кастомними командами та постійним контекстом + +#### Що ви досягнете + +✅ Створення кастомних слеш-команд для повторюваних завдань +✅ Налаштування пам'яті проекту для командних стандартів +✅ Конфігурація персональних налаштувань +✅ Розуміння автоматичного завантаження контексту Claude + +#### Практичні вправи + +```bash +# Вправа 1: Встановіть першу слеш-команду +mkdir -p .claude/commands +cp 01-slash-commands/optimize.md .claude/commands/ + +# Вправа 2: Створіть пам'ять проекту +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Вправа 3: Спробуйте +# У Claude Code введіть: /optimize +``` + +#### Критерії успіху + +- [ ] Успішний виклик команди `/optimize` +- [ ] Claude пам'ятає стандарти проекту з CLAUDE.md +- [ ] Ви розумієте, коли використовувати слеш-команди, а коли пам'ять + +#### Наступні кроки + +Коли освоїтесь, прочитайте: + +- [01-slash-commands/README.md](../01-slash-commands/README.md) +- [02-memory/README.md](../02-memory/README.md) + +> **Перевірте розуміння**: Запустіть `/lesson-quiz slash-commands` або `/lesson-quiz memory` у Claude Code. + +--- + +### Етап 1B: Безпечне дослідження + +**Теми**: Контрольні точки + Основи CLI +**Час**: 1 година +**Складність**: ⭐⭐ Початківець+ +**Мета**: Навчитися безпечно експериментувати та використовувати базові команди CLI + +#### Що ви досягнете + +✅ Створення та відновлення контрольних точок для безпечних експериментів +✅ Розуміння інтерактивного та print mode +✅ Використання базових прапорців та опцій CLI +✅ Обробка файлів через пайпінг + +#### Практичні вправи + +```bash +# Вправа 1: Спробуйте процес з контрольними точками +# У Claude Code: +# Зробіть експериментальні зміни, потім натисніть Esc+Esc або /rewind +# Оберіть контрольну точку перед експериментом +# Оберіть "Restore code and conversation" для повернення + +# Вправа 2: Інтерактивний та Print mode +claude "explain this project" # Інтерактивний режим +claude -p "explain this function" # Print mode (неінтерактивний) + +# Вправа 3: Обробка вмісту файлу через пайп +cat error.log | claude -p "explain this error" +``` + +#### Критерії успіху + +- [ ] Створено та відновлено контрольну точку +- [ ] Використано інтерактивний та print mode +- [ ] Передано файл Claude для аналізу через пайп +- [ ] Розуміння використання контрольних точок для безпечних експериментів + +#### Наступні кроки + +- Прочитайте: [08-checkpoints/README.md](../08-checkpoints/README.md) +- Прочитайте: [10-cli/README.md](../10-cli/README.md) +- **Готові до Рівня 2!** Переходьте до [Етапу 2A](#етап-2a-автоматизація-навички--хуки) + +> **Перевірте розуміння**: Запустіть `/lesson-quiz checkpoints` або `/lesson-quiz cli`. + +--- + +## 🔵 Рівень 2: Середній — Побудова процесів + +**Для**: Користувачів з 3-5 відмітками в тесті +**Час**: ~5 годин +**Фокус**: Автоматизація, інтеграція, делегування завдань +**Результат**: Автоматизовані процеси, зовнішні інтеграції, готовність до Рівня 3 + +### Перевірка передумов + +Перед початком Рівня 2 переконайтеся, що ви освоїли концепції Рівня 1: + +- [ ] Вмієте створювати та використовувати слеш-команди ([01-slash-commands/](../01-slash-commands/)) +- [ ] Налаштували пам'ять проекту через CLAUDE.md ([02-memory/](../02-memory/)) +- [ ] Знаєте, як створювати та відновлювати контрольні точки ([08-checkpoints/](../08-checkpoints/)) +- [ ] Вмієте використовувати `claude` та `claude -p` з командного рядка ([10-cli/](../10-cli/)) + +> **Прогалини?** Перегляньте відповідні посібники перед продовженням. + +--- + +### Етап 2A: Автоматизація (Навички + Хуки) + +**Теми**: Навички + Хуки +**Час**: 2-3 години +**Складність**: ⭐⭐ Середній +**Мета**: Автоматизувати типові процеси та перевірки якості + +#### Що ви досягнете + +✅ Автовиклик спеціалізованих можливостей з YAML-фронтматером (включно з полями `effort` та `shell`) +✅ Налаштування автоматизації на основі подій через 25 подій хуків +✅ Використання всіх 4 типів хуків (command, http, prompt, agent) +✅ Забезпечення стандартів якості коду +✅ Створення кастомних хуків для ваших процесів + +#### Практичні вправи + +```bash +# Вправа 1: Встановіть навичку +cp -r 03-skills/code-review ~/.claude/skills/ + +# Вправа 2: Налаштуйте хуки +mkdir -p ~/.claude/hooks +cp 06-hooks/pre-tool-check.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/pre-tool-check.sh + +# Вправа 3: Налаштуйте хуки в settings +# Додайте в ~/.claude/settings.json: +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "~/.claude/hooks/pre-tool-check.sh" + } + ] + } + ] + } +} +``` + +#### Критерії успіху + +- [ ] Навичка code review автоматично викликається при потребі +- [ ] Хук PreToolUse запускається перед виконанням інструменту +- [ ] Ви розумієте різницю між автовикликом навичок та тригерами подій хуків + +#### Наступні кроки + +- Створіть власну кастомну навичку +- Налаштуйте додаткові хуки для вашого процесу +- Прочитайте: [03-skills/README.md](../03-skills/README.md) +- Прочитайте: [06-hooks/README.md](../06-hooks/README.md) + +> **Перевірте розуміння**: Запустіть `/lesson-quiz skills` або `/lesson-quiz hooks`. + +--- + +### Етап 2B: Інтеграція (MCP + Субагенти) + +**Теми**: MCP + Субагенти +**Час**: 2-3 години +**Складність**: ⭐⭐⭐ Середній+ +**Мета**: Інтегрувати зовнішні сервіси та делегувати складні завдання + +#### Що ви досягнете + +✅ Доступ до даних з GitHub, баз даних тощо в реальному часі +✅ Делегування роботи спеціалізованим AI-агентам +✅ Розуміння, коли використовувати MCP, а коли субагентів +✅ Побудова інтегрованих процесів + +#### Практичні вправи + +```bash +# Вправа 1: Налаштуйте GitHub MCP +export GITHUB_TOKEN="your_github_token" +claude mcp add github -- npx -y @modelcontextprotocol/server-github + +# Вправа 2: Перевірте MCP-інтеграцію +# У Claude Code: /mcp__github__list_prs + +# Вправа 3: Встановіть субагентів +mkdir -p .claude/agents +cp 04-subagents/*.md .claude/agents/ +``` + +#### Вправа з інтеграції + +Спробуйте повний процес: + +1. Використайте MCP для отримання GitHub PR +2. Дозвольте Claude делегувати ревʼю субагенту code-reviewer +3. Використайте хуки для автоматичного запуску тестів + +#### Критерії успіху + +- [ ] Успішний запит даних GitHub через MCP +- [ ] Claude делегує складні завдання субагентам +- [ ] Ви розумієте різницю між MCP та субагентами +- [ ] Комбінація MCP + субагенти + хуки у процесі + +#### Наступні кроки + +- Налаштуйте додаткові MCP-сервери (база даних, Slack тощо) +- Створіть кастомних субагентів для вашої предметної області +- Прочитайте: [05-mcp/README.md](../05-mcp/README.md) +- Прочитайте: [04-subagents/README.md](../04-subagents/README.md) +- **Готові до Рівня 3!** Переходьте до [Етапу 3A](#етап-3a-розширені-функції) + +> **Перевірте розуміння**: Запустіть `/lesson-quiz mcp` або `/lesson-quiz subagents`. + +--- + +## 🔴 Рівень 3: Просунутий — Досвідчений користувач та тімлід + +**Для**: Користувачів з 6-8 відмітками в тесті +**Час**: ~5 годин +**Фокус**: Командні інструменти, CI/CD, enterprise-функції, розробка плагінів +**Результат**: Досвідчений користувач, здатний налаштувати командні процеси та CI/CD + +### Перевірка передумов + +Перед початком Рівня 3 переконайтеся, що ви освоїли концепції Рівня 2: + +- [ ] Вмієте створювати та використовувати навички з автовикликом ([03-skills/](../03-skills/)) +- [ ] Налаштували хуки для автоматизації на основі подій ([06-hooks/](../06-hooks/)) +- [ ] Вмієте конфігурувати MCP-сервери для зовнішніх даних ([05-mcp/](../05-mcp/)) +- [ ] Знаєте, як використовувати субагентів для делегування ([04-subagents/](../04-subagents/)) + +> **Прогалини?** Перегляньте відповідні посібники перед продовженням. + +--- + +### Етап 3A: Розширені функції + +**Теми**: Розширені функції (Планування, Дозволи, Розширене мислення, Auto Mode, Канали, Голосовий ввід, Віддалене/Десктоп/Веб) +**Час**: 2-3 години +**Складність**: ⭐⭐⭐⭐⭐ Просунутий +**Мета**: Опанувати розширені процеси та інструменти експерта + +#### Що ви досягнете + +✅ Режим планування для складних функцій +✅ Точний контроль дозволів з 6 режимами (default, acceptEdits, plan, auto, dontAsk, bypassPermissions) +✅ Розширене мислення через Alt+T / Option+T +✅ Управління фоновими завданнями +✅ Автопам'ять для вивчених налаштувань +✅ Auto Mode з фоновим класифікатором безпеки +✅ Канали для структурованих багатосесійних процесів +✅ Голосовий ввід для роботи без клавіатури +✅ Віддалене керування, десктопний застосунок та веб-сесії +✅ Команди агентів для багатоагентної співпраці + +#### Практичні вправи + +```bash +# Вправа 1: Режим планування +/plan Implement user authentication system + +# Вправа 2: Режими дозволів (6 доступних: default, acceptEdits, plan, auto, dontAsk, bypassPermissions) +claude --permission-mode plan "analyze this codebase" +claude --permission-mode acceptEdits "refactor the auth module" +claude --permission-mode auto "implement the feature" + +# Вправа 3: Розширене мислення +# Натисніть Alt+T (Option+T на macOS) під час сесії для перемикання + +# Вправа 4: Розширений процес з контрольними точками +# 1. Створіть контрольну точку "Clean state" +# 2. Використайте режим планування для проєктування функції +# 3. Реалізуйте з делегуванням субагенту +# 4. Запустіть тести у фоні +# 5. Якщо тести не пройшли — відкат до контрольної точки +# 6. Спробуйте альтернативний підхід + +# Вправа 5: Auto mode (фоновий класифікатор безпеки) +claude --permission-mode auto "implement user settings page" + +# Вправа 6: Команди агентів +export CLAUDE_AGENT_TEAMS=1 +# Попросіть Claude: "Implement feature X using a team approach" + +# Вправа 7: Заплановані завдання +/loop 5m /check-status +# Або CronCreate для постійних запланованих завдань + +# Вправа 8: Канали для багатосесійних процесів +# Використовуйте канали для організації роботи між сесіями + +# Вправа 9: Голосовий ввід +# Використовуйте голосовий ввід для роботи без клавіатури з Claude Code +``` + +#### Критерії успіху + +- [ ] Використано режим планування для складної функції +- [ ] Налаштовано режими дозволів (plan, acceptEdits, auto, dontAsk) +- [ ] Увімкнено розширене мислення з Alt+T / Option+T +- [ ] Використано auto mode з класифікатором безпеки +- [ ] Використано фонові завдання для тривалих операцій +- [ ] Досліджено канали для багатосесійних процесів +- [ ] Спробовано голосовий ввід +- [ ] Розуміння віддаленого керування, десктопного застосунку та веб-сесій +- [ ] Увімкнено та використано команди агентів для спільних завдань +- [ ] Використано `/loop` для повторюваних завдань або моніторингу + +#### Наступні кроки + +- Прочитайте: [09-advanced-features/README.md](../09-advanced-features/README.md) + +> **Перевірте розуміння**: Запустіть `/lesson-quiz advanced`. + +--- + +### Етап 3B: Команда та дистрибуція (Плагіни + Майстерність CLI) + +**Теми**: Плагіни + Майстерність CLI + CI/CD +**Час**: 2-3 години +**Складність**: ⭐⭐⭐⭐ Просунутий +**Мета**: Створення командних інструментів, плагінів, майстерність CI/CD-інтеграції + +#### Що ви досягнете + +✅ Встановлення та створення повних плагінів +✅ Майстерність CLI для скриптів та автоматизації +✅ Налаштування CI/CD-інтеграції з `claude -p` +✅ JSON-вивід для автоматизованих пайплайнів +✅ Управління сесіями та пакетна обробка + +#### Практичні вправи + +```bash +# Вправа 1: Встановіть повний плагін +# У Claude Code: /plugin install pr-review + +# Вправа 2: Print mode для CI/CD +claude -p "Run all tests and generate report" + +# Вправа 3: JSON-вивід для скриптів +claude -p --output-format json "list all functions" + +# Вправа 4: Управління сесіями та відновлення +claude -r "feature-auth" "continue implementation" + +# Вправа 5: CI/CD-інтеграція з обмеженнями +claude -p --max-turns 3 --output-format json "review code" + +# Вправа 6: Пакетна обробка +for file in *.md; do + claude -p --output-format json "summarize this: $(cat $file)" > ${file%.md}.summary.json +done +``` + +#### Вправа з CI/CD-інтеграції + +Створіть простий CI/CD-скрипт: + +1. Використайте `claude -p` для ревʼю змінених файлів +2. Виведіть результати як JSON +3. Обробіть з `jq` для конкретних проблем +4. Інтегруйте в GitHub Actions workflow + +#### Критерії успіху + +- [ ] Встановлено та використано плагін +- [ ] Створено або модифіковано плагін для команди +- [ ] Використано print mode (`claude -p`) в CI/CD +- [ ] Згенеровано JSON-вивід для скриптів +- [ ] Відновлено попередню сесію +- [ ] Створено скрипт пакетної обробки +- [ ] Інтегровано Claude в CI/CD-процес + +#### Реальні сценарії для CLI + +- **Автоматизація ревʼю коду**: Запуск ревʼю в CI/CD-пайплайнах +- **Аналіз логів**: Аналіз журналів помилок та системних виводів +- **Генерація документації**: Пакетна генерація документації +- **Інсайти тестування**: Аналіз невдалих тестів +- **Аналіз продуктивності**: Перегляд метрик продуктивності +- **Обробка даних**: Трансформація та аналіз файлів даних + +#### Наступні кроки + +- Прочитайте: [07-plugins/README.md](../07-plugins/README.md) +- Прочитайте: [10-cli/README.md](../10-cli/README.md) +- Створіть командні CLI-ярлики та плагіни +- Налаштуйте скрипти пакетної обробки + +> **Перевірте розуміння**: Запустіть `/lesson-quiz plugins` або `/lesson-quiz cli`. + +--- + +## 🧪 Перевірте свої знання + +Цей репозиторій включає дві інтерактивні навички для оцінки розуміння: + +| Навичка | Команда | Призначення | +|---------|---------|-------------| +| **Самооцінка** | `/self-assessment` | Оцінка загальної компетенції за всіма 10 функціями. Оберіть швидкий (2 хв) або глибокий (5 хв) режим для персоналізованого профілю. | +| **Тест уроку** | `/lesson-quiz [урок]` | Перевірка розуміння конкретного уроку з 10 питаннями. Використовуйте перед уроком (пре-тест), під час (перевірка) або після (верифікація). | + +**Приклади:** + +``` +/self-assessment # Визначити загальний рівень +/lesson-quiz hooks # Тест з Уроку 06: Хуки +/lesson-quiz 03 # Тест з Уроку 03: Навички +/lesson-quiz advanced-features # Тест з Уроку 09 +``` + +--- + +## ⚡ Швидкі шляхи + +### Якщо у вас лише 15 хвилин + +**Мета**: Отримати перший результат + +1. Скопіюйте одну слеш-команду: `cp 01-slash-commands/optimize.md .claude/commands/` +2. Спробуйте в Claude Code: `/optimize` +3. Прочитайте: [01-slash-commands/README.md](../01-slash-commands/README.md) + +**Результат**: Робоча слеш-команда та розуміння основ + +--- + +### Якщо у вас 1 година + +**Мета**: Налаштувати основні інструменти продуктивності + +1. **Слеш-команди** (15 хв): Скопіюйте та протестуйте `/optimize` та `/pr` +2. **Пам'ять проекту** (15 хв): Створіть CLAUDE.md зі стандартами проекту +3. **Навичка** (15 хв): Встановіть навичку code-review +4. **Спробуйте разом** (15 хв): Подивіться, як вони працюють у зв'язці + +**Результат**: Базовий приріст продуктивності з командами, пам'яттю та автонавичками + +--- + +### Якщо у вас є вихідні + +**Мета**: Стати компетентним у більшості функцій + +**Субота вранці** (3 години): + +- Завершити Етап 1A: Слеш-команди + Пам'ять +- Завершити Етап 1B: Контрольні точки + Основи CLI + +**Субота вдень** (3 години): + +- Завершити Етап 2A: Навички + Хуки +- Завершити Етап 2B: MCP + Субагенти + +**Неділя** (4 години): + +- Завершити Етап 3A: Розширені функції +- Завершити Етап 3B: Плагіни + Майстерність CLI + CI/CD +- Створити кастомний плагін для команди + +**Результат**: Ви станете досвідченим користувачем Claude Code, готовим навчати інших та автоматизувати складні процеси + +--- + +## 💡 Поради з навчання + +### ✅ Робіть + +- **Пройдіть тест спочатку**, щоб знайти відправну точку +- **Виконуйте практичні вправи** для кожного етапу +- **Починайте просто** та додавайте складність поступово +- **Тестуйте кожну функцію** перед переходом до наступної +- **Робіть нотатки** про те, що працює для вашого процесу +- **Повертайтесь** до попередніх концепцій при вивченні просунутих тем +- **Експериментуйте безпечно** з контрольними точками +- **Діліться знаннями** з командою + +### ❌ Не робіть + +- **Не пропускайте перевірку передумов** при переході на вищий рівень +- **Не намагайтесь вивчити все одразу** — це перевантажує +- **Не копіюйте конфігурації без розуміння** — не зможете налагодити +- **Не забувайте тестувати** — завжди перевіряйте роботу +- **Не поспішайте з етапами** — приділіть час для розуміння +- **Не ігноруйте документацію** — кожен README містить цінні деталі +- **Не працюйте ізольовано** — обговорюйте з колегами + +--- + +## 🎓 Стилі навчання + +### Візуальні учні + +- Вивчайте діаграми mermaid у кожному README +- Спостерігайте за потоком виконання команд +- Малюйте власні діаграми процесів +- Використовуйте візуальний навчальний шлях вище + +### Практики + +- Виконуйте кожну практичну вправу +- Експериментуйте з варіаціями +- Ламайте та лагодьте (використовуйте контрольні точки!) +- Створюйте власні приклади + +### Читачі + +- Уважно читайте кожен README +- Вивчайте приклади коду +- Переглядайте порівняльні таблиці +- Читайте блог-пости з ресурсів + +### Соціальні учні + +- Організуйте сесії парного програмування +- Навчайте концепцій колег +- Долучайтесь до обговорень спільноти Claude Code +- Діліться кастомними конфігураціями + +--- + +## 📈 Відстеження прогресу + +Використовуйте ці чеклісти для відстеження прогресу за рівнями. Запустіть `/self-assessment` у будь-який час для оновленого профілю, або `/lesson-quiz [урок]` після кожного посібника для перевірки розуміння. + +### 🟢 Рівень 1: Початківець + +- [ ] Завершено [01-slash-commands](../01-slash-commands/) +- [ ] Завершено [02-memory](../02-memory/) +- [ ] Створено першу кастомну слеш-команду +- [ ] Налаштовано пам'ять проекту +- [ ] **Етап 1A досягнуто** +- [ ] Завершено [08-checkpoints](../08-checkpoints/) +- [ ] Завершено основи [10-cli](../10-cli/) +- [ ] Створено та відновлено контрольну точку +- [ ] Використано інтерактивний та print mode +- [ ] **Етап 1B досягнуто** + +### 🔵 Рівень 2: Середній + +- [ ] Завершено [03-skills](../03-skills/) +- [ ] Завершено [06-hooks](../06-hooks/) +- [ ] Встановлено першу навичку +- [ ] Налаштовано хук PreToolUse +- [ ] **Етап 2A досягнуто** +- [ ] Завершено [05-mcp](../05-mcp/) +- [ ] Завершено [04-subagents](../04-subagents/) +- [ ] Підключено GitHub MCP +- [ ] Створено кастомного субагента +- [ ] Комбіновано інтеграції у процесі +- [ ] **Етап 2B досягнуто** + +### 🔴 Рівень 3: Просунутий + +- [ ] Завершено [09-advanced-features](../09-advanced-features/) +- [ ] Використано режим планування +- [ ] Налаштовано режими дозволів (6 режимів включно з auto) +- [ ] Використано auto mode з класифікатором безпеки +- [ ] Увімкнено розширене мислення +- [ ] Досліджено канали та голосовий ввід +- [ ] **Етап 3A досягнуто** +- [ ] Завершено [07-plugins](../07-plugins/) +- [ ] Завершено розширене використання [10-cli](../10-cli/) +- [ ] Налаштовано print mode (`claude -p`) CI/CD +- [ ] Створено JSON-вивід для автоматизації +- [ ] Інтегровано Claude в CI/CD-пайплайн +- [ ] Створено командний плагін +- [ ] **Етап 3B досягнуто** + +--- + +## 🆘 Типові труднощі навчання + +### Труднощі 1: "Забагато концепцій одразу" + +**Рішення**: Зосередьтесь на одному етапі за раз. Завершіть усі вправи перед переходом далі. + +### Труднощі 2: "Не знаю, яку функцію використати" + +**Рішення**: Зверніться до [Матриці сценаріїв](../README.md#use-case-matrix) у головному README. + +### Труднощі 3: "Конфігурація не працює" + +**Рішення**: Перевірте розділ [Усунення неполадок](../README.md#troubleshooting) та перевірте розташування файлів. + +### Труднощі 4: "Концепції здаються схожими" + +**Рішення**: Перегляньте таблицю [Порівняння функцій](../README.md#feature-comparison) для розуміння відмінностей. + +### Труднощі 5: "Важко все запам'ятати" + +**Рішення**: Створіть власну шпаргалку. Використовуйте контрольні точки для безпечних експериментів. + +### Труднощі 6: "Я досвідчений, але не знаю з чого почати" + +**Рішення**: Пройдіть [Тест самооцінки](#-визначте-свій-рівень) вище. Перейдіть на свій рівень та використовуйте перевірку передумов для виявлення прогалин. + +--- + +## 🎯 Що далі після завершення? + +Після завершення всіх етапів: + +1. **Створіть командну документацію** — задокументуйте налаштування Claude Code вашої команди +2. **Створіть кастомні плагіни** — запакуйте процеси команди +3. **Дослідіть віддалене керування** — керуйте сесіями програмно +4. **Спробуйте веб-сесії** — використовуйте Claude Code через браузер +5. **Використовуйте десктопний застосунок** — нативний десктопний доступ +6. **Використовуйте Auto Mode** — автономна робота з класифікатором безпеки +7. **Використовуйте автопам'ять** — Claude автоматично вивчає ваші налаштування +8. **Налаштуйте команди агентів** — координуйте кількох агентів для складних завдань +9. **Використовуйте канали** — організуйте роботу між сесіями +10. **Спробуйте голосовий ввід** — робота без клавіатури +11. **Використовуйте заплановані завдання** — автоматизуйте з `/loop` та cron +12. **Додавайте приклади** — діліться зі спільнотою +13. **Менторіть інших** — допомагайте колегам навчатися +14. **Оптимізуйте процеси** — постійно покращуйте на основі досвіду +15. **Слідкуйте за оновленнями** — відстежуйте релізи та нові функції + +--- + +## 📚 Додаткові ресурси + +### Офіційна документація + +- [Документація Claude Code](https://code.claude.com/docs/en/overview) +- [Документація Anthropic](https://docs.anthropic.com) +- [Специфікація MCP](https://modelcontextprotocol.io) + +### Блог-пости + +- [Discovering Claude Code Slash Commands](https://medium.com/@luongnv89/discovering-claude-code-slash-commands-cdc17f0dfb29) + +### Спільнота + +- [Anthropic Cookbook](https://github.com/anthropics/anthropic-cookbook) +- [Репозиторій MCP-серверів](https://github.com/modelcontextprotocol/servers) + +--- + +## 💬 Зворотний зв'язок та підтримка + +- **Знайшли проблему?** Створіть issue в репозиторії +- **Маєте пропозицію?** Надішліть pull request +- **Потрібна допомога?** Перевірте документацію або запитайте спільноту + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Підтримується**: Контриб'ютори Claude How-To +**Ліцензія**: Освітні цілі, вільне використання та адаптація + +--- + +[← Повернутися до головного README](README.md) From 8684be223d8acfb2e928889201f78f33ad257535 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 13:45:06 +0300 Subject: [PATCH 06/20] feat(uk): translate Module 01 and Module 08 READMEs Module 01: Slash Commands (565 lines) Module 08: Checkpoints and Rewind (320 lines) Update TRANSLATION_QUEUE.md with P1 completion. Progress: 7/67 files (P1: 5/5 DONE, P2: 2/10) Ref: luongnv89/claude-howto#63 --- uk/01-slash-commands/README.md | 585 +++++++++++++++++++++++++++++++++ uk/08-checkpoints/README.md | 335 +++++++++++++++++++ uk/TRANSLATION_QUEUE.md | 119 ++----- 3 files changed, 946 insertions(+), 93 deletions(-) create mode 100644 uk/01-slash-commands/README.md create mode 100644 uk/08-checkpoints/README.md diff --git a/uk/01-slash-commands/README.md b/uk/01-slash-commands/README.md new file mode 100644 index 0000000..0429321 --- /dev/null +++ b/uk/01-slash-commands/README.md @@ -0,0 +1,585 @@ + + + + + + + Claude How To + + +# Слеш-команди + +## Огляд + +Слеш-команди — це ярлики, що керують поведінкою Claude під час інтерактивної сесії. Вони бувають кількох типів: + +- **Вбудовані команди**: Надаються Claude Code (`/help`, `/clear`, `/model`) +- **Навички (Skills)**: Користувацькі команди, створені як файли `SKILL.md` (`/optimize`, `/pr`) +- **Команди плагінів**: Команди з встановлених плагінів (`/frontend-design:frontend-design`) +- **MCP-промпти**: Команди з MCP-серверів (`/mcp__github__list_prs`) + +> **Примітка**: Кастомні слеш-команди об'єднані з навичками. Файли в `.claude/commands/` все ще працюють, але навички (`.claude/skills/`) — рекомендований підхід. Обидва створюють ярлики `/command-name`. Див. [Посібник з навичок](../03-skills/) для повного довідника. + +## Довідник вбудованих команд + +Вбудовані команди — це ярлики для типових дій. Доступно **60+ вбудованих команд** та **5 вбудованих навичок**. Введіть `/` у Claude Code для повного списку, або `/` з літерами для фільтрації. + +| Команда | Призначення | +|---------|------------| +| `/add-dir ` | Додати робочий каталог | +| `/agents` | Управління конфігураціями агентів | +| `/branch [name]` | Розгалужити розмову в нову сесію (аліас: `/fork`). Примітка: `/fork` перейменовано на `/branch` у v2.1.77 | +| `/btw ` | Побічне запитання без додавання в історію | +| `/chrome` | Налаштування інтеграції з Chrome | +| `/clear` | Очистити розмову (аліаси: `/reset`, `/new`) | +| `/color [color\|default]` | Встановити колір рядка промпту | +| `/compact [instructions]` | Компактизувати розмову з необов'язковими інструкціями фокусу | +| `/config` | Відкрити налаштування (аліас: `/settings`) | +| `/context` | Візуалізація використання контексту кольоровою сіткою | +| `/copy [N]` | Скопіювати відповідь у буфер; `w` записує у файл | +| `/cost` | Показати статистику використання токенів | +| `/desktop` | Продовжити в десктопному застосунку (аліас: `/app`) | +| `/diff` | Інтерактивний перегляд незакомічених змін | +| `/doctor` | Діагностика стану встановлення | +| `/effort [low\|medium\|high\|max\|auto]` | Встановити рівень зусиль. `max` потребує Opus 4.6 | +| `/exit` | Вийти з REPL (аліас: `/quit`) | +| `/export [filename]` | Експортувати розмову у файл або буфер | +| `/extra-usage` | Налаштування додаткового використання для лімітів | +| `/fast [on\|off]` | Перемкнути швидкий режим | +| `/feedback` | Надіслати відгук (аліас: `/bug`) | +| `/help` | Показати довідку | +| `/hooks` | Переглянути конфігурації хуків | +| `/ide` | Управління IDE-інтеграціями | +| `/init` | Ініціалізувати `CLAUDE.md`. `CLAUDE_CODE_NEW_INIT=1` для інтерактивного потоку | +| `/insights` | Згенерувати звіт аналізу сесії | +| `/install-github-app` | Налаштувати GitHub Actions | +| `/install-slack-app` | Встановити Slack-застосунок | +| `/keybindings` | Відкрити налаштування клавіш | +| `/login` | Змінити обліковий запис Anthropic | +| `/logout` | Вийти з облікового запису Anthropic | +| `/mcp` | Управління MCP-серверами та OAuth | +| `/memory` | Редагувати `CLAUDE.md`, перемкнути автопам'ять | +| `/mobile` | QR-код для мобільного (аліаси: `/ios`, `/android`) | +| `/model [model]` | Вибір моделі зі стрілками вліво/вправо для рівня зусиль | +| `/passes` | Поділитися безкоштовним тижнем Claude Code | +| `/permissions` | Переглянути/оновити дозволи (аліас: `/allowed-tools`) | +| `/plan [description]` | Увійти в режим планування | +| `/plugin` | Управління плагінами | +| `/powerup` | Інтерактивні уроки з анімованими демо | +| `/privacy-settings` | Налаштування приватності (Pro/Max) | +| `/release-notes` | Переглянути журнал змін | +| `/reload-plugins` | Перезавантажити активні плагіни | +| `/remote-control` | Віддалене керування з claude.ai (аліас: `/rc`) | +| `/remote-env` | Налаштування стандартного віддаленого середовища | +| `/rename [name]` | Перейменувати сесію | +| `/resume [session]` | Відновити розмову (аліас: `/continue`) | +| `/review` | **Застаріла** — встановіть плагін `code-review` | +| `/rewind` | Відкат розмови та/або коду (аліас: `/checkpoint`) | +| `/sandbox` | Перемкнути режим пісочниці | +| `/schedule [description]` | Створити/управляти хмарними запланованими завданнями | +| `/security-review` | Аналіз гілки на вразливості безпеки | +| `/skills` | Список доступних навичок | +| `/stats` | Візуалізація щоденного використання, сесій, серій | +| `/stickers` | Замовити стікери Claude Code | +| `/status` | Показати версію, модель, обліковий запис | +| `/statusline` | Налаштування рядка стану | +| `/tasks` | Список/управління фоновими завданнями | +| `/terminal-setup` | Налаштування клавіш терміналу | +| `/theme` | Змінити колірну тему | +| `/ultraplan ` | Створити план в ultraplan-сесії, переглянути в браузері | +| `/upgrade` | Відкрити сторінку оновлення тарифу | +| `/usage` | Показати ліміти плану та статус обмежень | +| `/voice` | Перемкнути голосовий ввід push-to-talk | + +### Вбудовані навички + +Ці навички поставляються з Claude Code і викликаються як слеш-команди: + +| Навичка | Призначення | +|---------|------------| +| `/batch ` | Оркестрація масштабних паралельних змін через worktrees | +| `/claude-api` | Завантажити довідник Claude API для мови проекту | +| `/debug [description]` | Увімкнути налагоджувальне логування | +| `/loop [interval] ` | Запускати промпт повторно за інтервалом | +| `/simplify [focus]` | Перевірити змінені файли на якість коду | + +### Застарілі команди + +| Команда | Статус | +|---------|--------| +| `/review` | Застаріла — замінена плагіном `code-review` | +| `/output-style` | Застаріла з v2.1.73 | +| `/fork` | Перейменована на `/branch` (аліас працює, v2.1.77) | +| `/pr-comments` | Видалена в v2.1.91 — запитайте Claude напряму | +| `/vim` | Видалена в v2.1.92 — використовуйте /config → Editor mode | + +### Останні зміни + +- `/fork` перейменовано на `/branch`, `/fork` залишено як аліас (v2.1.77) +- `/output-style` застаріла (v2.1.73) +- `/review` застаріла на користь плагіна `code-review` +- Додано команду `/effort` з рівнем `max` для Opus 4.6 +- Додано команду `/voice` для голосового вводу push-to-talk +- Додано команду `/schedule` для запланованих завдань +- Додано команду `/color` для кастомізації рядка промпту +- `/pr-comments` видалена в v2.1.91 +- `/vim` видалена в v2.1.92 +- Додано `/ultraplan` для перегляду плану в браузері +- Додано `/powerup` для інтерактивних уроків +- Додано `/sandbox` для режиму пісочниці +- Вибір `/model` тепер показує зрозумілі назви (наприклад, "Sonnet 4.6") замість ID моделей +- `/resume` підтримує аліас `/continue` +- MCP-промпти доступні як команди `/mcp____` (див. [MCP-промпти як команди](#mcp-промпти-як-команди)) + +## Кастомні команди (тепер навички) + +Кастомні слеш-команди **об'єднані з навичками**. Обидва підходи створюють команди, які викликаються через `/command-name`: + +| Підхід | Розташування | Статус | +|--------|-------------|--------| +| **Навички (Рекомендовано)** | `.claude/skills//SKILL.md` | Поточний стандарт | +| **Legacy-команди** | `.claude/commands/.md` | Все ще працює | + +Якщо навичка і команда мають однакове ім'я, **навичка має пріоритет**. Наприклад, коли існують і `.claude/commands/review.md`, і `.claude/skills/review/SKILL.md`, використовується версія навички. + +### Шлях міграції + +Існуючі файли `.claude/commands/` продовжують працювати без змін. Для міграції на навички: + +**До (Команда):** + +``` +.claude/commands/optimize.md +``` + +**Після (Навичка):** + +``` +.claude/skills/optimize/SKILL.md +``` + +### Чому навички? + +Навички пропонують додаткові можливості порівняно з legacy-командами: + +- **Структура каталогів**: Пакування скриптів, шаблонів та довідкових файлів +- **Автовиклик**: Claude може запускати навички автоматично за потреби +- **Контроль виклику**: Вибір — користувач, Claude, або обидва можуть викликати +- **Виконання в субагенті**: Запуск навичок в ізольованих контекстах з `context: fork` +- **Прогресивне розкриття**: Завантаження додаткових файлів лише за потреби + +### Створення кастомної команди як навички + +Створіть каталог з файлом `SKILL.md`: + +```bash +mkdir -p .claude/skills/my-command +``` + +**Файл:** `.claude/skills/my-command/SKILL.md` + +```yaml +--- +name: my-command +description: Що робить ця команда і коли її використовувати +--- + +# My Command + +Інструкції для Claude при виклику цієї команди. + +1. Перший крок +2. Другий крок +3. Третій крок +``` + +### Довідник фронтматеру + +| Поле | Призначення | За замовчуванням | +|------|------------|-----------------| +| `name` | Ім'я команди (стає `/name`) | Ім'я каталогу | +| `description` | Короткий опис (допомагає Claude знати коли використовувати) | Перший абзац | +| `argument-hint` | Очікувані аргументи для автодоповнення | Немає | +| `allowed-tools` | Інструменти без запиту дозволу | Успадковується | +| `model` | Конкретна модель для використання | Успадковується | +| `disable-model-invocation` | Якщо `true`, тільки користувач може викликати | `false` | +| `user-invocable` | Якщо `false`, сховати з меню `/` | `true` | +| `context` | `fork` для запуску в ізольованому субагенті | Немає | +| `agent` | Тип агента при `context: fork` | `general-purpose` | +| `hooks` | Хуки на рівні навички (PreToolUse, PostToolUse, Stop) | Немає | + +### Аргументи + +Команди можуть отримувати аргументи: + +**Усі аргументи з `$ARGUMENTS`:** + +```yaml +--- +name: fix-issue +description: Fix a GitHub issue by number +--- + +Fix issue #$ARGUMENTS following our coding standards +``` + +Використання: `/fix-issue 123` → `$ARGUMENTS` стає "123" + +**Окремі аргументи з `$0`, `$1` тощо:** + +```yaml +--- +name: review-pr +description: Review a PR with priority +--- + +Review PR #$0 with priority $1 +``` + +Використання: `/review-pr 456 high` → `$0`="456", `$1`="high" + +### Динамічний контекст з shell-командами + +Виконуйте bash-команди перед промптом з допомогою `` !`command` ``: + +```yaml +--- +name: commit +description: Create a git commit with context +allowed-tools: Bash(git *) +--- + +## Context + +- Current git status: !`git status` +- Current git diff: !`git diff HEAD` +- Current branch: !`git branch --show-current` +- Recent commits: !`git log --oneline -5` + +## Your task + +Based on the above changes, create a single git commit. +``` + +### Посилання на файли + +Включайте вміст файлів з `@`: + +```markdown +Review the implementation in @src/utils/helpers.js +Compare @src/old-version.js with @src/new-version.js +``` + +## Команди плагінів + +Плагіни можуть надавати кастомні команди: + +``` +/plugin-name:command-name +``` + +Або просто `/command-name`, якщо немає конфліктів імен. + +**Приклади:** + +```bash +/frontend-design:frontend-design +/commit-commands:commit +``` + +## MCP-промпти як команди + +MCP-сервери можуть надавати промпти як слеш-команди: + +``` +/mcp____ [arguments] +``` + +**Приклади:** + +```bash +/mcp__github__list_prs +/mcp__github__pr_review 456 +/mcp__jira__create_issue "Bug title" high +``` + +### Синтаксис дозволів MCP + +Контроль доступу до MCP-серверів у дозволах: + +- `mcp__github` — Доступ до всього GitHub MCP-сервера +- `mcp__github__*` — Wildcard-доступ до всіх інструментів +- `mcp__github__get_issue` — Доступ до конкретного інструменту + +## Архітектура команд + +```mermaid +graph TD + A["User Input: /command-name"] --> B{"Command Type?"} + B -->|Built-in| C["Execute Built-in"] + B -->|Skill| D["Load SKILL.md"] + B -->|Plugin| E["Load Plugin Command"] + B -->|MCP| F["Execute MCP Prompt"] + + D --> G["Parse Frontmatter"] + G --> H["Substitute Variables"] + H --> I["Execute Shell Commands"] + I --> J["Send to Claude"] + J --> K["Return Results"] +``` + +## Життєвий цикл команди + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant FS as File System + participant CLI as Shell/Bash + + User->>Claude: Types /optimize + Claude->>FS: Searches .claude/skills/ and .claude/commands/ + FS-->>Claude: Returns optimize/SKILL.md + Claude->>Claude: Parses frontmatter + Claude->>CLI: Executes !`command` substitutions + CLI-->>Claude: Command outputs + Claude->>Claude: Substitutes $ARGUMENTS + Claude->>User: Processes prompt + Claude->>User: Returns results +``` + +## Доступні команди в цьому каталозі + +Ці приклади команд можна встановити як навички або legacy-команди. + +### 1. `/optimize` — Оптимізація коду + +Аналізує код на проблеми продуктивності, витоки пам'яті та можливості оптимізації. + +**Використання:** + +``` +/optimize +[Вставте ваш код] +``` + +### 2. `/pr` — Підготовка Pull Request + +Проводить через чекліст підготовки PR, включаючи лінтинг, тестування та форматування комітів. + +**Використання:** + +``` +/pr +``` + +**Скріншот:** +![/pr](../../01-slash-commands/pr-slash-command.png) + +### 3. `/generate-api-docs` — Генератор API-документації + +Генерує комплексну API-документацію з вихідного коду. + +**Використання:** + +``` +/generate-api-docs +``` + +### 4. `/commit` — Git-коміт з контекстом + +Створює git-коміт з динамічним контекстом вашого репозиторію. + +**Використання:** + +``` +/commit [необов'язкове повідомлення] +``` + +### 5. `/push-all` — Stage, Commit та Push + +Stage всіх змін, створення коміту та push на remote з перевірками безпеки. + +**Використання:** + +``` +/push-all +``` + +**Перевірки безпеки:** + +- Секрети: `.env*`, `*.key`, `*.pem`, `credentials.json` +- API-ключі: Виявлення реальних ключів vs. заповнювачів +- Великі файли: `>10MB` без Git LFS +- Артефакти збірки: `node_modules/`, `dist/`, `__pycache__/` + +### 6. `/doc-refactor` — Реструктуризація документації + +Реструктуризує документацію проекту для ясності та доступності. + +**Використання:** + +``` +/doc-refactor +``` + +### 7. `/setup-ci-cd` — Налаштування CI/CD-пайплайну + +Впроваджує pre-commit хуки та GitHub Actions для контролю якості. + +**Використання:** + +``` +/setup-ci-cd +``` + +### 8. `/unit-test-expand` — Розширення покриття тестами + +Збільшує покриття тестами, націлюючись на непротестовані гілки та крайові випадки. + +**Використання:** + +``` +/unit-test-expand +``` + +## Встановлення + +### Як навички (Рекомендовано) + +Скопіюйте у каталог навичок: + +```bash +# Створити каталог навичок +mkdir -p .claude/skills + +# Для кожного файлу команди створити каталог навички +for cmd in optimize pr commit; do + mkdir -p .claude/skills/$cmd + cp 01-slash-commands/$cmd.md .claude/skills/$cmd/SKILL.md +done +``` + +### Як legacy-команди + +Скопіюйте у каталог команд: + +```bash +# На рівні проекту (команда) +mkdir -p .claude/commands +cp 01-slash-commands/*.md .claude/commands/ + +# Персональне використання +mkdir -p ~/.claude/commands +cp 01-slash-commands/*.md ~/.claude/commands/ +``` + +## Створення власних команд + +### Шаблон навички (Рекомендовано) + +Створіть `.claude/skills/my-command/SKILL.md`: + +```yaml +--- +name: my-command +description: What this command does. Use when [trigger conditions]. +argument-hint: [optional-args] +allowed-tools: Bash(npm *), Read, Grep +--- + +# Command Title + +## Context + +- Current branch: !`git branch --show-current` +- Related files: @package.json + +## Instructions + +1. First step +2. Second step with argument: $ARGUMENTS +3. Third step + +## Output Format + +- How to format the response +- What to include +``` + +### Команда лише для користувача (без автовиклику) + +Для команд з побічними ефектами, які Claude не повинен запускати автоматично: + +```yaml +--- +name: deploy +description: Deploy to production +disable-model-invocation: true +allowed-tools: Bash(npm *), Bash(git *) +--- + +Deploy the application to production: + +1. Run tests +2. Build application +3. Push to deployment target +4. Verify deployment +``` + +## Найкращі практики + +| Робіть | Не робіть | +|--------|-----------| +| Використовуйте чіткі, орієнтовані на дію назви | Не створюйте команди для одноразових завдань | +| Додавайте `description` з умовами тригеру | Не вбудовуйте складну логіку в команди | +| Тримайте команди зосередженими на одному завданні | Не хардкодьте чутливу інформацію | +| Використовуйте `disable-model-invocation` для побічних ефектів | Не пропускайте поле description | +| Використовуйте `!` для динамічного контексту | Не вважайте, що Claude знає поточний стан | +| Організуйте пов'язані файли в каталогах навичок | Не кладіть все в один файл | + +## Усунення неполадок + +### Команда не знайдена + +**Рішення:** + +- Перевірте, що файл у `.claude/skills//SKILL.md` або `.claude/commands/.md` +- Перевірте поле `name` у фронтматері +- Перезапустіть сесію Claude Code +- Запустіть `/help` для перегляду доступних команд + +### Команда працює не як очікувалось + +**Рішення:** + +- Додайте більш конкретні інструкції +- Включіть приклади у файл навички +- Перевірте `allowed-tools` при використанні bash-команд +- Спочатку тестуйте з простими вхідними даними + +### Конфлікт навички та команди + +Якщо обидві існують з однаковим ім'ям, **навичка має пріоритет**. Видаліть одну або перейменуйте. + +## Пов'язані посібники + +- **[Навички](../03-skills/)** — Повний довідник навичок (автоматично викликані можливості) +- **[Пам'ять](../02-memory/)** — Постійний контекст з CLAUDE.md +- **[Субагенти](../04-subagents/)** — Делеговані AI-агенти +- **[Плагіни](../07-plugins/)** — Пакетні набори команд +- **[Хуки](../06-hooks/)** — Автоматизація на основі подій + +## Додаткові ресурси + +- [Офіційна документація інтерактивного режиму](https://code.claude.com/docs/en/interactive-mode) — Довідник вбудованих команд +- [Офіційна документація навичок](https://code.claude.com/docs/en/skills) — Повний довідник навичок +- [Довідник CLI](https://code.claude.com/docs/en/cli-reference) — Опції командного рядка + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 + +*Частина серії посібників [Claude How To](../)* diff --git a/uk/08-checkpoints/README.md b/uk/08-checkpoints/README.md new file mode 100644 index 0000000..781d855 --- /dev/null +++ b/uk/08-checkpoints/README.md @@ -0,0 +1,335 @@ + + + + + + + Claude How To + + +# Контрольні точки та відкат + +Контрольні точки дозволяють зберігати стан розмови та повертатися до попередніх моментів у сесії Claude Code. Це незамінно для дослідження різних підходів, відновлення після помилок або порівняння альтернативних рішень. + +## Огляд + +Контрольні точки — це знімки стану вашої розмови, що включають: + +- Усі повідомлення розмови +- Модифікації файлів +- Історію використання інструментів +- Контекст сесії + +Контрольні точки незамінні при дослідженні різних підходів, відновленні після помилок або порівнянні альтернативних рішень. + +## Ключові поняття + +| Поняття | Опис | +|---------|------| +| **Контрольна точка (Checkpoint)** | Знімок стану розмови, включаючи повідомлення, файли та контекст | +| **Відкат (Rewind)** | Повернення до попередньої контрольної точки з відкиданням подальших змін | +| **Точка розгалуження (Branch Point)** | Контрольна точка, з якої досліджуються кілька підходів | + +## Доступ до контрольних точок + +Ви можете отримати доступ та управляти контрольними точками двома способами: + +### Клавіатурне скорочення + +Натисніть `Esc` двічі (`Esc` + `Esc`), щоб відкрити інтерфейс контрольних точок та переглянути збережені точки. + +### Слеш-команда + +Використовуйте команду `/rewind` (аліас: `/checkpoint`) для швидкого доступу: + +```bash +# Відкрити інтерфейс відкату +/rewind + +# Або використайте аліас +/checkpoint +``` + +## Варіанти відкату + +При відкаті вам пропонується меню з п'яти варіантів: + +1. **Відновити код і розмову** — Повернути і файли, і повідомлення до цієї контрольної точки +2. **Відновити розмову** — Відкотити лише повідомлення, залишити поточний код як є +3. **Відновити код** — Повернути зміни файлів, зберегти повну історію розмови +4. **Підсумувати звідси** — Стиснути розмову від цієї точки вперед в AI-згенерований підсумок, звільняючи контекстне вікно. Повідомлення до обраної точки залишаються недоторканими. Жодні файли на диску не змінюються. Оригінальні повідомлення зберігаються в транскрипті сесії. Можна додатково вказати інструкції для фокусування підсумку на конкретних темах. +5. **Скасувати** — Скасувати та повернутися до поточного стану + +> **Примітка**: Після відновлення розмови або підсумовування оригінальний промпт з обраного повідомлення відновлюється в полі вводу, щоб ви могли повторно надіслати або відредагувати його. + +## Автоматичні контрольні точки + +Claude Code автоматично створює контрольні точки: + +- **Кожен промпт користувача** — Нова контрольна точка створюється з кожним введенням +- **Постійні** — Контрольні точки зберігаються між сесіями +- **Автоочищення** — Контрольні точки автоматично очищуються через 30 днів + +Це означає, що ви завжди можете повернутися до будь-якого попереднього моменту розмови — від кількох хвилин тому до днів. + +## Сценарії використання + +| Сценарій | Процес | +|----------|--------| +| **Дослідження підходів** | Зберегти → Спробувати A → Зберегти → Відкат → Спробувати B → Порівняти | +| **Безпечний рефакторинг** | Зберегти → Рефакторити → Тест → Якщо не вдалось: Відкат | +| **A/B тестування** | Зберегти → Дизайн A → Зберегти → Відкат → Дизайн B → Порівняти | +| **Відновлення після помилки** | Помітити проблему → Відкат до останнього робочого стану | + +## Використання контрольних точок + +### Перегляд та відкат + +Натисніть `Esc` двічі або використайте `/rewind`, щоб відкрити браузер контрольних точок. Ви побачите список усіх доступних точок з мітками часу. Оберіть будь-яку для відкату. + +### Деталі контрольної точки + +Кожна контрольна точка показує: + +- Мітку часу створення +- Модифіковані файли +- Кількість повідомлень у розмові +- Використані інструменти + +## Практичні приклади + +### Приклад 1: Дослідження різних підходів + +``` +User: Let's add a caching layer to the API + +Claude: I'll add Redis caching to your API endpoints... +[Makes changes at checkpoint A] + +User: Actually, let's try in-memory caching instead + +Claude: I'll rewind to explore a different approach... +[User presses Esc+Esc and rewinds to checkpoint A] +[Implements in-memory caching at checkpoint B] + +User: Now I can compare both approaches +``` + +### Приклад 2: Відновлення після помилки + +``` +User: Refactor the authentication module to use JWT + +Claude: I'll refactor the authentication module... +[Makes extensive changes] + +User: Wait, that broke the OAuth integration. Let's go back. + +Claude: I'll help you rewind to before the refactoring... +[User presses Esc+Esc and selects the checkpoint before the refactor] + +User: Let's try a more conservative approach this time +``` + +### Приклад 3: Безпечне експериментування + +``` +User: Let's try rewriting this in a functional style +[Creates checkpoint before experiment] + +Claude: [Makes experimental changes] + +User: The tests are failing. Let's rewind. +[User presses Esc+Esc and rewinds to the checkpoint] + +Claude: I've rewound the changes. Let's try a different approach. +``` + +### Приклад 4: Розгалуження підходів + +``` +User: I want to compare two database designs +[Takes note of checkpoint - call it "Start"] + +Claude: I'll create the first design... +[Implements Schema A] + +User: Now let me go back and try the second approach +[User presses Esc+Esc and rewinds to "Start"] + +Claude: Now I'll implement Schema B... +[Implements Schema B] + +User: Great! Now I have both schemas to choose from +``` + +## Збереження контрольних точок + +Claude Code автоматично управляє контрольними точками: + +- Контрольні точки створюються автоматично з кожним промптом +- Старі контрольні точки зберігаються до 30 днів +- Автоматичне очищення запобігає необмеженому зростанню сховища + +## Патерни процесів + +### Стратегія розгалуження для дослідження + +При дослідженні кількох підходів: + +``` +1. Початкова реалізація → Контрольна точка A +2. Спроба Підходу 1 → Контрольна точка B +3. Відкат до Контрольної точки A +4. Спроба Підходу 2 → Контрольна точка C +5. Порівняння результатів B та C +6. Вибір найкращого підходу та продовження +``` + +### Патерн безпечного рефакторингу + +При значних змінах: + +``` +1. Поточний стан → Контрольна точка (авто) +2. Початок рефакторингу +3. Запуск тестів +4. Якщо тести пройшли → Продовжити роботу +5. Якщо тести не пройшли → Відкат та спроба іншого підходу +``` + +## Найкращі практики + +Оскільки контрольні точки створюються автоматично, ви можете зосередитися на роботі, не турбуючись про ручне збереження стану. Але пам'ятайте: + +### Ефективне використання контрольних точок + +✅ **Робіть:** + +- Переглядайте доступні контрольні точки перед відкатом +- Використовуйте відкат для дослідження різних напрямків +- Зберігайте контрольні точки для порівняння підходів +- Розумійте, що робить кожен варіант відкату + +❌ **Не робіть:** + +- Не покладайтесь лише на контрольні точки для збереження коду +- Не очікуйте, що контрольні точки відстежують зовнішні зміни файлової системи +- Не використовуйте контрольні точки замість git-комітів + +## Конфігурація + +Контрольні точки — вбудована поведінка Claude Code за замовчуванням, не потребує конфігурації. Кожен промпт автоматично створює контрольну точку. + +Єдине налаштування — `cleanupPeriodDays`, що контролює тривалість зберігання: + +```json +{ + "cleanupPeriodDays": 30 +} +``` + +- `cleanupPeriodDays`: Кількість днів зберігання історії сесій та контрольних точок (за замовчуванням: `30`) + +## Обмеження + +Контрольні точки мають такі обмеження: + +- **Bash-команди НЕ відстежуються** — Операції `rm`, `mv`, `cp` у файловій системі не фіксуються +- **Зовнішні зміни НЕ відстежуються** — Зміни, зроблені поза Claude Code (у редакторі, терміналі тощо), не фіксуються +- **Не заміна системі контролю версій** — Використовуйте git для постійних, аудитованих змін + +## Усунення неполадок + +### Відсутні контрольні точки + +**Проблема**: Очікувана контрольна точка не знайдена + +**Рішення**: + +- Перевірте, чи контрольні точки не були очищені +- Перевірте дисковий простір +- Переконайтесь, що `cleanupPeriodDays` встановлено достатньо високо (за замовчуванням: 30 днів) + +### Невдалий відкат + +**Проблема**: Не вдається відкотити до контрольної точки + +**Рішення**: + +- Переконайтесь, що немає конфліктуючих незакомічених змін +- Перевірте, чи контрольна точка не пошкоджена +- Спробуйте відкат до іншої контрольної точки + +## Інтеграція з Git + +Контрольні точки доповнюють (але не замінюють) git: + +| Характеристика | Git | Контрольні точки | +|----------------|-----|-----------------| +| Область | Файлова система | Розмова + файли | +| Постійність | Постійна | На рівні сесії | +| Деталізація | Коміти | Будь-яка точка | +| Швидкість | Повільніше | Миттєво | +| Спільний доступ | Так | Обмежено | + +Використовуйте обидва разом: + +1. Контрольні точки для швидкого експериментування +2. Git-коміти для фіналізованих змін +3. Створення контрольної точки перед git-операціями +4. Коміт успішних станів до git + +## Швидкий старт + +### Базовий процес + +1. **Працюйте як зазвичай** — Claude Code створює контрольні точки автоматично +2. **Хочете повернутись?** — Натисніть `Esc` двічі або `/rewind` +3. **Оберіть контрольну точку** — Виберіть зі списку +4. **Оберіть що відновити** — Код і розмову, лише розмову, лише код, підсумувати або скасувати +5. **Продовжуйте роботу** — Ви повернулись до тієї точки + +### Клавіатурні скорочення + +- **`Esc` + `Esc`** — Відкрити браузер контрольних точок +- **`/rewind`** — Альтернативний спосіб доступу +- **`/checkpoint`** — Аліас для `/rewind` + +## Коли відкочуватися: Моніторинг контексту + +Контрольні точки дозволяють повернутись — але як зрозуміти, *коли* це потрібно? З ростом розмови контекстне вікно Claude заповнюється, і якість моделі непомітно знижується. Ви можете відправляти код, згенерований напівсліпою моделлю, навіть не усвідомлюючи цього. + +**[cc-context-stats](https://github.com/luongnv89/cc-context-stats)** вирішує це, додаючи **зони контексту** в реальному часі до рядка стану Claude Code. Інструмент відстежує, де ви знаходитесь у контекстному вікні — від **Plan** (зелений, безпечно планувати та кодити) через **Code** (жовтий, уникайте нових планів) до **Dump** (оранжевий, завершуйте та відкочуйте). Коли бачите зміну зони — час створити контрольну точку та почати заново. + +## Пов'язані концепції + +- **[Розширені функції](../09-advanced-features/)** — Режим планування та інші просунуті можливості +- **[Управління пам'яттю](../02-memory/)** — Управління історією розмови та контекстом +- **[Слеш-команди](../01-slash-commands/)** — Ярлики користувача +- **[Хуки](../06-hooks/)** — Автоматизація на основі подій +- **[Плагіни](../07-plugins/)** — Пакетні розширення + +## Додаткові ресурси + +- [Офіційна документація контрольних точок](https://code.claude.com/docs/en/checkpointing) +- [Посібник з розширених функцій](../09-advanced-features/) — Розширене мислення та інші можливості + +## Підсумок + +Контрольні точки — автоматична функція Claude Code, що дозволяє безпечно досліджувати різні підходи без страху втратити роботу. Кожен промпт автоматично створює нову контрольну точку, тож ви можете відкотитися до будь-якого попереднього моменту сесії. + +Ключові переваги: + +- Безстрашне експериментування з кількома підходами +- Швидке відновлення після помилок +- Порівняння різних рішень пліч-о-пліч +- Безпечна інтеграція з системами контролю версій + +Пам'ятайте: контрольні точки не замінюють git. Використовуйте контрольні точки для швидкого експериментування, а git — для постійних змін коду. + +--- + +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/TRANSLATION_QUEUE.md b/uk/TRANSLATION_QUEUE.md index 9787084..179040b 100644 --- a/uk/TRANSLATION_QUEUE.md +++ b/uk/TRANSLATION_QUEUE.md @@ -2,111 +2,44 @@ # Прогрес перекладу українською -**Загальний прогрес:** 0/67 файлів (0%) +**Загальний прогрес:** 5/67 файлів (7%) -**Статус:** 🚧 В ПРОЦЕСІ +**Статус:** 🚧 В ПРОЦЕСІ — P1 ядро завершено ✅ -## Пріоритет 1 — Ядро (5 файлів) +## Пріоритет 1 — Ядро (5 файлів) ✅ -| Файл | Статус | Дата | Перекладач | -|------|--------|------|------------| -| README.md | ✅ Готово | 2026-04-09 | edocltd | -| INDEX.md | ⏳ Очікує | | | -| CATALOG.md | ⏳ Очікує | | | -| QUICK_REFERENCE.md | ⏳ Очікує | | | -| LEARNING-ROADMAP.md | ⏳ Очікує | | | +| Файл | Статус | Дата | +|------|--------|------| +| README.md | ✅ | 2026-04-09 | +| INDEX.md | ✅ | 2026-04-09 | +| CATALOG.md | ✅ | 2026-04-09 | +| QUICK_REFERENCE.md | ✅ | 2026-04-09 | +| LEARNING-ROADMAP.md | ✅ | 2026-04-09 | -**Прогрес P1:** 1/5 (20%) +**Прогрес P1:** 5/5 (100%) ✅ ## Пріоритет 2 — Модулі README (10 файлів) -| Модуль | Файл | Статус | Дата | -|--------|------|--------|------| -| 01 | 01-slash-commands/README.md | ⏳ Очікує | | -| 02 | 02-memory/README.md | ⏳ Очікує | | -| 03 | 03-skills/README.md | ⏳ Очікує | | -| 04 | 04-subagents/README.md | ⏳ Очікує | | -| 05 | 05-mcp/README.md | ⏳ Очікує | | -| 06 | 06-hooks/README.md | ⏳ Очікує | | -| 07 | 07-plugins/README.md | ⏳ Очікує | | -| 08 | 08-checkpoints/README.md | ⏳ Очікує | | -| 09 | 09-advanced-features/README.md | ⏳ Очікує | | -| 10 | 10-cli/README.md | ⏳ Очікує | | +| Модуль | Рядків | Статус | Дата | +|--------|--------|--------|------| +| 01 slash-commands | 565 | ⏳ | | +| 02 memory | 1156 | ⏳ | | +| 03 skills | 811 | ⏳ | | +| 04 subagents | 1142 | ⏳ | | +| 05 mcp | 1113 | ⏳ | | +| 06 hooks | 1170 | ⏳ | | +| 07 plugins | 949 | ⏳ | | +| 08 checkpoints | 320 | ⏳ | | +| 09 advanced | 1945 | ⏳ | | +| 10 cli | 837 | ⏳ | | **Прогрес P2:** 0/10 (0%) -## Пріоритет 3 — Приклади модулів (47 файлів) +## Пріоритет 3 — Приклади (47 файлів) · P4 — Допоміжні (5 файлів) -### Модуль 01 — Слеш-команди (8 файлів) +Деталі — див. попередню версію цього файлу. -| Файл | Статус | Дата | -|------|--------|------| -| commit.md | ⏳ | | -| doc-refactor.md | ⏳ | | -| generate-api-docs.md | ⏳ | | -| optimize.md | ⏳ | | -| pr.md | ⏳ | | -| push-all.md | ⏳ | | -| setup-ci-cd.md | ⏳ | | -| unit-test-expand.md | ⏳ | | - -### Модуль 02 — Пам'ять (3 файли) - -| Файл | Статус | Дата | -|------|--------|------| -| directory-api-CLAUDE.md | ⏳ | | -| personal-CLAUDE.md | ⏳ | | -| project-CLAUDE.md | ⏳ | | - -### Модуль 03 — Навички (6 файлів) - -| Файл | Статус | Дата | -|------|--------|------| -| blog-draft/SKILL.md | ⏳ | | -| brand-voice/SKILL.md | ⏳ | | -| brand-voice/tone-examples.md | ⏳ | | -| claude-md/SKILL.md | ⏳ | | -| code-review/SKILL.md | ⏳ | | -| doc-generator/SKILL.md | ⏳ | | -| refactor/SKILL.md | ⏳ | | - -### Модуль 04 — Субагенти (8 файлів) - -| Файл | Статус | Дата | -|------|--------|------| -| clean-code-reviewer.md | ⏳ | | -| code-reviewer.md | ⏳ | | -| data-scientist.md | ⏳ | | -| debugger.md | ⏳ | | -| documentation-writer.md | ⏳ | | -| implementation-agent.md | ⏳ | | -| performance-optimizer.md | ⏳ | | -| secure-reviewer.md | ⏳ | | -| test-engineer.md | ⏳ | | - -### Модуль 05-10 — Приклади - -Код-файли (`.sh`, `.py`, `.json`) **не копіюються** — посилаємося на оригінали. -Файли прикладів перекладаються за потреби. - -| Файл | Статус | Дата | -|------|--------|------| -| 08-checkpoints/checkpoint-examples.md | ⏳ | | -| 09-advanced-features/planning-mode-examples.md | ⏳ | | - -**Прогрес P3:** 0/47 (0%) - -## Пріоритет 4 — Допоміжні документи (5 файлів) - -| Файл | Статус | Дата | -|------|--------|------| -| CONTRIBUTING.md | ⏳ Очікує | | -| SECURITY.md | ⏳ Очікує | | -| CODE_OF_CONDUCT.md | ⏳ Очікує | | -| STYLE_GUIDE.md | ⏳ Очікує | | -| CHANGELOG.md | ⏳ Очікує | | - -**Прогрес P4:** 0/5 (0%) +**Прогрес P3:** 0/47 · **P4:** 0/5 --- From 2a276147706f903af38ba2b4aa878d909aa5bc56 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 19:55:57 +0300 Subject: [PATCH 07/20] fix(uk): complete translations for modules 06, 07, 09, 10 Modules 06-hooks, 07-plugins, 09-advanced-features, 10-cli had truncated translations (18-58% content loss). Retranslated from scratch using original English sources. All files now match expected ~40% size increase for Cyrillic. Ref: luongnv89/claude-howto#63 --- uk/06-hooks/README.md | 1174 +++++++++++++++++ uk/07-plugins/README.md | 953 ++++++++++++++ uk/09-advanced-features/README.md | 1945 +++++++++++++++++++++++++++++ uk/10-cli/README.md | 841 +++++++++++++ 4 files changed, 4913 insertions(+) create mode 100644 uk/06-hooks/README.md create mode 100644 uk/07-plugins/README.md create mode 100644 uk/09-advanced-features/README.md create mode 100644 uk/10-cli/README.md diff --git a/uk/06-hooks/README.md b/uk/06-hooks/README.md new file mode 100644 index 0000000..44078d8 --- /dev/null +++ b/uk/06-hooks/README.md @@ -0,0 +1,1174 @@ + + + + + + + Claude How To + + +# Хуки + +Хуки — це автоматизовані скрипти, які виконуються у відповідь на конкретні події під час сесій Claude Code. Вони забезпечують автоматизацію, валідацію, управління дозволами та кастомні робочі процеси. + +## Огляд + +Хуки — це автоматичні дії (shell-команди, HTTP-вебхуки, LLM-промпти або оцінки субагентів), що виконуються автоматично при виникненні конкретних подій у Claude Code. Вони отримують JSON-вхід і повідомляють результати через коди виходу та JSON-вивід. + +**Ключові можливості:** +- Автоматизація на основі подій +- Введення/виведення на основі JSON +- Підтримка типів хуків: command, prompt, HTTP та agent +- Відповідність шаблонам (pattern matching) для хуків, специфічних для інструментів + +## Конфігурація + +Хуки налаштовуються у файлах налаштувань з конкретною структурою: + +- `~/.claude/settings.json` — налаштування користувача (усі проєкти) +- `.claude/settings.json` — налаштування проєкту (спільні, комітяться) +- `.claude/settings.local.json` — локальні налаштування проєкту (не комітяться) +- Керована політика (Managed policy) — загальноорганізаційні налаштування +- `hooks/hooks.json` плагіна — хуки з областю дії плагіна +- Frontmatter навичок/агентів — хуки часу життя компонентів + +### Базова структура конфігурації + +```json +{ + "hooks": { + "EventName": [ + { + "matcher": "ToolPattern", + "hooks": [ + { + "type": "command", + "command": "your-command-here", + "timeout": 60 + } + ] + } + ] + } +} +``` + +**Ключові поля:** + +| Поле | Опис | Приклад | +|------|------|---------| +| `matcher` | Шаблон для відповідності назвам інструментів (чутливий до регістру) | `"Write"`, `"Edit\|Write"`, `"*"` | +| `hooks` | Масив визначень хуків | `[{ "type": "command", ... }]` | +| `type` | Тип хука: `"command"` (bash), `"prompt"` (LLM), `"http"` (вебхук) або `"agent"` (субагент) | `"command"` | +| `command` | Shell-команда для виконання | `"$CLAUDE_PROJECT_DIR/.claude/hooks/format.sh"` | +| `timeout` | Необовʼязковий таймаут у секундах (за замовчуванням 60) | `30` | +| `once` | Якщо `true`, хук запускається лише один раз за сесію | `true` | + +### Шаблони matcher + +| Шаблон | Опис | Приклад | +|--------|------|---------| +| Точний рядок | Відповідає конкретному інструменту | `"Write"` | +| Regex-шаблон | Відповідає кільком інструментам | `"Edit\|Write"` | +| Підстановочний знак | Відповідає всім інструментам | `"*"` або `""` | +| MCP-інструменти | Шаблон сервера та інструмента | `"mcp__memory__.*"` | + +**Значення matcher для InstructionsLoaded:** + +| Значення matcher | Опис | +|-----------------|------| +| `session_start` | Інструкції завантажені при запуску сесії | +| `nested_traversal` | Інструкції завантажені при обході вкладених каталогів | +| `path_glob_match` | Інструкції завантажені через відповідність glob-шаблону шляху | + +## Типи хуків + +Claude Code підтримує чотири типи хуків: + +### Command-хуки + +Тип за замовчуванням. Виконує shell-команду та комунікує через JSON stdin/stdout і коди виходу. + +```json +{ + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/validate.py\"", + "timeout": 60 +} +``` + +### HTTP-хуки + +> Додано у v2.1.63. + +Віддалені вебхук-ендпоінти, які отримують той самий JSON-вхід, що й command-хуки. HTTP-хуки надсилають POST JSON на URL і отримують JSON-відповідь. HTTP-хуки маршрутизуються через пісочницю (sandbox), коли вона увімкнена. Інтерполяція змінних оточення в URL вимагає явного списку `allowedEnvVars` з міркувань безпеки. + +```json +{ + "hooks": { + "PostToolUse": [{ + "type": "http", + "url": "https://my-webhook.example.com/hook", + "matcher": "Write" + }] + } +} +``` + +**Ключові властивості:** +- `"type": "http"` — ідентифікує як HTTP-хук +- `"url"` — URL ендпоінту вебхука +- Маршрутизується через sandbox, коли sandbox увімкнено +- Вимагає явного списку `allowedEnvVars` для будь-якої інтерполяції змінних оточення в URL + +### Prompt-хуки + +Промпти, оцінювані LLM, де вміст хука є промптом, який оцінює Claude. Переважно використовуються з подіями `Stop` та `SubagentStop` для інтелектуальної перевірки завершення завдань. + +```json +{ + "type": "prompt", + "prompt": "Evaluate if Claude completed all requested tasks.", + "timeout": 30 +} +``` + +LLM оцінює промпт і повертає структуроване рішення (деталі див. у [Prompt-хуки](#prompt-хуки-1)). + +### Agent-хуки + +Хуки верифікації на основі субагентів, які створюють виділеного агента для оцінки умов або виконання складних перевірок. На відміну від prompt-хуків (однокрокова оцінка LLM), agent-хуки можуть використовувати інструменти та виконувати багатокрокове міркування. + +```json +{ + "type": "agent", + "prompt": "Verify the code changes follow our architecture guidelines. Check the relevant design docs and compare.", + "timeout": 120 +} +``` + +**Ключові властивості:** +- `"type": "agent"` — ідентифікує як agent-хук +- `"prompt"` — опис завдання для субагента +- Агент може використовувати інструменти (Read, Grep, Bash тощо) для оцінки +- Повертає структуроване рішення, аналогічне prompt-хукам + +## Події хуків + +Claude Code підтримує **26 подій хуків**: + +| Подія | Коли спрацьовує | Вхід matcher | Може блокувати | Типове використання | +|-------|----------------|-------------|----------------|---------------------| +| **SessionStart** | Початок/відновлення/очищення/компакція сесії | startup/resume/clear/compact | Ні | Налаштування середовища | +| **InstructionsLoaded** | Після завантаження CLAUDE.md або файлу правил | (немає) | Ні | Модифікація/фільтрація інструкцій | +| **UserPromptSubmit** | Користувач подає промпт | (немає) | Так | Валідація промптів | +| **PreToolUse** | Перед виконанням інструмента | Назва інструмента | Так (allow/deny/ask) | Валідація, модифікація вхідних даних | +| **PermissionRequest** | Показ діалогу дозволів | Назва інструмента | Так | Автозатвердження/відхилення | +| **PermissionDenied** | Користувач відхиляє запит дозволу | Назва інструмента | Ні | Логування, аналітика, політики | +| **PostToolUse** | Після успішного виконання інструмента | Назва інструмента | Ні | Контекст, зворотний звʼязок | +| **PostToolUseFailure** | Невдале виконання інструмента | Назва інструмента | Ні | Обробка помилок, логування | +| **Notification** | Надсилання сповіщення | Тип сповіщення | Ні | Кастомні сповіщення | +| **SubagentStart** | Створення субагента | Назва типу агента | Ні | Налаштування субагента | +| **SubagentStop** | Завершення субагента | Назва типу агента | Так | Валідація субагента | +| **Stop** | Claude завершує відповідь | (немає) | Так | Перевірка завершення завдання | +| **StopFailure** | Помилка API завершує хід | (немає) | Ні | Відновлення після помилок, логування | +| **TeammateIdle** | Неактивність учасника Agent Teams | (немає) | Так | Координація учасників | +| **TaskCompleted** | Завдання позначено як виконане | (немає) | Так | Дії після завершення завдання | +| **TaskCreated** | Завдання створене через TaskCreate | (немає) | Ні | Відстеження завдань, логування | +| **ConfigChange** | Зміна файлу конфігурації | (немає) | Так (крім policy) | Реакція на оновлення конфігурації | +| **CwdChanged** | Зміна робочого каталогу | (немає) | Ні | Налаштування для каталогу | +| **FileChanged** | Зміна відстежуваного файлу | (немає) | Ні | Моніторинг файлів, перебудова | +| **PreCompact** | Перед компакцією контексту | manual/auto | Ні | Дії перед компакцією | +| **PostCompact** | Після завершення компакції | (немає) | Ні | Дії після компакції | +| **WorktreeCreate** | Створення робочого дерева (worktree) | (немає) | Так (повернення шляху) | Ініціалізація worktree | +| **WorktreeRemove** | Видалення робочого дерева | (немає) | Ні | Очищення worktree | +| **Elicitation** | MCP-сервер запитує введення користувача | (немає) | Так | Валідація введення | +| **ElicitationResult** | Відповідь користувача на elicitation | (немає) | Так | Обробка відповіді | +| **SessionEnd** | Завершення сесії | (немає) | Ні | Очищення, фінальне логування | + +### PreToolUse + +Запускається після створення параметрів інструмента Claude і перед обробкою. Використовується для валідації або модифікації вхідних даних інструмента. + +**Конфігурація:** +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-bash.py" + } + ] + } + ] + } +} +``` + +**Типові matcher:** `Task`, `Bash`, `Glob`, `Grep`, `Read`, `Edit`, `Write`, `WebFetch`, `WebSearch` + +**Управління виводом:** +- `permissionDecision`: `"allow"`, `"deny"` або `"ask"` +- `permissionDecisionReason`: Пояснення рішення +- `updatedInput`: Модифіковані вхідні параметри інструмента + +### PostToolUse + +Запускається одразу після завершення інструмента. Використовується для верифікації, логування або надання контексту назад Claude. + +**Конфігурація:** +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/security-scan.py" + } + ] + } + ] + } +} +``` + +**Управління виводом:** +- Рішення `"block"` подає Claude зворотний звʼязок +- `additionalContext`: Контекст, доданий для Claude + +### UserPromptSubmit + +Запускається, коли користувач подає промпт, перед тим як Claude його обробить. + +**Конфігурація:** +```json +{ + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-prompt.py" + } + ] + } + ] + } +} +``` + +**Управління виводом:** +- `decision`: `"block"` для запобігання обробці +- `reason`: Пояснення у разі блокування +- `additionalContext`: Контекст, доданий до промпта + +### Stop та SubagentStop + +Запускаються, коли Claude завершує відповідь (Stop) або субагент завершує роботу (SubagentStop). Підтримують оцінку на основі промптів для інтелектуальної перевірки завершення завдань. + +**Додаткове поле введення:** Обидва хуки `Stop` та `SubagentStop` отримують поле `last_assistant_message` у JSON-вході, що містить останнє повідомлення від Claude або субагента перед зупинкою. Це корисно для оцінки завершення завдання. + +**Конфігурація:** +```json +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Evaluate if Claude completed all requested tasks.", + "timeout": 30 + } + ] + } + ] + } +} +``` + +### SubagentStart + +Запускається при початку виконання субагента. Вхід matcher — назва типу агента, що дозволяє хукам націлюватися на конкретні типи субагентів. + +**Конфігурація:** +```json +{ + "hooks": { + "SubagentStart": [ + { + "matcher": "code-review", + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/subagent-init.sh" + } + ] + } + ] + } +} +``` + +### SessionStart + +Запускається при старті або відновленні сесії. Може зберігати змінні оточення. + +**Matcher:** `startup`, `resume`, `clear`, `compact` + +**Спеціальна можливість:** Використовуйте `CLAUDE_ENV_FILE` для збереження змінних оточення (також доступно в хуках `CwdChanged` та `FileChanged`): + +```bash +#!/bin/bash +if [ -n "$CLAUDE_ENV_FILE" ]; then + echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE" +fi +exit 0 +``` + +### SessionEnd + +Запускається при завершенні сесії для очищення або фінального логування. Не може блокувати завершення. + +**Значення поля reason:** +- `clear` — користувач очистив сесію +- `logout` — користувач вийшов із системи +- `prompt_input_exit` — користувач вийшов через введення промпта +- `other` — інша причина + +**Конфігурація:** +```json +{ + "hooks": { + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh\"" + } + ] + } + ] + } +} +``` + +### Подія Notification + +Оновлені matcher для подій сповіщень: +- `permission_prompt` — сповіщення про запит дозволу +- `idle_prompt` — сповіщення про стан простою +- `auth_success` — успішна автентифікація +- `elicitation_dialog` — діалог, показаний користувачу + +## Хуки з областю дії компонентів + +Хуки можна прикріплювати до конкретних компонентів (навички, агенти, команди) у їхньому frontmatter: + +**У SKILL.md, agent.md або command.md:** + +```yaml +--- +name: secure-operations +description: Perform operations with security checks +hooks: + PreToolUse: + - matcher: "Bash" + hooks: + - type: command + command: "./scripts/check.sh" + once: true # Запустити лише один раз за сесію +--- +``` + +**Підтримувані події для хуків компонентів:** `PreToolUse`, `PostToolUse`, `Stop` + +Це дозволяє визначати хуки безпосередньо в компоненті, що їх використовує, зберігаючи повʼязаний код разом. + +### Хуки у frontmatter субагента + +Коли хук `Stop` визначений у frontmatter субагента, він автоматично перетворюється на хук `SubagentStop` з областю дії цього субагента. Це гарантує, що хук зупинки спрацьовує лише коли завершує роботу саме цей субагент, а не при зупинці основної сесії. + +```yaml +--- +name: code-review-agent +description: Automated code review subagent +hooks: + Stop: + - hooks: + - type: prompt + prompt: "Verify the code review is thorough and complete." + # Наведений Stop-хук автоматично перетворюється на SubagentStop для цього субагента +--- +``` + +## Подія PermissionRequest + +Обробка запитів дозволів з кастомним форматом виводу: + +```json +{ + "hookSpecificOutput": { + "hookEventName": "PermissionRequest", + "decision": { + "behavior": "allow|deny", + "updatedInput": {}, + "message": "Custom message", + "interrupt": false + } + } +} +``` + +## Вхідні та вихідні дані хуків + +### JSON-вхід (через stdin) + +Усі хуки отримують JSON-вхід через stdin: + +```json +{ + "session_id": "abc123", + "transcript_path": "/path/to/transcript.jsonl", + "cwd": "/current/working/directory", + "permission_mode": "default", + "hook_event_name": "PreToolUse", + "tool_name": "Write", + "tool_input": { + "file_path": "/path/to/file.js", + "content": "..." + }, + "tool_use_id": "toolu_01ABC123...", + "agent_id": "agent-abc123", + "agent_type": "main", + "worktree": "/path/to/worktree" +} +``` + +**Загальні поля:** + +| Поле | Опис | +|------|------| +| `session_id` | Унікальний ідентифікатор сесії | +| `transcript_path` | Шлях до файлу транскрипту розмови | +| `cwd` | Поточний робочий каталог | +| `hook_event_name` | Назва події, що запустила хук | +| `agent_id` | Ідентифікатор агента, що запускає хук | +| `agent_type` | Тип агента (`"main"`, назва типу субагента тощо) | +| `worktree` | Шлях до git worktree, якщо агент працює в ньому | + +### Коди виходу + +| Код виходу | Значення | Поведінка | +|-----------|----------|----------| +| **0** | Успіх | Продовжити, розібрати JSON stdout | +| **2** | Блокуюча помилка | Заблокувати операцію, stderr показується як помилка | +| **Інші** | Неблокуюча помилка | Продовжити, stderr показується у verbose-режимі | + +### JSON-вивід (stdout, код виходу 0) + +```json +{ + "continue": true, + "stopReason": "Optional message if stopping", + "suppressOutput": false, + "systemMessage": "Optional warning message", + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "allow", + "permissionDecisionReason": "File is in allowed directory", + "updatedInput": { + "file_path": "/modified/path.js" + } + } +} +``` + +## Змінні оточення + +| Змінна | Доступність | Опис | +|--------|------------|------| +| `CLAUDE_PROJECT_DIR` | Усі хуки | Абсолютний шлях до кореня проєкту | +| `CLAUDE_ENV_FILE` | SessionStart, CwdChanged, FileChanged | Шлях до файлу для збереження змінних оточення | +| `CLAUDE_CODE_REMOTE` | Усі хуки | `"true"` при роботі у віддаленому середовищі | +| `${CLAUDE_PLUGIN_ROOT}` | Хуки плагінів | Шлях до каталогу плагіна | +| `${CLAUDE_PLUGIN_DATA}` | Хуки плагінів | Шлях до каталогу даних плагіна | +| `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` | Хуки SessionEnd | Налаштовуваний таймаут у мілісекундах для хуків SessionEnd (перевизначає стандартний) | + +## Prompt-хуки + +Для подій `Stop` та `SubagentStop` можна використовувати оцінку на основі LLM: + +```json +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Review if all tasks are complete. Return your decision.", + "timeout": 30 + } + ] + } + ] + } +} +``` + +**Схема відповіді LLM:** +```json +{ + "decision": "approve", + "reason": "All tasks completed successfully", + "continue": false, + "stopReason": "Task complete" +} +``` + +## Приклади + +### Приклад 1: Валідатор Bash-команд (PreToolUse) + +**Файл:** `.claude/hooks/validate-bash.py` + +```python +#!/usr/bin/env python3 +import json +import sys +import re + +BLOCKED_PATTERNS = [ + (r"\brm\s+-rf\s+/", "Blocking dangerous rm -rf / command"), + (r"\bsudo\s+rm", "Blocking sudo rm command"), +] + +def main(): + input_data = json.load(sys.stdin) + + tool_name = input_data.get("tool_name", "") + if tool_name != "Bash": + sys.exit(0) + + command = input_data.get("tool_input", {}).get("command", "") + + for pattern, message in BLOCKED_PATTERNS: + if re.search(pattern, command): + print(message, file=sys.stderr) + sys.exit(2) # Код виходу 2 = блокуюча помилка + + sys.exit(0) + +if __name__ == "__main__": + main() +``` + +**Конфігурація:** +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/validate-bash.py\"" + } + ] + } + ] + } +} +``` + +### Приклад 2: Сканер безпеки (PostToolUse) + +**Файл:** `.claude/hooks/security-scan.py` + +```python +#!/usr/bin/env python3 +import json +import sys +import re + +SECRET_PATTERNS = [ + (r"password\s*=\s*['\"][^'\"]+['\"]", "Potential hardcoded password"), + (r"api[_-]?key\s*=\s*['\"][^'\"]+['\"]", "Potential hardcoded API key"), +] + +def main(): + input_data = json.load(sys.stdin) + + tool_name = input_data.get("tool_name", "") + if tool_name not in ["Write", "Edit"]: + sys.exit(0) + + tool_input = input_data.get("tool_input", {}) + content = tool_input.get("content", "") or tool_input.get("new_string", "") + file_path = tool_input.get("file_path", "") + + warnings = [] + for pattern, message in SECRET_PATTERNS: + if re.search(pattern, content, re.IGNORECASE): + warnings.append(message) + + if warnings: + output = { + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": f"Security warnings for {file_path}: " + "; ".join(warnings) + } + } + print(json.dumps(output)) + + sys.exit(0) + +if __name__ == "__main__": + main() +``` + +### Приклад 3: Автоформатування коду (PostToolUse) + +**Файл:** `.claude/hooks/format-code.sh` + +```bash +#!/bin/bash + +# Читання JSON з stdin +INPUT=$(cat) +TOOL_NAME=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('tool_name', ''))") +FILE_PATH=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('tool_input', {}).get('file_path', ''))") + +if [ "$TOOL_NAME" != "Write" ] && [ "$TOOL_NAME" != "Edit" ]; then + exit 0 +fi + +# Форматування залежно від розширення файлу +case "$FILE_PATH" in + *.js|*.jsx|*.ts|*.tsx|*.json) + command -v prettier &>/dev/null && prettier --write "$FILE_PATH" 2>/dev/null + ;; + *.py) + command -v black &>/dev/null && black "$FILE_PATH" 2>/dev/null + ;; + *.go) + command -v gofmt &>/dev/null && gofmt -w "$FILE_PATH" 2>/dev/null + ;; +esac + +exit 0 +``` + +### Приклад 4: Валідатор промптів (UserPromptSubmit) + +**Файл:** `.claude/hooks/validate-prompt.py` + +```python +#!/usr/bin/env python3 +import json +import sys +import re + +BLOCKED_PATTERNS = [ + (r"delete\s+(all\s+)?database", "Dangerous: database deletion"), + (r"rm\s+-rf\s+/", "Dangerous: root deletion"), +] + +def main(): + input_data = json.load(sys.stdin) + prompt = input_data.get("user_prompt", "") or input_data.get("prompt", "") + + for pattern, message in BLOCKED_PATTERNS: + if re.search(pattern, prompt, re.IGNORECASE): + output = { + "decision": "block", + "reason": f"Blocked: {message}" + } + print(json.dumps(output)) + sys.exit(0) + + sys.exit(0) + +if __name__ == "__main__": + main() +``` + +### Приклад 5: Інтелектуальний Stop-хук (на основі промпта) + +```json +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Review if Claude completed all requested tasks. Check: 1) Were all files created/modified? 2) Were there unresolved errors? If incomplete, explain what's missing.", + "timeout": 30 + } + ] + } + ] + } +} +``` + +### Приклад 6: Трекер використання контексту (пара хуків) + +Відстеження споживання токенів на запит за допомогою хуків `UserPromptSubmit` (перед повідомленням) та `Stop` (після відповіді). + +**Файл:** `.claude/hooks/context-tracker.py` + +```python +#!/usr/bin/env python3 +""" +Context Usage Tracker — Відстежує споживання токенів на запит. + +Використовує UserPromptSubmit як хук "перед повідомленням" і Stop як хук "після відповіді" +для обчислення дельти використання токенів для кожного запиту. + +Методи підрахунку токенів: +1. Оцінка за символами (за замовчуванням): ~4 символи на токен, без залежностей +2. tiktoken (необовʼязково): Точніший (~90-95%), потребує: pip install tiktoken +""" +import json +import os +import sys +import tempfile + +# Конфігурація +CONTEXT_LIMIT = 128000 # Контекстне вікно Claude (налаштуйте для вашої моделі) +USE_TIKTOKEN = False # Встановіть True, якщо tiktoken встановлено для кращої точності + + +def get_state_file(session_id: str) -> str: + """Отримати шлях до тимчасового файлу для збереження лічильника токенів, ізольовано за сесією.""" + return os.path.join(tempfile.gettempdir(), f"claude-context-{session_id}.json") + + +def count_tokens(text: str) -> int: + """ + Підрахунок токенів у тексті. + + Використовує tiktoken з кодуванням p50k_base, якщо доступно (~90-95% точності), + інакше повертається до оцінки за символами (~80-90% точності). + """ + if USE_TIKTOKEN: + try: + import tiktoken + enc = tiktoken.get_encoding("p50k_base") + return len(enc.encode(text)) + except ImportError: + pass # Повернутися до оцінки + + # Оцінка на основі символів: ~4 символи на токен для англійської + return len(text) // 4 + + +def read_transcript(transcript_path: str) -> str: + """Читання та конкатенація всього вмісту з файлу транскрипту.""" + if not transcript_path or not os.path.exists(transcript_path): + return "" + + content = [] + with open(transcript_path, "r") as f: + for line in f: + try: + entry = json.loads(line.strip()) + # Витяг текстового вмісту з різних форматів повідомлень + if "message" in entry: + msg = entry["message"] + if isinstance(msg.get("content"), str): + content.append(msg["content"]) + elif isinstance(msg.get("content"), list): + for block in msg["content"]: + if isinstance(block, dict) and block.get("type") == "text": + content.append(block.get("text", "")) + except json.JSONDecodeError: + continue + + return "\n".join(content) + + +def handle_user_prompt_submit(data: dict) -> None: + """Хук перед повідомленням: зберегти поточний лічильник токенів перед запитом.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens(transcript_content) + + # Зберегти в тимчасовий файл для подальшого порівняння + state_file = get_state_file(session_id) + with open(state_file, "w") as f: + json.dump({"pre_tokens": current_tokens}, f) + + +def handle_stop(data: dict) -> None: + """Хук після відповіді: обчислити дельту та повідомити про використання.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens(transcript_content) + + # Завантажити лічильник перед повідомленням + state_file = get_state_file(session_id) + pre_tokens = 0 + if os.path.exists(state_file): + try: + with open(state_file, "r") as f: + state = json.load(f) + pre_tokens = state.get("pre_tokens", 0) + except (json.JSONDecodeError, IOError): + pass + + # Обчислити дельту + delta_tokens = current_tokens - pre_tokens + remaining = CONTEXT_LIMIT - current_tokens + percentage = (current_tokens / CONTEXT_LIMIT) * 100 + + # Повідомити про використання + method = "tiktoken" if USE_TIKTOKEN else "estimated" + print(f"Context ({method}): ~{current_tokens:,} tokens ({percentage:.1f}% used, ~{remaining:,} remaining)", file=sys.stderr) + if delta_tokens > 0: + print(f"This request: ~{delta_tokens:,} tokens", file=sys.stderr) + + +def main(): + data = json.load(sys.stdin) + event = data.get("hook_event_name", "") + + if event == "UserPromptSubmit": + handle_user_prompt_submit(data) + elif event == "Stop": + handle_stop(data) + + sys.exit(0) + + +if __name__ == "__main__": + main() +``` + +**Конфігурація:** +```json +{ + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/context-tracker.py\"" + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/context-tracker.py\"" + } + ] + } + ] + } +} +``` + +**Як це працює:** +1. `UserPromptSubmit` спрацьовує перед обробкою промпта — зберігає поточний лічильник токенів +2. `Stop` спрацьовує після відповіді Claude — обчислює дельту та повідомляє про використання +3. Кожна сесія ізольована через `session_id` в імені тимчасового файлу + +**Методи підрахунку токенів:** + +| Метод | Точність | Залежності | Швидкість | +|-------|----------|------------|-----------| +| Оцінка за символами | ~80-90% | Немає | <1мс | +| tiktoken (p50k_base) | ~90-95% | `pip install tiktoken` | <10мс | + +> **Примітка:** Anthropic не випустили офіційний офлайн-токенізатор. Обидва методи є наближеннями. Транскрипт включає промпти користувача, відповіді Claude та вивід інструментів, але НЕ системні промпти або внутрішній контекст. + +### Приклад 7: Початкове налаштування дозволів Auto-Mode (одноразовий скрипт) + +Одноразовий скрипт налаштування, що додає до `~/.claude/settings.json` ~67 безпечних правил дозволів, еквівалентних базовому набору auto-mode Claude Code — без жодного хука, без запамʼятовування майбутніх виборів. Запустіть один раз; безпечно для повторного запуску (пропускає правила, що вже присутні). + +**Файл:** `09-advanced-features/setup-auto-mode-permissions.py` + +```bash +# Попередній перегляд того, що буде додано +python3 09-advanced-features/setup-auto-mode-permissions.py --dry-run + +# Застосувати +python3 09-advanced-features/setup-auto-mode-permissions.py +``` + +**Що додається:** + +| Категорія | Приклади | +|-----------|---------| +| Вбудовані інструменти | `Read(*)`, `Edit(*)`, `Write(*)`, `Glob(*)`, `Grep(*)`, `Agent(*)`, `WebSearch(*)` | +| Git читання | `Bash(git status:*)`, `Bash(git log:*)`, `Bash(git diff:*)` | +| Git запис (локально) | `Bash(git add:*)`, `Bash(git commit:*)`, `Bash(git checkout:*)` | +| Пакетні менеджери | `Bash(npm install:*)`, `Bash(pip install:*)`, `Bash(cargo build:*)` | +| Збірка та тестування | `Bash(make:*)`, `Bash(pytest:*)`, `Bash(go test:*)` | +| Загальні shell-команди | `Bash(ls:*)`, `Bash(cat:*)`, `Bash(find:*)`, `Bash(cp:*)`, `Bash(mv:*)` | +| GitHub CLI | `Bash(gh pr view:*)`, `Bash(gh pr create:*)`, `Bash(gh issue list:*)` | + +**Що навмисно виключено** (цей скрипт ніколи не додає): +- `rm -rf`, `sudo`, force push, `git reset --hard` +- `DROP TABLE`, `kubectl delete`, `terraform destroy` +- `npm publish`, `curl | bash`, деплої на продакшн + +## Хуки плагінів + +Плагіни можуть включати хуки у файлі `hooks/hooks.json`: + +**Файл:** `plugins/hooks/hooks.json` + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh" + } + ] + } + ] + } +} +``` + +**Змінні оточення в хуках плагінів:** +- `${CLAUDE_PLUGIN_ROOT}` — шлях до каталогу плагіна +- `${CLAUDE_PLUGIN_DATA}` — шлях до каталогу даних плагіна + +Це дозволяє плагінам включати кастомні хуки валідації та автоматизації. + +## Хуки MCP-інструментів + +MCP-інструменти використовують шаблон `mcp____`: + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "mcp__memory__.*", + "hooks": [ + { + "type": "command", + "command": "echo '{\"systemMessage\": \"Memory operation logged\"}'" + } + ] + } + ] + } +} +``` + +## Міркування безпеки + +### Застереження + +**ВИКОРИСТОВУЙТЕ НА ВЛАСНИЙ РИЗИК**: Хуки виконують довільні shell-команди. Ви несете повну відповідальність за: +- Команди, які ви налаштовуєте +- Дозволи на доступ/модифікацію файлів +- Потенційну втрату даних або пошкодження системи +- Тестування хуків у безпечних середовищах перед використанням на продакшні + +### Примітки щодо безпеки + +- **Потрібна довіра до робочого простору:** Команди виводу хуків `statusLine` та `fileSuggestion` тепер вимагають прийняття довіри до робочого простору перед набранням чинності. +- **HTTP-хуки та змінні оточення:** HTTP-хуки вимагають явного списку `allowedEnvVars` для використання інтерполяції змінних оточення в URL. Це запобігає випадковому витоку чутливих змінних оточення на віддалені ендпоінти. +- **Ієрархія керованих налаштувань:** Налаштування `disableAllHooks` тепер поважає ієрархію керованих налаштувань, тобто налаштування рівня організації можуть примусово вимкнути хуки, що не може бути перевизначено окремими користувачами. + +### Найкращі практики + +| Рекомендовано | Не рекомендовано | +|-------------|-----------------| +| Валідувати та санітизувати всі вхідні дані | Довіряти вхідним даним сліпо | +| Екранувати змінні shell: `"$VAR"` | Використовувати без лапок: `$VAR` | +| Блокувати обхід шляху (`..`) | Дозволяти довільні шляхи | +| Використовувати абсолютні шляхи з `$CLAUDE_PROJECT_DIR` | Жорстко кодувати шляхи | +| Пропускати чутливі файли (`.env`, `.git/`, ключі) | Обробляти всі файли | +| Тестувати хуки окремо спочатку | Деплоїти неперевірені хуки | +| Використовувати явний `allowedEnvVars` для HTTP-хуків | Відкривати всі змінні оточення для вебхуків | + +## Налагодження + +### Увімкнення режиму налагодження + +Запустіть Claude з прапорцем debug для детальних журналів хуків: + +```bash +claude --debug +``` + +### Verbose-режим + +Використовуйте `Ctrl+O` в Claude Code для увімкнення verbose-режиму та перегляду прогресу виконання хуків. + +### Тестування хуків окремо + +```bash +# Тест із зразковим JSON-вводом +echo '{"tool_name": "Bash", "tool_input": {"command": "ls -la"}}' | python3 .claude/hooks/validate-bash.py + +# Перевірка коду виходу +echo $? +``` + +## Повний приклад конфігурації + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/validate-bash.py\"", + "timeout": 10 + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/format-code.sh\"", + "timeout": 30 + }, + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/security-scan.py\"", + "timeout": 10 + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/validate-prompt.py\"" + } + ] + } + ], + "SessionStart": [ + { + "matcher": "startup", + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/session-init.sh\"" + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Verify all tasks are complete before stopping.", + "timeout": 30 + } + ] + } + ] + } +} +``` + +## Деталі виконання хуків + +| Аспект | Поведінка | +|--------|----------| +| **Таймаут** | 60 секунд за замовчуванням, налаштовується для кожної команди | +| **Паралелізація** | Усі відповідні хуки запускаються паралельно | +| **Дедуплікація** | Ідентичні команди хуків дедуплікуються | +| **Середовище** | Запускається в поточному каталозі з середовищем Claude Code | + +## Усунення несправностей + +### Хук не виконується +- Перевірте правильність синтаксису JSON-конфігурації +- Переконайтеся, що шаблон matcher відповідає назві інструмента +- Перевірте існування та виконуваність скрипта: `chmod +x script.sh` +- Запустіть `claude --debug` для перегляду журналів виконання хуків +- Переконайтеся, що хук читає JSON з stdin (не з аргументів команди) + +### Хук блокує несподівано +- Тестуйте хук зі зразковим JSON: `echo '{"tool_name": "Write", ...}' | ./hook.py` +- Перевірте код виходу: має бути 0 для дозволу, 2 для блокування +- Перевірте вивід stderr (показується при коді виходу 2) + +### Помилки парсингу JSON +- Завжди читайте з stdin, не з аргументів команди +- Використовуйте належний парсинг JSON (не маніпуляцію рядками) +- Обробляйте відсутні поля коректно + +## Встановлення + +### Крок 1: Створення каталогу хуків +```bash +mkdir -p ~/.claude/hooks +``` + +### Крок 2: Копіювання прикладів хуків +```bash +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh +``` + +### Крок 3: Налаштування у settings +Відредагуйте `~/.claude/settings.json` або `.claude/settings.json` з конфігурацією хуків, показаною вище. + +## Повʼязані концепції + +- **[Контрольні точки та відкат](../08-checkpoints/)** — збереження та відновлення стану розмови +- **[Слеш-команди](../01-slash-commands/)** — створення кастомних слеш-команд +- **[Навички](../03-skills/)** — повторно використовувані автономні можливості +- **[Субагенти](../04-subagents/)** — делеговане виконання завдань +- **[Плагіни](../07-plugins/)** — обʼєднані пакети розширень +- **[Розширені функції](../09-advanced-features/)** — дослідження розширених можливостей Claude Code + +## Додаткові ресурси + +- **[Офіційна документація хуків](https://code.claude.com/docs/en/hooks)** — повний довідник хуків +- **[Довідник CLI](https://code.claude.com/docs/en/cli-reference)** — документація інтерфейсу командного рядка +- **[Посібник з памʼяті](../02-memory/)** — конфігурація постійного контексту + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/07-plugins/README.md b/uk/07-plugins/README.md new file mode 100644 index 0000000..1942d25 --- /dev/null +++ b/uk/07-plugins/README.md @@ -0,0 +1,953 @@ + + + + + + + Claude How To + + +# Плагіни Claude Code + +Ця папка містить повні приклади плагінів, які обʼєднують кілька функцій Claude Code у цілісні пакети, що встановлюються однією командою. + +## Огляд + +Плагіни Claude Code — це обʼєднані колекції кастомізацій (слеш-команди, субагенти, MCP-сервери та хуки), які встановлюються однією командою. Вони є механізмом розширення найвищого рівня — поєднуючи кілька функцій у цілісні пакети, якими можна ділитися. + +## Архітектура плагінів + +```mermaid +graph TB + A["Plugin"] + B["Slash Commands"] + C["Subagents"] + D["MCP Servers"] + E["Hooks"] + F["Configuration"] + + A -->|bundles| B + A -->|bundles| C + A -->|bundles| D + A -->|bundles| E + A -->|bundles| F +``` + +## Процес завантаження плагіна + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Plugin as Plugin Marketplace + participant Install as Installation + participant SlashCmds as Slash Commands + participant Subagents + participant MCPServers as MCP Servers + participant Hooks + participant Tools as Configured Tools + + User->>Claude: /plugin install pr-review + Claude->>Plugin: Download plugin manifest + Plugin-->>Claude: Return plugin definition + Claude->>Install: Extract components + Install->>SlashCmds: Configure + Install->>Subagents: Configure + Install->>MCPServers: Configure + Install->>Hooks: Configure + SlashCmds-->>Tools: Ready to use + Subagents-->>Tools: Ready to use + MCPServers-->>Tools: Ready to use + Hooks-->>Tools: Ready to use + Tools-->>Claude: Plugin installed ✅ +``` + +## Типи та дистрибуція плагінів + +| Тип | Область | Спільний | Авторитет | Приклади | +|-----|---------|----------|-----------|----------| +| Офіційний | Глобальний | Усі користувачі | Anthropic | PR Review, Security Guidance | +| Спільнота | Публічний | Усі користувачі | Спільнота | DevOps, Data Science | +| Організація | Внутрішній | Члени команди | Компанія | Внутрішні стандарти, інструменти | +| Персональний | Індивідуальний | Один користувач | Розробник | Кастомні робочі процеси | + +## Структура визначення плагіна + +Маніфест плагіна використовує формат JSON у файлі `.claude-plugin/plugin.json`: + +```json +{ + "name": "my-first-plugin", + "description": "A greeting plugin", + "version": "1.0.0", + "author": { + "name": "Your Name" + }, + "homepage": "https://example.com", + "repository": "https://github.com/user/repo", + "license": "MIT" +} +``` + +## Приклад структури плагіна + +``` +my-plugin/ +├── .claude-plugin/ +│ └── plugin.json # Маніфест (назва, опис, версія, автор) +├── commands/ # Навички як Markdown-файли +│ ├── task-1.md +│ ├── task-2.md +│ └── workflows/ +├── agents/ # Визначення кастомних агентів +│ ├── specialist-1.md +│ ├── specialist-2.md +│ └── configs/ +├── skills/ # Навички агентів з файлами SKILL.md +│ ├── skill-1.md +│ └── skill-2.md +├── hooks/ # Обробники подій у hooks.json +│ └── hooks.json +├── .mcp.json # Конфігурації MCP-серверів +├── .lsp.json # Конфігурації LSP-серверів для інтелектуальної роботи з кодом +├── bin/ # Виконувані файли, додані до PATH інструменту Bash поки плагін увімкнено +├── settings.json # Стандартні налаштування при увімкненні плагіна (наразі підтримується лише ключ `agent`) +├── templates/ +│ └── issue-template.md +├── scripts/ +│ ├── helper-1.sh +│ └── helper-2.py +├── docs/ +│ ├── README.md +│ └── USAGE.md +└── tests/ + └── plugin.test.js +``` + +### Конфігурація LSP-сервера + +Плагіни можуть включати підтримку Language Server Protocol (LSP — протокол мовного сервера) для інтелектуальної роботи з кодом у реальному часі. LSP-сервери надають діагностику, навігацію по коду та інформацію про символи під час роботи. + +**Розташування конфігурації**: +- Файл `.lsp.json` у кореневому каталозі плагіна +- Інлайн-ключ `lsp` у `plugin.json` + +#### Довідник полів + +| Поле | Обовʼязкове | Опис | +|------|-------------|------| +| `command` | Так | Бінарний файл LSP-сервера (має бути в PATH) | +| `extensionToLanguage` | Так | Відповідність розширень файлів ідентифікаторам мов | +| `args` | Ні | Аргументи командного рядка для сервера | +| `transport` | Ні | Метод комунікації: `stdio` (за замовчуванням) або `socket` | +| `env` | Ні | Змінні оточення для процесу сервера | +| `initializationOptions` | Ні | Опції, що надсилаються під час ініціалізації LSP | +| `settings` | Ні | Конфігурація робочого простору, що передається серверу | +| `workspaceFolder` | Ні | Перевизначення шляху до папки робочого простору | +| `startupTimeout` | Ні | Максимальний час (мс) очікування запуску сервера | +| `shutdownTimeout` | Ні | Максимальний час (мс) для коректного завершення | +| `restartOnCrash` | Ні | Автоматичний перезапуск при збої сервера | +| `maxRestarts` | Ні | Максимальна кількість спроб перезапуску | + +#### Приклади конфігурацій + +**Go (gopls)**: + +```json +{ + "go": { + "command": "gopls", + "args": ["serve"], + "extensionToLanguage": { + ".go": "go" + } + } +} +``` + +**Python (pyright)**: + +```json +{ + "python": { + "command": "pyright-langserver", + "args": ["--stdio"], + "extensionToLanguage": { + ".py": "python", + ".pyi": "python" + } + } +} +``` + +**TypeScript**: + +```json +{ + "typescript": { + "command": "typescript-language-server", + "args": ["--stdio"], + "extensionToLanguage": { + ".ts": "typescript", + ".tsx": "typescriptreact", + ".js": "javascript", + ".jsx": "javascriptreact" + } + } +} +``` + +#### Доступні LSP-плагіни + +Офіційний маркетплейс включає попередньо налаштовані LSP-плагіни: + +| Плагін | Мова | Бінарний файл сервера | Команда встановлення | +|--------|------|----------------------|---------------------| +| `pyright-lsp` | Python | `pyright-langserver` | `pip install pyright` | +| `typescript-lsp` | TypeScript/JavaScript | `typescript-language-server` | `npm install -g typescript-language-server typescript` | +| `rust-lsp` | Rust | `rust-analyzer` | Встановлення через `rustup component add rust-analyzer` | + +#### Можливості LSP + +Після налаштування LSP-сервери надають: + +- **Миттєва діагностика** — помилки та попередження зʼявляються одразу після редагування +- **Навігація по коду** — перехід до визначення, пошук посилань, реалізацій +- **Інформація при наведенні** — сигнатури типів та документація при наведенні курсора +- **Список символів** — перегляд символів у поточному файлі або робочому просторі + +## Опції плагіна (v2.1.83+) + +Плагіни можуть оголошувати користувацькі опції в маніфесті через `userConfig`. Значення з позначкою `sensitive: true` зберігаються у системному сховищі ключів (keychain), а не в текстових файлах налаштувань: + +```json +{ + "name": "my-plugin", + "version": "1.0.0", + "userConfig": { + "apiKey": { + "description": "API key for the service", + "sensitive": true + }, + "region": { + "description": "Deployment region", + "default": "us-east-1" + } + } +} +``` + +## Постійні дані плагіна (`${CLAUDE_PLUGIN_DATA}`) (v2.1.78+) + +Плагіни мають доступ до каталогу постійного стану через змінну оточення `${CLAUDE_PLUGIN_DATA}`. Цей каталог є унікальним для кожного плагіна та зберігається між сесіями, що робить його придатним для кешів, баз даних та іншого постійного стану: + +```json +{ + "hooks": { + "PostToolUse": [ + { + "command": "node ${CLAUDE_PLUGIN_DATA}/track-usage.js" + } + ] + } +} +``` + +Каталог створюється автоматично при встановленні плагіна. Файли зберігаються до видалення плагіна. + +## Інлайн-плагін через налаштування (`source: 'settings'`) (v2.1.80+) + +Плагіни можна визначати інлайн у файлах налаштувань як записи маркетплейсу з полем `source: 'settings'`. Це дозволяє вбудовувати визначення плагіна безпосередньо, без окремого репозиторію або маркетплейсу: + +```json +{ + "pluginMarketplaces": [ + { + "name": "inline-tools", + "source": "settings", + "plugins": [ + { + "name": "quick-lint", + "source": "./local-plugins/quick-lint" + } + ] + } + ] +} +``` + +## Налаштування плагіна + +Плагіни можуть постачатися з файлом `settings.json` для стандартної конфігурації. Наразі підтримується ключ `agent`, який встановлює основного агента потоку для плагіна: + +```json +{ + "agent": "agents/specialist-1.md" +} +``` + +Коли плагін включає `settings.json`, його стандартні значення застосовуються при встановленні. Користувачі можуть перевизначити ці налаштування у своїй конфігурації проєкту або користувача. + +## Автономний vs плагін-підхід + +| Підхід | Назви команд | Конфігурація | Найкраще для | +|--------|-------------|--------------|--------------| +| **Автономний** | `/hello` | Ручне налаштування в CLAUDE.md | Персональне, специфічне для проєкту | +| **Плагіни** | `/plugin-name:hello` | Автоматичне через plugin.json | Поширення, дистрибуція, командна робота | + +Використовуйте **автономні слеш-команди** для швидких персональних робочих процесів. Використовуйте **плагіни**, коли хочете обʼєднати кілька функцій, поділитися з командою або опублікувати для дистрибуції. + +## Практичні приклади + +### Приклад 1: Плагін PR Review + +**Файл:** `.claude-plugin/plugin.json` + +```json +{ + "name": "pr-review", + "version": "1.0.0", + "description": "Complete PR review workflow with security, testing, and docs", + "author": { + "name": "Anthropic" + }, + "repository": "https://github.com/your-org/pr-review", + "license": "MIT" +} +``` + +**Файл:** `commands/review-pr.md` + +```markdown +--- +name: Review PR +description: Start comprehensive PR review with security and testing checks +--- + +# PR Review + +This command initiates a complete pull request review including: + +1. Security analysis +2. Test coverage verification +3. Documentation updates +4. Code quality checks +5. Performance impact assessment +``` + +**Файл:** `agents/security-reviewer.md` + +```yaml +--- +name: security-reviewer +description: Security-focused code review +tools: read, grep, diff +--- + +# Security Reviewer + +Specializes in finding security vulnerabilities: +- Authentication/authorization issues +- Data exposure +- Injection attacks +- Secure configuration +``` + +**Встановлення:** + +```bash +/plugin install pr-review + +# Результат: +# ✅ 3 слеш-команди встановлено +# ✅ 3 субагенти налаштовано +# ✅ 2 MCP-сервери підключено +# ✅ 4 хуки зареєстровано +# ✅ Готово до використання! +``` + +### Приклад 2: Плагін DevOps + +**Компоненти:** + +``` +devops-automation/ +├── commands/ +│ ├── deploy.md +│ ├── rollback.md +│ ├── status.md +│ └── incident.md +├── agents/ +│ ├── deployment-specialist.md +│ ├── incident-commander.md +│ └── alert-analyzer.md +├── mcp/ +│ ├── github-config.json +│ ├── kubernetes-config.json +│ └── prometheus-config.json +├── hooks/ +│ ├── pre-deploy.js +│ ├── post-deploy.js +│ └── on-error.js +└── scripts/ + ├── deploy.sh + ├── rollback.sh + └── health-check.sh +``` + +### Приклад 3: Плагін документації + +**Обʼєднані компоненти:** + +``` +documentation/ +├── commands/ +│ ├── generate-api-docs.md +│ ├── generate-readme.md +│ ├── sync-docs.md +│ └── validate-docs.md +├── agents/ +│ ├── api-documenter.md +│ ├── code-commentator.md +│ └── example-generator.md +├── mcp/ +│ ├── github-docs-config.json +│ └── slack-announce-config.json +└── templates/ + ├── api-endpoint.md + ├── function-docs.md + └── adr-template.md +``` + +## Маркетплейс плагінів + +Офіційний каталог плагінів, керований Anthropic — `anthropics/claude-plugins-official`. Адміністратори підприємств також можуть створювати приватні маркетплейси для внутрішньої дистрибуції. + +```mermaid +graph TB + A["Plugin Marketplace"] + B["Official
anthropics/claude-plugins-official"] + C["Community
Marketplace"] + D["Enterprise
Private Registry"] + + A --> B + A --> C + A --> D + + B -->|Categories| B1["Development"] + B -->|Categories| B2["DevOps"] + B -->|Categories| B3["Documentation"] + + C -->|Search| C1["DevOps Automation"] + C -->|Search| C2["Mobile Dev"] + C -->|Search| C3["Data Science"] + + D -->|Internal| D1["Company Standards"] + D -->|Internal| D2["Legacy Systems"] + D -->|Internal| D3["Compliance"] + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#e8f5e9,stroke:#333,color:#333 + style C fill:#f3e5f5,stroke:#333,color:#333 + style D fill:#fff3e0,stroke:#333,color:#333 +``` + +### Конфігурація маркетплейсу + +Підприємства та просунуті користувачі можуть контролювати поведінку маркетплейсу через налаштування: + +| Налаштування | Опис | +|-------------|------| +| `extraKnownMarketplaces` | Додати додаткові джерела маркетплейсу крім стандартних | +| `strictKnownMarketplaces` | Контролювати, які маркетплейси дозволено додавати користувачам | +| `deniedPlugins` | Блок-список для запобігання встановленню конкретних плагінів (керований адміністратором) | + +### Додаткові функції маркетплейсу + +- **Стандартний таймаут git**: Збільшено з 30с до 120с для великих репозиторіїв плагінів +- **Кастомні npm-реєстри**: Плагіни можуть вказувати URL кастомних npm-реєстрів для розвʼязання залежностей +- **Фіксація версій**: Закріплення плагінів за конкретними версіями для відтворюваних середовищ + +### Схема визначення маркетплейсу + +Маркетплейси плагінів визначаються у `.claude-plugin/marketplace.json`: + +```json +{ + "name": "my-team-plugins", + "owner": "my-org", + "plugins": [ + { + "name": "code-standards", + "source": "./plugins/code-standards", + "description": "Enforce team coding standards", + "version": "1.2.0", + "author": "platform-team" + }, + { + "name": "deploy-helper", + "source": { + "source": "github", + "repo": "my-org/deploy-helper", + "ref": "v2.0.0" + }, + "description": "Deployment automation workflows" + } + ] +} +``` + +| Поле | Обовʼязкове | Опис | +|------|-------------|------| +| `name` | Так | Назва маркетплейсу в kebab-case | +| `owner` | Так | Організація або користувач, що підтримує маркетплейс | +| `plugins` | Так | Масив записів плагінів | +| `plugins[].name` | Так | Назва плагіна (kebab-case) | +| `plugins[].source` | Так | Джерело плагіна (рядок шляху або обʼєкт джерела) | +| `plugins[].description` | Ні | Короткий опис плагіна | +| `plugins[].version` | Ні | Рядок семантичної версії | +| `plugins[].author` | Ні | Імʼя автора плагіна | + +### Типи джерел плагінів + +Плагіни можуть завантажуватися з кількох місць: + +| Джерело | Синтаксис | Приклад | +|---------|-----------|---------| +| **Відносний шлях** | Рядок шляху | `"./plugins/my-plugin"` | +| **GitHub** | `{ "source": "github", "repo": "owner/repo" }` | `{ "source": "github", "repo": "acme/lint-plugin", "ref": "v1.0" }` | +| **Git URL** | `{ "source": "url", "url": "..." }` | `{ "source": "url", "url": "https://git.internal/plugin.git" }` | +| **Підкаталог Git** | `{ "source": "git-subdir", "url": "...", "path": "..." }` | `{ "source": "git-subdir", "url": "https://github.com/org/monorepo.git", "path": "packages/plugin" }` | +| **npm** | `{ "source": "npm", "package": "..." }` | `{ "source": "npm", "package": "@acme/claude-plugin", "version": "^2.0" }` | +| **pip** | `{ "source": "pip", "package": "..." }` | `{ "source": "pip", "package": "claude-data-plugin", "version": ">=1.0" }` | + +Джерела GitHub та git підтримують необовʼязкові поля `ref` (гілка/тег) та `sha` (хеш коміту) для фіксації версій. + +### Методи дистрибуції + +**GitHub (рекомендовано)**: +```bash +# Користувачі додають ваш маркетплейс +/plugin marketplace add owner/repo-name +``` + +**Інші git-сервіси** (потрібен повний URL): +```bash +/plugin marketplace add https://gitlab.com/org/marketplace-repo.git +``` + +**Приватні репозиторії**: Підтримуються через git credential helpers або токени оточення. Користувачі повинні мати доступ на читання до репозиторію. + +**Подання до офіційного маркетплейсу**: Подавайте плагіни до курованого Anthropic маркетплейсу для ширшої дистрибуції через [claude.ai/settings/plugins/submit](https://claude.ai/settings/plugins/submit) або [platform.claude.com/plugins/submit](https://platform.claude.com/plugins/submit). + +### Суворий режим (strict mode) + +Контроль взаємодії визначень маркетплейсу з локальними файлами `plugin.json`: + +| Налаштування | Поведінка | +|-------------|----------| +| `strict: true` (за замовчуванням) | Локальний `plugin.json` є авторитетним; запис маркетплейсу доповнює його | +| `strict: false` | Запис маркетплейсу є повним визначенням плагіна | + +**Обмеження організації** через `strictKnownMarketplaces`: + +| Значення | Ефект | +|----------|-------| +| Не встановлено | Без обмежень — користувачі можуть додавати будь-який маркетплейс | +| Порожній масив `[]` | Блокування — маркетплейси заборонені | +| Масив патернів | Білий список — дозволено лише маркетплейси, що відповідають патернам | + +```json +{ + "strictKnownMarketplaces": [ + "my-org/*", + "github.com/trusted-vendor/*" + ] +} +``` + +> **Увага**: У суворому режимі з `strictKnownMarketplaces` користувачі можуть встановлювати плагіни лише з маркетплейсів білого списку. Це корисно для корпоративних середовищ, що вимагають контрольованої дистрибуції плагінів. + +## Встановлення та життєвий цикл плагіна + +```mermaid +graph LR + A["Discover"] -->|Browse| B["Marketplace"] + B -->|Select| C["Plugin Page"] + C -->|View| D["Components"] + D -->|Install| E["/plugin install"] + E -->|Extract| F["Configure"] + F -->|Activate| G["Use"] + G -->|Check| H["Update"] + H -->|Available| G + G -->|Done| I["Disable"] + I -->|Later| J["Enable"] + J -->|Back| G +``` + +## Порівняння функцій плагінів + +| Функція | Слеш-команда | Навичка | Субагент | Плагін | +|---------|-------------|---------|----------|--------| +| **Встановлення** | Ручне копіювання | Ручне копіювання | Ручна конфігурація | Одна команда | +| **Час налаштування** | 5 хвилин | 10 хвилин | 15 хвилин | 2 хвилини | +| **Обʼєднання** | Один файл | Один файл | Один файл | Кілька | +| **Версіонування** | Ручне | Ручне | Ручне | Автоматичне | +| **Поширення в команді** | Копіювання файлу | Копіювання файлу | Копіювання файлу | ID встановлення | +| **Оновлення** | Ручне | Ручне | Ручне | Автоматично доступне | +| **Залежності** | Немає | Немає | Немає | Можуть включати | +| **Маркетплейс** | Ні | Ні | Ні | Так | +| **Дистрибуція** | Репозиторій | Репозиторій | Репозиторій | Маркетплейс | + +## CLI-команди плагінів + +Усі операції з плагінами доступні як CLI-команди: + +```bash +claude plugin install @ # Встановити з маркетплейсу +claude plugin uninstall # Видалити плагін +claude plugin list # Список встановлених плагінів +claude plugin enable # Увімкнути вимкнений плагін +claude plugin disable # Вимкнути плагін +claude plugin validate # Валідація структури плагіна +``` + +## Методи встановлення + +### З маркетплейсу +```bash +/plugin install plugin-name +# або з CLI: +claude plugin install plugin-name@marketplace-name +``` + +### Увімкнення / Вимкнення (з автовизначенням області) +```bash +/plugin enable plugin-name +/plugin disable plugin-name +``` + +### Локальний плагін (для розробки) +```bash +# CLI-прапорець для локального тестування (повторюваний для кількох плагінів) +claude --plugin-dir ./path/to/plugin +claude --plugin-dir ./plugin-a --plugin-dir ./plugin-b +``` + +### З Git-репозиторію +```bash +/plugin install github:username/repo +``` + +## Коли створювати плагін + +```mermaid +graph TD + A["Should I create a plugin?"] + A -->|Need multiple components| B{"Multiple commands
or subagents
or MCPs?"} + B -->|Yes| C["✅ Create Plugin"] + B -->|No| D["Use Individual Feature"] + A -->|Team workflow| E{"Share with
team?"} + E -->|Yes| C + E -->|No| F["Keep as Local Setup"] + A -->|Complex setup| G{"Needs auto
configuration?"} + G -->|Yes| C + G -->|No| D +``` + +### Випадки використання плагінів + +| Випадок | Рекомендація | Чому | +|---------|-------------|------| +| **Онбординг команди** | ✅ Плагін | Миттєве налаштування, усі конфігурації | +| **Налаштування фреймворку** | ✅ Плагін | Обʼєднує команди, специфічні для фреймворку | +| **Корпоративні стандарти** | ✅ Плагін | Централізована дистрибуція, контроль версій | +| **Швидка автоматизація** | ❌ Команда | Надмірна складність | +| **Одна предметна область** | ❌ Навичка | Занадто важко, використовуйте навичку | +| **Спеціалізований аналіз** | ❌ Субагент | Створіть вручну або використовуйте навичку | +| **Доступ до живих даних** | ❌ MCP | Автономний, не обʼєднуйте | + +## Тестування плагіна + +Перед публікацією протестуйте плагін локально за допомогою CLI-прапорця `--plugin-dir` (повторюваний для кількох плагінів): + +```bash +claude --plugin-dir ./my-plugin +claude --plugin-dir ./my-plugin --plugin-dir ./another-plugin +``` + +Це запускає Claude Code з завантаженим плагіном, дозволяючи: +- Перевірити доступність усіх слеш-команд +- Протестувати коректну роботу субагентів та агентів +- Підтвердити правильне підключення MCP-серверів +- Валідувати виконання хуків +- Перевірити конфігурації LSP-серверів +- Виявити помилки конфігурації + +## Гаряче перезавантаження (Hot-Reload) + +Плагіни підтримують гаряче перезавантаження під час розробки. При зміні файлів плагіна Claude Code може автоматично виявляти зміни. Також можна примусово перезавантажити командою: + +```bash +/reload-plugins +``` + +Це повторно зчитує всі маніфести плагінів, команди, агентів, навички, хуки та конфігурації MCP/LSP без перезапуску сесії. + +## Керовані налаштування для плагінів + +Адміністратори можуть контролювати поведінку плагінів в організації через керовані налаштування (managed settings): + +| Налаштування | Опис | +|-------------|------| +| `enabledPlugins` | Білий список плагінів, увімкнених за замовчуванням | +| `deniedPlugins` | Блок-список плагінів, які не можна встановити | +| `extraKnownMarketplaces` | Додаткові джерела маркетплейсу крім стандартних | +| `strictKnownMarketplaces` | Обмеження маркетплейсів, які дозволено додавати користувачам | +| `allowedChannelPlugins` | Контроль дозволених плагінів для кожного каналу випуску | + +Ці налаштування можна застосувати на рівні організації через файли керованої конфігурації, і вони мають пріоритет над налаштуваннями рівня користувача. + +## Безпека плагінів + +Субагенти плагінів працюють в обмеженій пісочниці (sandbox). Наступні ключі frontmatter **заборонені** у визначеннях субагентів плагінів: + +- `hooks` — субагенти не можуть реєструвати обробники подій +- `mcpServers` — субагенти не можуть налаштовувати MCP-сервери +- `permissionMode` — субагенти не можуть перевизначати модель дозволів + +Це гарантує, що плагіни не можуть підвищити привілеї або модифікувати хост-середовище за межами оголошеної області. + +## Публікація плагіна + +**Кроки для публікації:** + +1. Створити структуру плагіна з усіма компонентами +2. Написати маніфест `.claude-plugin/plugin.json` +3. Створити `README.md` з документацією +4. Протестувати локально за допомогою `claude --plugin-dir ./my-plugin` +5. Подати до маркетплейсу плагінів +6. Пройти перевірку та затвердження +7. Публікація в маркетплейсі +8. Користувачі можуть встановити однією командою + +**Приклад подання:** + +```markdown +# PR Review Plugin + +## Description +Complete PR review workflow with security, testing, and documentation checks. + +## What's Included +- 3 slash commands for different review types +- 3 specialized subagents +- GitHub and CodeQL MCP integration +- Automated security scanning hooks + +## Installation +```bash +/plugin install pr-review +``` + +## Features +✅ Security analysis +✅ Test coverage checking +✅ Documentation verification +✅ Code quality assessment +✅ Performance impact analysis + +## Usage +```bash +/review-pr +/check-security +/check-tests +``` + +## Requirements +- Claude Code 1.0+ +- GitHub access +- CodeQL (optional) +``` + +## Плагін vs ручна конфігурація + +**Ручне налаштування (2+ години):** +- Встановити слеш-команди одну за одною +- Створити субагентів окремо +- Налаштувати MCP окремо +- Встановити хуки вручну +- Задокументувати все +- Поширити в команді (сподіватися, що налаштують правильно) + +**З плагіном (2 хвилини):** +```bash +/plugin install pr-review +# ✅ Все встановлено та налаштовано +# ✅ Готово до використання одразу +# ✅ Команда може відтворити точну конфігурацію +``` + +## Найкращі практики + +### Рекомендовано ✅ +- Використовуйте зрозумілі, описові назви плагінів +- Включайте вичерпний README +- Версіонуйте плагін правильно (semver — семантичне версіонування) +- Тестуйте всі компоненти разом +- Документуйте вимоги чітко +- Надавайте приклади використання +- Включайте обробку помилок +- Тегуйте належним чином для виявлення +- Підтримуйте зворотну сумісність +- Тримайте плагіни зосередженими та цілісними +- Включайте вичерпні тести +- Документуйте всі залежності + +### Не рекомендовано ❌ +- Не обʼєднуйте неповʼязані функції +- Не зашивайте облікові дані в код +- Не пропускайте тестування +- Не забувайте про документацію +- Не створюйте надлишкових плагінів +- Не ігноруйте версіонування +- Не ускладнюйте залежності компонентів +- Не забувайте обробляти помилки коректно + +## Інструкції зі встановлення + +### Встановлення з маркетплейсу + +1. **Перегляд доступних плагінів:** + ```bash + /plugin list + ``` + +2. **Деталі плагіна:** + ```bash + /plugin info plugin-name + ``` + +3. **Встановлення плагіна:** + ```bash + /plugin install plugin-name + ``` + +### Встановлення з локального шляху + +```bash +/plugin install ./path/to/plugin-directory +``` + +### Встановлення з GitHub + +```bash +/plugin install github:username/repo +``` + +### Список встановлених плагінів + +```bash +/plugin list --installed +``` + +### Оновлення плагіна + +```bash +/plugin update plugin-name +``` + +### Вимкнення/Увімкнення плагіна + +```bash +# Тимчасове вимкнення +/plugin disable plugin-name + +# Повторне увімкнення +/plugin enable plugin-name +``` + +### Видалення плагіна + +```bash +/plugin uninstall plugin-name +``` + +## Повʼязані концепції + +Наступні функції Claude Code працюють разом з плагінами: + +- **[Слеш-команди](../01-slash-commands/)** — окремі команди, обʼєднані в плагіни +- **[Памʼять](../02-memory/)** — постійний контекст для плагінів +- **[Навички](../03-skills/)** — предметна експертиза, яку можна обгорнути в плагіни +- **[Субагенти](../04-subagents/)** — спеціалізовані агенти як компоненти плагінів +- **[MCP-сервери](../05-mcp/)** — інтеграції Model Context Protocol, обʼєднані в плагіни +- **[Хуки](../06-hooks/)** — обробники подій, що запускають робочі процеси плагінів + +## Повний приклад робочого процесу + +### Повний робочий процес плагіна PR Review + +``` +1. Користувач: /review-pr + +2. Плагін виконує: + ├── pre-review.js хук валідує git-репо + ├── GitHub MCP отримує дані PR + ├── security-reviewer субагент аналізує безпеку + ├── test-checker субагент перевіряє покриття + └── performance-analyzer субагент перевіряє продуктивність + +3. Результати синтезуються та представляються: + ✅ Безпека: Критичних проблем не виявлено + ⚠️ Тестування: Покриття 65% (рекомендовано 80%+) + ✅ Продуктивність: Значного впливу немає + 📝 Надано 12 рекомендацій +``` + +## Усунення несправностей + +### Плагін не встановлюється +- Перевірте сумісність версії Claude Code: `/version` +- Перевірте синтаксис `plugin.json` валідатором JSON +- Перевірте підключення до інтернету (для віддалених плагінів) +- Перевірте дозволи: `ls -la plugin/` + +### Компоненти не завантажуються +- Переконайтеся, що шляхи в `plugin.json` відповідають фактичній структурі каталогів +- Перевірте дозволи файлів: `chmod +x scripts/` +- Перегляньте синтаксис файлів компонентів +- Перевірте журнали: `/plugin debug plugin-name` + +### Збій підключення MCP +- Переконайтеся, що змінні оточення встановлені правильно +- Перевірте встановлення та працездатність MCP-сервера +- Протестуйте підключення MCP окремо за допомогою `/mcp test` +- Перегляньте конфігурацію MCP у каталозі `mcp/` + +### Команди недоступні після встановлення +- Переконайтеся, що плагін встановлено успішно: `/plugin list --installed` +- Перевірте, чи плагін увімкнено: `/plugin status plugin-name` +- Перезапустіть Claude Code: `exit` та відкрийте знову +- Перевірте конфлікти назв з існуючими командами + +### Проблеми з виконанням хуків +- Переконайтеся, що файли хуків мають правильні дозволи +- Перевірте синтаксис хуків та назви подій +- Перегляньте журнали хуків для деталей помилок +- Протестуйте хуки вручну, якщо можливо + +## Додаткові ресурси + +- [Офіційна документація плагінів](https://code.claude.com/docs/en/plugins) +- [Каталог плагінів](https://code.claude.com/docs/en/discover-plugins) +- [Маркетплейси плагінів](https://code.claude.com/docs/en/plugin-marketplaces) +- [Довідник плагінів](https://code.claude.com/docs/en/plugins-reference) +- [Довідник MCP-серверів](https://modelcontextprotocol.io/) +- [Посібник конфігурації субагентів](../04-subagents/README.md) +- [Довідник системи хуків](../06-hooks/README.md) + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/09-advanced-features/README.md b/uk/09-advanced-features/README.md new file mode 100644 index 0000000..5705faf --- /dev/null +++ b/uk/09-advanced-features/README.md @@ -0,0 +1,1945 @@ + + + Claude How To + + +# Розширені функції + +Повний посібник з розширених можливостей Claude Code, включаючи режим планування, розширене мислення, автоматичний режим, фонові завдання, режими дозволів, режим друку (неінтерактивний), управління сесіями, інтерактивні функції, канали, голосовий ввід, дистанційне керування, веб-сесії, десктопний додаток, список завдань, підказки промптів, git worktrees, пісочницю, керовані налаштування та конфігурацію. + +## Зміст + +1. [Огляд](#огляд) +2. [Режим планування](#режим-планування) +3. [Розширене мислення](#розширене-мислення) +4. [Auto Mode](#auto-mode) +5. [Фонові завдання](#фонові-завдання) +6. [Заплановані завдання](#заплановані-завдання) +7. [Режими дозволів](#режими-дозволів) +8. [Headless Mode](#headless-mode) +9. [Управління сесіями](#управління-сесіями) +10. [Інтерактивні функції](#інтерактивні-функції) +11. [Голосовий ввід](#голосовий-ввід) +12. [Канали](#канали) +13. [Інтеграція Chrome](#інтеграція-chrome) +14. [Remote Control](#remote-control) +15. [Веб-сесії](#веб-сесії) +16. [Десктопний додаток](#десктопний-додаток) +17. [Список завдань](#список-завдань) +18. [Підказки промптів](#підказки-промптів) +19. [Git Worktrees](#git-worktrees) +20. [Пісочниця](#пісочниця) +21. [Керовані налаштування (Enterprise)](#керовані-налаштування-enterprise) +22. [Конфігурація та налаштування](#конфігурація-та-налаштування) +23. [Agent Teams](#agent-teams) +24. [Найкращі практики](#найкращі-практики) +25. [Додаткові ресурси](#додаткові-ресурси) + +--- + +## Огляд + +Розширені функції Claude Code доповнюють базові можливості плануванням, міркуванням, автоматизацією та механізмами контролю. Ці функції забезпечують складні робочі процеси для комплексних завдань розробки, ревʼю коду, автоматизації та управління кількома сесіями. + +**Ключові розширені функції:** +- **Режим планування**: Створення детальних планів реалізації перед кодуванням +- **Розширене мислення**: Глибоке міркування для складних проблем +- **Auto Mode**: Фоновий класифікатор безпеки перевіряє кожну дію перед виконанням (Research Preview) +- **Фонові завдання**: Виконання тривалих операцій без блокування розмови +- **Режими дозволів**: Контроль дій Claude (`default`, `acceptEdits`, `plan`, `auto`, `dontAsk`, `bypassPermissions`) +- **Режим друку**: Неінтерактивний запуск Claude Code для автоматизації та CI/CD (`claude -p`) +- **Управління сесіями**: Управління кількома робочими сесіями +- **Інтерактивні функції**: Клавіатурні скорочення, багаторядковий ввід та історія команд +- **Голосовий ввід**: Push-to-talk голосовий ввід з підтримкою STT для 20 мов +- **Канали**: MCP-сервери надсилають повідомлення в активні сесії (Research Preview) +- **Remote Control**: Управління Claude Code з Claude.ai або додатку Claude +- **Веб-сесії**: Запуск Claude Code у браузері на claude.ai/code +- **Десктопний додаток**: Автономний додаток для візуального перегляду diff та кількох сесій +- **Список завдань**: Постійне відстеження завдань між стисненнями контексту +- **Підказки промптів**: Розумні підказки команд на основі контексту +- **Git Worktrees**: Ізольовані робочі дерева для паралельної роботи +- **Пісочниця**: Ізоляція файлової системи та мережі на рівні ОС +- **Керовані налаштування**: Корпоративне розгортання через plist, Registry або керовані файли +- **Конфігурація**: Налаштування поведінки за допомогою JSON-файлів конфігурації + +--- + +## Режим планування + +Режим планування дозволяє Claude продумати складні завдання перед їх реалізацією, створюючи детальний план, який ви можете переглянути та затвердити. + +### Що таке режим планування? + +Режим планування — це двофазний підхід: +1. **Фаза планування**: Claude аналізує завдання та створює детальний план реалізації +2. **Фаза реалізації**: Після затвердження Claude виконує план + +### Коли використовувати режим планування + +✅ Використовуйте для: +- Складного рефакторингу кількох файлів +- Реалізації нових функцій +- Архітектурних змін +- Міграцій баз даних +- Масштабних змін API + +❌ Не використовуйте для: +- Простого виправлення помилок +- Змін форматування +- Редагування одного файлу +- Швидких запитів + +### Активація режиму планування + +**Слеш-команда**: +```bash +/plan Implement user authentication system +``` + +**Прапорець CLI**: +```bash +claude --permission-mode plan +``` + +**Встановити за замовчуванням**: +```json +{ + "permissions": { + "defaultMode": "plan" + } +} +``` + +**Клавіатурне скорочення**: +- `Shift + Tab` — Перемикання режимів дозволів (включно з plan) +- `Alt + M` — Перемикання режимів дозволів (Windows/Linux) + +### Переваги режиму планування + +- **Структурований підхід до реалізації**: Детальна розбивка кроків реалізації +- **Перегляд та затвердження**: Затвердіть або скоригуйте план перед виконанням +- **Виявлення ризиків**: Визначення потенційних проблем до реалізації +- **Чіткі фази**: Організовані фази та етапи реалізації + +### Приклад: Реалізація функції + +``` +User: /plan Add a real-time notification system + +Claude: I'll create a plan for implementing real-time notifications. + +## Implementation Plan + +### Phase 1: Infrastructure Setup +1. Install WebSocket libraries (socket.io) +2. Set up WebSocket server +3. Configure connection management + +### Phase 2: Backend Implementation +4. Create notification service +5. Implement notification queue +6. Add database schema for notifications +7. Create API endpoints + +### Phase 3: Frontend Integration +8. Set up WebSocket client +9. Create notification UI components +10. Implement notification state management +11. Add notification permissions + +### Phase 4: Testing & Deployment +12. Write unit tests +13. Write integration tests +14. Update documentation +15. Deploy to staging + +Estimated time: 3-4 hours +Files to modify: 12 +New files to create: 8 + +Ready to proceed? (yes/no/modify plan) + +User: yes + +Claude: [Begins implementation following the plan] +``` + +### Модифікація планів + +``` +User: Modify the plan - skip the queue for now, we'll add it later + +Claude: Updated plan: +[Shows modified plan with queue removed] + +User: Looks good, proceed + +Claude: [Implements modified plan] +``` + +### Конфігурація режиму планування + +Режим планування активується через прапорець CLI або слеш-команду: + +```bash +# Активація режиму планування через CLI +claude --permission-mode plan + +# Або використовуйте слеш-команду /plan всередині REPL +/plan Implement user authentication system +``` + +**Псевдонім моделі для планування**: Використовуйте `opusplan` як псевдонім моделі, щоб використовувати Opus для планування та Sonnet для виконання: + +```bash +claude --model opusplan "design and implement the new API" +``` + +**Редагування плану зовні**: Натисніть `Ctrl+G`, щоб відкрити поточний план у зовнішньому редакторі для детальних змін. + +### Ultraplan + +Використовуйте `/ultraplan ` для наскрізного робочого процесу планування: Claude складає детальний план, відкриває його у браузері для перегляду, потім виконує план віддалено або повертає його у ваш термінал для локального виконання. + +--- + +## Розширене мислення + +Розширене мислення дозволяє Claude витрачати більше часу на обмірковування складних проблем перед наданням рішення. + +### Що таке розширене мислення? + +Розширене мислення — це цілеспрямований покроковий процес міркування, де Claude: +- Розбиває складні проблеми на частини +- Розглядає кілька підходів +- Оцінює компроміси +- Продумує граничні випадки + +### Активація розширеного мислення + +**Клавіатурне скорочення**: +- `Option + T` (macOS) / `Alt + T` (Windows/Linux) — Перемикання розширеного мислення + +**Автоматична активація**: +- Увімкнено за замовчуванням для всіх моделей (Opus 4.6, Sonnet 4.6, Haiku 4.5) +- Opus 4.6: Адаптивне міркування з рівнями зусиль: `low` (○), `medium` (◐), `high` (●), `max` (тільки Opus 4.6) +- Інші моделі: Фіксований бюджет до 31 999 токенів + +**Методи конфігурації**: +- Перемикання: `Alt+T` / `Option+T`, або через `/config` +- Перегляд міркувань: `Ctrl+O` (детальний режим) +- Встановлення зусиль: команда `/effort` або прапорець `--effort` + +**Власний бюджет**: +```bash +export MAX_THINKING_TOKENS=1024 +``` + +**Рівень зусиль** (тільки Opus 4.6): +```bash +export CLAUDE_CODE_EFFORT_LEVEL=high # low (○), medium (◐), high (●), або max (тільки Opus 4.6) +``` + +**Прапорець CLI**: +```bash +claude --effort high "complex architectural review" +``` + +**Слеш-команда**: +``` +/effort high +``` + +> **Примітка:** Ключове слово "ultrathink" у промптах активує режим глибокого міркування. Рівні зусиль `low`, `medium`, `high` та `max` (тільки Opus 4.6) контролюють обсяг міркувань Claude. + +### Переваги розширеного мислення + +- **Глибоке міркування**: Більше часу на обдумування складних проблем +- **Кращі архітектурні рішення**: Обґрунтовані рішення з комплексною оцінкою +- **Розгляд граничних випадків**: Продумування потенційних проблем і сценаріїв +- **Ретельний аналіз**: Структурований підхід до вирішення складних проблем + +### Приклад: Архітектурне рішення + +``` +User: /think Should we use microservices or a monolith for our e-commerce platform? + +Claude: Let me think through this architectural decision carefully... + + +## Context Analysis +- Team size: 5 developers +- Expected traffic: 10k daily users initially +- Need to scale to 100k+ users +- Limited DevOps resources +- 6-month timeline to MVP + +## Approach 1: Microservices +Pros: ++ Independent scaling ++ Technology flexibility ++ Team independence ++ Fault isolation + +Cons: +- Operational complexity +- Network overhead +- Distributed tracing needed +- Requires DevOps expertise +- Slower initial development + +## Approach 2: Monolith +Pros: ++ Simpler deployment ++ Faster initial development ++ Easier debugging ++ Lower operational overhead ++ Single codebase + +Cons: +- Scaling challenges later +- All-or-nothing deployments +- Technology lock-in +- Potential for tight coupling + +## Decision Factors +1. Team size (5 devs) → Favors monolith +2. DevOps resources (limited) → Favors monolith +3. Timeline (6 months) → Favors monolith +4. Future scale (100k users) → Achievable with monolith + caching +5. Complexity budget → Limited + +## Recommendation +Start with a **modular monolith**: +- Single deployment unit +- Clear module boundaries +- Clean interfaces between modules +- Prepare for future extraction to microservices if needed + +This gives you: +✓ Fast initial development +✓ Low operational complexity +✓ Option to extract services later +✓ Clear architecture + +Migration path: When you reach 50k+ users or specific modules need independent scaling, extract those modules into microservices. + + +**Recommendation**: Implement a modular monolith with clean module boundaries. + +This approach balances your current constraints (team size, timeline, DevOps resources) with future scalability needs. You can migrate specific modules to microservices later when there's a clear business need. +``` + +### Конфігурація розширеного мислення + +Розширене мислення контролюється через змінні оточення, клавіатурні скорочення та прапорці CLI: + +```bash +# Встановлення бюджету токенів мислення +export MAX_THINKING_TOKENS=16000 + +# Встановлення рівня зусиль (тільки Opus 4.6): low (○), medium (◐), high (●), або max (тільки Opus 4.6) +export CLAUDE_CODE_EFFORT_LEVEL=high +``` + +Перемикання під час сесії за допомогою `Alt+T` / `Option+T`, встановлення зусиль через `/effort` або конфігурація через `/config`. + +--- + +## Auto Mode + +Auto Mode — це режим дозволів Research Preview (березень 2026), який використовує фоновий класифікатор безпеки для перевірки кожної дії перед виконанням. Він дозволяє Claude працювати автономно, блокуючи небезпечні операції. + +### Вимоги + +- **План**: Team, Enterprise або API (недоступно на планах Pro або Max) +- **Модель**: Claude Sonnet 4.6 або Opus 4.6 +- **Провайдер**: Тільки Anthropic API (не підтримується на Bedrock, Vertex або Foundry) +- **Класифікатор**: Працює на Claude Sonnet 4.6 (додаткова вартість токенів) + +### Увімкнення Auto Mode + +```bash +# Розблокування auto mode за допомогою прапорця CLI +claude --enable-auto-mode + +# Потім перемикайте через Shift+Tab у REPL +``` + +Або встановіть як режим дозволів за замовчуванням: + +```bash +claude --permission-mode auto +``` + +Встановлення через конфігурацію: +```json +{ + "permissions": { + "defaultMode": "auto" + } +} +``` + +### Як працює класифікатор + +Фоновий класифікатор оцінює кожну дію в такому порядку: + +1. **Правила дозволу/заборони** — Спочатку перевіряються явні правила дозволів +2. **Читання/редагування автоматично затверджуються** — Читання та редагування файлів проходять автоматично +3. **Класифікатор** — Фоновий класифікатор перевіряє дію +4. **Запасний варіант** — Повертається до запиту після 3 послідовних або 20 загальних блокувань + +### Заблоковані дії за замовчуванням + +Auto mode блокує наступне за замовчуванням: + +| Заблокована дія | Приклад | +|----------------|---------| +| Встановлення через pipe-to-shell | `curl \| bash` | +| Надсилання конфіденційних даних назовні | API-ключі, облікові дані через мережу | +| Деплой на продакшн | Команди деплою на продакшн | +| Масове видалення | `rm -rf` на великих директоріях | +| Зміни IAM | Зміни дозволів та ролей | +| Force push у main | `git push --force origin main` | + +### Дозволені дії за замовчуванням + +| Дозволена дія | Приклад | +|----------------|---------| +| Локальні операції з файлами | Читання, запис, редагування файлів проєкту | +| Встановлення оголошених залежностей | `npm install`, `pip install` з маніфесту | +| HTTP тільки для читання | `curl` для отримання документації | +| Push у поточну гілку | `git push origin feature-branch` | + +### Конфігурація Auto Mode + +**Вивести правила за замовчуванням у JSON**: +```bash +claude auto-mode defaults +``` + +**Налаштування довіреної інфраструктури** через керовану настройку `autoMode.environment` для корпоративних розгортань. Це дозволяє адміністраторам визначати довірені середовища CI/CD, цілі деплою та шаблони інфраструктури. + +### Запасна поведінка + +Коли класифікатор невпевнений, auto mode повертається до запиту користувача: +- Після **3 послідовних** блокувань класифікатором +- Після **20 загальних** блокувань класифікатором за сесію + +Це гарантує, що користувач завжди зберігає контроль, коли класифікатор не може впевнено затвердити дію. + +### Посів дозволів Auto-Mode без Team-плану + +Якщо у вас немає Team-плану або ви хочете простіший підхід без фонового класифікатора, ви можете наповнити ваш `~/.claude/settings.json` консервативним базовим набором безпечних правил дозволів. Скрипт починає з правил тільки для читання та локального інспектування, потім дозволяє вам додавати редагування, тести, локальний запис у git, встановлення пакетів та дії запису GitHub лише за потреби. + +**Файл:** `09-advanced-features/setup-auto-mode-permissions.py` + +```bash +# Попередній перегляд змін (без запису) +python3 09-advanced-features/setup-auto-mode-permissions.py --dry-run + +# Застосувати консервативний базовий набір +python3 09-advanced-features/setup-auto-mode-permissions.py + +# Додавати більше можливостей лише за потреби +python3 09-advanced-features/setup-auto-mode-permissions.py --include-edits --include-tests +python3 09-advanced-features/setup-auto-mode-permissions.py --include-git-write --include-packages +``` + +Скрипт додає правила в таких категоріях: + +| Категорія | Приклади | +|----------|---------| +| Базові інструменти тільки для читання | `Read(*)`, `Glob(*)`, `Grep(*)`, `Agent(*)`, `WebSearch(*)`, `WebFetch(*)` | +| Локальне інспектування | `Bash(git status:*)`, `Bash(git log:*)`, `Bash(git diff:*)`, `Bash(cat:*)` | +| Опціональне редагування | `Edit(*)`, `Write(*)`, `NotebookEdit(*)` | +| Опціональні тести/збірка | `Bash(pytest:*)`, `Bash(python3 -m pytest:*)`, `Bash(cargo test:*)` | +| Опціональний запис у git | `Bash(git add:*)`, `Bash(git commit:*)`, `Bash(git stash:*)` | +| Git (локальний запис) | `Bash(git add:*)`, `Bash(git commit:*)`, `Bash(git checkout:*)` | +| Менеджери пакетів | `Bash(npm install:*)`, `Bash(pip install:*)`, `Bash(cargo build:*)` | +| Збірка та тести | `Bash(make:*)`, `Bash(pytest:*)`, `Bash(go test:*)` | +| Звичайні shell-команди | `Bash(ls:*)`, `Bash(cat:*)`, `Bash(find:*)`, `Bash(cp:*)`, `Bash(mv:*)` | +| GitHub CLI | `Bash(gh pr view:*)`, `Bash(gh pr create:*)`, `Bash(gh issue list:*)` | + +Небезпечні операції (`rm -rf`, `sudo`, force push, `DROP TABLE`, `terraform destroy` тощо) навмисно виключені. Скрипт ідемпотентний — повторний запуск не дублює правила. + +--- + +## Фонові завдання + +Фонові завдання дозволяють виконувати тривалі операції без блокування вашої розмови. + +### Що таке фонові завдання? + +Фонові завдання виконуються асинхронно, поки ви продовжуєте працювати: +- Тривалі набори тестів +- Процеси збірки +- Міграції баз даних +- Скрипти деплою +- Інструменти аналізу + +**Базове використання:** +```bash +User: Run tests in background + +Claude: Started task bg-1234 + +/task list # Показати всі завдання +/task status bg-1234 # Перевірити прогрес +/task show bg-1234 # Переглянути вивід +/task cancel bg-1234 # Скасувати завдання +``` + +### Запуск фонових завдань + +``` +User: Run the full test suite in the background + +Claude: Starting tests in background (task-id: bg-1234) +You can continue working while tests run. + +[You can continue the conversation] + +User: Meanwhile, let's refactor the auth module + +Claude: [Works on auth module while tests run in background] + +[Later, when tests complete] + +Claude: 📢 Background task bg-1234 completed: +✅ 245 tests passed +❌ 3 tests failed +View results: /task show bg-1234 +``` + +### Управління фоновими завданнями + +**Список активних завдань**: +``` +User: /task list + +Active background tasks: +1. [bg-1234] Running tests (50% complete, 2min remaining) +2. [bg-1235] Building Docker image (25% complete, 8min remaining) +3. [bg-1236] Deploying to staging (90% complete, 30sec remaining) +``` + +**Перевірка статусу завдання**: +``` +User: /task status bg-1234 + +Task bg-1234: Running tests +Status: In progress +Progress: 120/245 tests (49%) +Started: 2025-11-08 10:30:15 +Estimated completion: 2025-11-08 10:34:22 +``` + +**Перегляд виводу завдання**: +``` +User: /task show bg-1234 + +[Shows live output from the test run] +``` + +**Скасування завдання**: +``` +User: /task cancel bg-1234 + +Cancelled background task bg-1234 +``` + +### Приклад: Паралельна розробка + +``` +User: Run the build in the background + +Claude: Starting build... (task-id: bg-5001) + +User: Also run the linter in background + +Claude: Starting linter... (task-id: bg-5002) + +User: While those run, let's implement the new API endpoint + +Claude: [Implements API endpoint while build and linter run] + +[10 minutes later] + +Claude: 📢 Build completed successfully (bg-5001) +📢 Linter found 12 issues (bg-5002) + +User: Show me the linter issues + +Claude: [Shows linter output from bg-5002] +``` + +### Конфігурація + +```json +{ + "backgroundTasks": { + "enabled": true, + "maxConcurrentTasks": 5, + "notifyOnCompletion": true, + "autoCleanup": true, + "logOutput": true + } +} +``` + +--- + +## Заплановані завдання + +Заплановані завдання дозволяють автоматично запускати промпти за розкладом або як одноразові нагадування. Завдання привʼязані до сесії — вони працюють, поки Claude Code активний, і очищуються при завершенні сесії. Доступно з v2.1.72+. + +### Команда `/loop` + +```bash +# Явний інтервал +/loop 5m check if the deployment finished + +# Природна мова +/loop check build status every 30 minutes +``` + +Також підтримуються стандартні 5-польні cron-вирази для точного планування. + +### Одноразові нагадування + +Встановлення нагадувань, які спрацьовують один раз у визначений час: + +``` +remind me at 3pm to push the release branch +in 45 minutes, run the integration tests +``` + +### Управління запланованими завданнями + +| Інструмент | Опис | +|------|-------------| +| `CronCreate` | Створити нове заплановане завдання | +| `CronList` | Показати всі активні заплановані завдання | +| `CronDelete` | Видалити заплановане завдання | + +**Обмеження та поведінка**: +- До **50 запланованих завдань** на сесію +- Привʼязані до сесії — очищуються при завершенні сесії +- Повторювані завдання автоматично закінчуються через **3 дні** +- Завдання спрацьовують лише під час роботи Claude Code — пропущені запуски не компенсуються + +### Деталі поведінки + +| Аспект | Деталь | +|--------|--------| +| **Джитер повторюваних** | До 10% від інтервалу (макс. 15 хвилин) | +| **Джитер одноразових** | До 90 секунд на межах :00/:30 | +| **Пропущені запуски** | Без компенсації — пропускаються, якщо Claude Code не працював | +| **Збереження** | Не зберігаються між перезапусками | + +### Хмарні заплановані завдання + +Використовуйте `/schedule` для створення хмарних запланованих завдань, які працюють на інфраструктурі Anthropic: + +``` +/schedule daily at 9am run the test suite and report failures +``` + +Хмарні заплановані завдання зберігаються між перезапусками і не потребують локально запущеного Claude Code. + +### Вимкнення запланованих завдань + +```bash +export CLAUDE_CODE_DISABLE_CRON=1 +``` + +### Приклад: Моніторинг деплою + +``` +/loop 5m check the deployment status of the staging environment. + If the deploy succeeded, notify me and stop looping. + If it failed, show the error logs. +``` + +> **Порада**: Заплановані завдання привʼязані до сесії. Для постійної автоматизації, яка переживає перезапуски, використовуйте CI/CD пайплайни, GitHub Actions або заплановані завдання десктопного додатку. + +--- + +## Режими дозволів + +Режими дозволів контролюють, які дії Claude може виконувати без явного схвалення. + +### Доступні режими дозволів + +| Режим | Поведінка | +|---|---| +| `default` | Тільки читання файлів; запитує дозвіл на всі інші дії | +| `acceptEdits` | Читання та редагування файлів; запитує дозвіл на команди | +| `plan` | Тільки читання файлів (режим дослідження, без редагувань) | +| `auto` | Усі дії з перевірками фонового класифікатора безпеки (Research Preview) | +| `bypassPermissions` | Усі дії, без перевірки дозволів (небезпечно) | +| `dontAsk` | Виконуються лише попередньо затверджені інструменти; всі інші відхиляються | + +Перемикайте режими через `Shift+Tab` у CLI. Встановіть режим за замовчуванням через прапорець `--permission-mode` або налаштування `permissions.defaultMode`. + +### Методи активації + +**Клавіатурне скорочення**: +```bash +Shift + Tab # Перемикання між усіма 6 режимами +``` + +**Слеш-команда**: +```bash +/plan # Увійти в режим планування +``` + +**Прапорець CLI**: +```bash +claude --permission-mode plan +claude --permission-mode auto +``` + +**Налаштування**: +```json +{ + "permissions": { + "defaultMode": "auto" + } +} +``` + +### Приклади режимів дозволів + +#### Режим Default +Claude запитує підтвердження на значущі дії: + +``` +User: Fix the bug in auth.ts + +Claude: I need to modify src/auth.ts to fix the bug. +The change will update the password validation logic. + +Approve this change? (yes/no/show) +``` + +#### Режим Plan +Перегляд плану реалізації перед виконанням: + +``` +User: /plan Implement user authentication system + +Claude: I'll create a plan for implementing authentication. + +## Implementation Plan +[Detailed plan with phases and steps] + +Ready to proceed? (yes/no/modify) +``` + +#### Режим Accept Edits +Автоматичне прийняття змін у файлах: + +``` +User: acceptEdits +User: Fix the bug in auth.ts + +Claude: [Makes changes without asking] +``` + +### Випадки використання + +**Ревʼю коду**: +``` +User: claude --permission-mode plan +User: Review this PR and suggest improvements + +Claude: [Reads code, provides feedback, but cannot modify] +``` + +**Парне програмування**: +``` +User: claude --permission-mode default +User: Let's implement the feature together + +Claude: [Asks for approval before each change] +``` + +**Автоматизовані завдання**: +``` +User: claude --permission-mode acceptEdits +User: Fix all linting issues in the codebase + +Claude: [Auto-accepts file edits without asking] +``` + +--- + +## Headless Mode + +Режим друку (`claude -p`) дозволяє запускати Claude Code без інтерактивного вводу, ідеально для автоматизації та CI/CD. Це неінтерактивний режим, що замінює старий прапорець `--headless`. + +### Що таке режим друку? + +Режим друку забезпечує: +- Автоматизоване виконання скриптів +- Інтеграцію з CI/CD +- Пакетну обробку +- Виконання запланованих завдань + +### Запуск у режимі друку (неінтерактивний) + +```bash +# Запуск конкретного завдання +claude -p "Run all tests" + +# Обробка переданого вмісту +cat error.log | claude -p "Analyze these errors" + +# Інтеграція CI/CD (GitHub Actions) +- name: AI Code Review + run: claude -p "Review PR" +``` + +### Додаткові приклади використання режиму друку + +```bash +# Запуск завдання з захопленням виводу +claude -p "Run all tests and generate coverage report" + +# Зі структурованим виводом +claude -p --output-format json "Analyze code quality" + +# З вводом через stdin +echo "Analyze code quality" | claude -p "explain this" +``` + +### Приклад: Інтеграція CI/CD + +**GitHub Actions**: +```yaml +# .github/workflows/code-review.yml +name: AI Code Review + +on: [pull_request] + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Claude Code + run: npm install -g @anthropic-ai/claude-code + + - name: Run Claude Code Review + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + claude -p --output-format json \ + --max-turns 3 \ + "Review this PR for: + - Code quality issues + - Security vulnerabilities + - Performance concerns + - Test coverage + Output results as JSON" > review.json + + - name: Post Review Comment + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const review = JSON.parse(fs.readFileSync('review.json', 'utf8')); + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: JSON.stringify(review, null, 2) + }); +``` + +### Конфігурація режиму друку + +Режим друку (`claude -p`) підтримує кілька прапорців для автоматизації: + +```bash +# Обмеження автономних ходів +claude -p --max-turns 5 "refactor this module" + +# Структурований вивід JSON +claude -p --output-format json "analyze this codebase" + +# З валідацією схеми +claude -p --json-schema '{"type":"object","properties":{"issues":{"type":"array"}}}' \ + "find bugs in this code" + +# Вимкнення збереження сесії +claude -p --no-session-persistence "one-off analysis" +``` + +--- + +## Управління сесіями + +Ефективне управління кількома сесіями Claude Code. + +### Команди управління сесіями + +| Команда | Опис | +|---------|-------------| +| `/resume` | Відновити розмову за ID або назвою | +| `/rename` | Назвати поточну сесію | +| `/fork` | Розгалужити поточну сесію в нову гілку | +| `claude -c` | Продовжити останню розмову | +| `claude -r "session"` | Відновити сесію за назвою або ID | + +### Відновлення сесій + +**Продовжити останню розмову**: +```bash +claude -c +``` + +**Відновити іменовану сесію**: +```bash +claude -r "auth-refactor" "finish this PR" +``` + +**Перейменувати поточну сесію** (всередині REPL): +``` +/rename auth-refactor +``` + +### Розгалуження сесій + +Розгалужте сесію, щоб спробувати альтернативний підхід без втрати оригіналу: + +``` +/fork +``` + +Або з CLI: +```bash +claude --resume auth-refactor --fork-session "try OAuth instead" +``` + +### Збереження сесій + +Сесії автоматично зберігаються і можуть бути відновлені: + +```bash +# Продовжити останню розмову +claude -c + +# Відновити конкретну сесію за назвою або ID +claude -r "auth-refactor" + +# Відновити та розгалужити для експериментів +claude --resume auth-refactor --fork-session "alternative approach" +``` + +--- + +## Інтерактивні функції + +### Клавіатурні скорочення + +Claude Code підтримує клавіатурні скорочення для ефективності. Ось повний довідник з офіційної документації: + +| Скорочення | Опис | +|----------|-------------| +| `Ctrl+C` | Скасувати поточний ввід/генерацію | +| `Ctrl+D` | Вийти з Claude Code | +| `Ctrl+G` | Редагувати план у зовнішньому редакторі | +| `Ctrl+L` | Очистити екран терміналу | +| `Ctrl+O` | Перемкнути детальний вивід (перегляд міркувань) | +| `Ctrl+R` | Зворотний пошук в історії | +| `Ctrl+T` | Перемкнути перегляд списку завдань | +| `Ctrl+B` | Перевести завдання у фоновий режим | +| `Esc+Esc` | Відкотити код/розмову | +| `Shift+Tab` / `Alt+M` | Перемикання режимів дозволів | +| `Option+P` / `Alt+P` | Перемкнути модель | +| `Option+T` / `Alt+T` | Перемкнути розширене мислення | + +**Редагування рядка (стандартні скорочення readline):** + +| Скорочення | Дія | +|----------|--------| +| `Ctrl + A` | Перейти на початок рядка | +| `Ctrl + E` | Перейти на кінець рядка | +| `Ctrl + K` | Вирізати до кінця рядка | +| `Ctrl + U` | Вирізати до початку рядка | +| `Ctrl + W` | Видалити слово назад | +| `Ctrl + Y` | Вставити (yank) | +| `Tab` | Автодоповнення | +| `↑ / ↓` | Історія команд | + +### Кастомізація клавіатурних скорочень + +Створюйте власні клавіатурні скорочення, запустивши `/keybindings`, що відкриває `~/.claude/keybindings.json` для редагування (v2.1.18+). + +**Формат конфігурації**: + +```json +{ + "$schema": "https://www.schemastore.org/claude-code-keybindings.json", + "bindings": [ + { + "context": "Chat", + "bindings": { + "ctrl+e": "chat:externalEditor", + "ctrl+u": null, + "ctrl+k ctrl+s": "chat:stash" + } + }, + { + "context": "Confirmation", + "bindings": { + "ctrl+a": "confirmation:yes" + } + } + ] +} +``` + +Встановіть привʼязку в `null`, щоб відвʼязати скорочення за замовчуванням. + +### Доступні контексти + +Клавіатурні скорочення привʼязані до конкретних контекстів UI: + +| Контекст | Ключові дії | +|---------|-------------| +| **Chat** | `submit`, `cancel`, `cycleMode`, `modelPicker`, `thinkingToggle`, `undo`, `externalEditor`, `stash`, `imagePaste` | +| **Confirmation** | `yes`, `no`, `previous`, `next`, `nextField`, `cycleMode`, `toggleExplanation` | +| **Global** | `interrupt`, `exit`, `toggleTodos`, `toggleTranscript` | +| **Autocomplete** | `accept`, `dismiss`, `next`, `previous` | +| **HistorySearch** | `search`, `previous`, `next` | +| **Settings** | Навігація налаштуваннями | +| **Tabs** | Перемикання та управління вкладками | +| **Help** | Навігація панеллю допомоги | + +Загалом 18 контекстів, включаючи `Transcript`, `Task`, `ThemePicker`, `Attachments`, `Footer`, `MessageSelector`, `DiffDialog`, `ModelPicker` та `Select`. + +### Підтримка акордів + +Клавіатурні скорочення підтримують послідовності акордів (комбінації з кількох клавіш): + +``` +"ctrl+k ctrl+s" → Двоклавішна послідовність: натисніть ctrl+k, потім ctrl+s +"ctrl+shift+p" → Одночасне натискання модифікаторів +``` + +**Синтаксис клавіш**: +- **Модифікатори**: `ctrl`, `alt` (або `opt`), `shift`, `meta` (або `cmd`) +- **Великі літери включають Shift**: `K` еквівалентно `shift+k` +- **Спеціальні клавіші**: `escape`, `enter`, `return`, `tab`, `space`, `backspace`, `delete`, клавіші стрілок + +### Зарезервовані та конфліктні клавіші + +| Клавіша | Статус | Примітки | +|-----|--------|-------| +| `Ctrl+C` | Зарезервовано | Неможливо перепривʼязати (переривання) | +| `Ctrl+D` | Зарезервовано | Неможливо перепривʼязати (вихід) | +| `Ctrl+B` | Конфлікт терміналу | Префіксна клавіша tmux | +| `Ctrl+A` | Конфлікт терміналу | Префіксна клавіша GNU Screen | +| `Ctrl+Z` | Конфлікт терміналу | Призупинення процесу | + +> **Порада**: Якщо скорочення не працює, перевірте конфлікти з вашим емулятором терміналу або мультиплексором. + +### Tab-доповнення + +Claude Code забезпечує інтелектуальне tab-доповнення: + +``` +User: /rew +→ /rewind + +User: /plu +→ /plugin + +User: /plugin +→ /plugin install +→ /plugin enable +→ /plugin disable +``` + +### Історія команд + +Доступ до попередніх команд: + +``` +User: <↑> # Попередня команда +User: <↓> # Наступна команда +User: Ctrl+R # Пошук в історії + +(reverse-i-search)`test': run all tests +``` + +### Багаторядковий ввід + +Для складних запитів використовуйте багаторядковий режим: + +```bash +User: \ +> Long complex prompt +> spanning multiple lines +> \end +``` + +**Приклад:** + +``` +User: \ +> Implement a user authentication system +> with the following requirements: +> - JWT tokens +> - Email verification +> - Password reset +> - 2FA support +> \end + +Claude: [Processes the multi-line request] +``` + +### Inline-редагування + +Редагування команд перед відправкою: + +``` +User: Deploy to prodcutionuction + +[Edit in-place before sending] +``` + +### Режим Vim + +Увімкнення Vi/Vim-клавіатурних привʼязок для редагування тексту: + +**Активація**: +- Використовуйте команду `/vim` або `/config` для увімкнення +- Перемикання режимів: `Esc` для NORMAL, `i/a/o` для INSERT + +**Клавіші навігації**: +- `h` / `l` — Рух вліво/вправо +- `j` / `k` — Рух вниз/вгору +- `w` / `b` / `e` — Рух по словах +- `0` / `$` — Перейти на початок/кінець рядка +- `gg` / `G` — Перейти на початок/кінець тексту + +**Текстові обʼєкти**: +- `iw` / `aw` — Внутрішнє/зовнішнє слово +- `i"` / `a"` — Внутрішній/зовнішній рядок у лапках +- `i(` / `a(` — Внутрішнє/зовнішнє у дужках + +### Режим Bash + +Виконання shell-команд безпосередньо з префіксом `!`: + +```bash +! npm test +! git status +! cat src/index.js +``` + +Використовуйте це для швидкого виконання команд без перемикання контексту. + +--- + +## Голосовий ввід + +Голосовий ввід забезпечує push-to-talk голосове введення для Claude Code, дозволяючи промовляти ваші промпти замість друкування. + +### Активація голосового вводу + +``` +/voice +``` + +### Можливості + +| Можливість | Опис | +|---------|-------------| +| **Push-to-talk** | Утримуйте клавішу для запису, відпустіть для відправки | +| **20 мов** | Розпізнавання мовлення підтримує 20 мов | +| **Власна клавіша** | Налаштуйте клавішу push-to-talk через `/keybindings` | +| **Вимога облікового запису** | Потрібен обліковий запис Claude.ai для обробки STT | + +### Конфігурація + +Налаштуйте клавішу push-to-talk у файлі привʼязок (`/keybindings`). Голосовий ввід використовує ваш обліковий запис Claude.ai для обробки мовлення в текст. + +--- + +## Канали + +Канали — це функція Research Preview, яка надсилає події від зовнішніх сервісів у запущену сесію Claude Code через MCP-сервери. Джерела включають Telegram, Discord, iMessage та довільні вебхуки, дозволяючи Claude реагувати на повідомлення в реальному часі без опитування. + +### Підписка на канали + +```bash +# Підписка на плагіни каналів при запуску +claude --channels discord,telegram + +# Підписка на кілька джерел +claude --channels discord,telegram,imessage,webhooks +``` + +### Підтримувані інтеграції + +| Інтеграція | Опис | +|-------------|-------------| +| **Discord** | Отримання та відповіді на повідомлення Discord у вашій сесії | +| **Telegram** | Отримання та відповіді на повідомлення Telegram у вашій сесії | +| **iMessage** | Отримання сповіщень iMessage у вашій сесії | +| **Webhooks** | Отримання подій від довільних джерел вебхуків | + +### Конфігурація + +Налаштуйте канали прапорцем `--channels` при запуску. Для корпоративних розгортань використовуйте керовану настройку для контролю дозволених плагінів каналів: + +```json +{ + "allowedChannelPlugins": ["discord", "telegram"] +} +``` + +Керована настройка `allowedChannelPlugins` контролює, які плагіни каналів дозволені в організації. + +### Як це працює + +1. MCP-сервери діють як плагіни каналів, що підключаються до зовнішніх сервісів +2. Вхідні повідомлення та події надсилаються в активну сесію Claude Code +3. Claude може читати та відповідати на повідомлення в контексті сесії +4. Плагіни каналів мають бути затверджені через керовану настройку `allowedChannelPlugins` +5. Опитування не потрібне — події надсилаються в реальному часі + +--- + +## Інтеграція Chrome + +Інтеграція Chrome підключає Claude Code до вашого браузера Chrome або Microsoft Edge для автоматизації та відлагодження веб-сторінок у реальному часі. Це бета-функція, доступна з v2.0.73+ (підтримка Edge додана в v1.0.36+). + +### Увімкнення інтеграції Chrome + +**При запуску**: + +```bash +claude --chrome # Увімкнути зʼєднання з Chrome +claude --no-chrome # Вимкнути зʼєднання з Chrome +``` + +**Всередині сесії**: + +``` +/chrome +``` + +Оберіть "Enabled by default" для активації інтеграції Chrome для всіх майбутніх сесій. Claude Code використовує стан входу вашого браузера, тому може взаємодіяти з автентифікованими веб-додатками. + +### Можливості + +| Можливість | Опис | +|------------|-------------| +| **Відлагодження в реальному часі** | Читання логів консолі, інспектування DOM-елементів, відлагодження JavaScript в реальному часі | +| **Перевірка дизайну** | Порівняння відрендерених сторінок з макетами дизайну | +| **Валідація форм** | Тестування відправки форм, валідації вводу та обробки помилок | +| **Тестування веб-додатків** | Взаємодія з автентифікованими додатками (Gmail, Google Docs, Notion тощо) | +| **Витягування даних** | Збір та обробка контенту з веб-сторінок | +| **Запис сесії** | Запис взаємодій з браузером у GIF-файли | + +### Дозволи на рівні сайтів + +Розширення Chrome управляє доступом до окремих сайтів. Надавайте або відкликайте доступ для конкретних сайтів у будь-який час через спливаюче вікно розширення. Claude Code взаємодіє лише з сайтами, які ви явно дозволили. + +### Як це працює + +Claude Code керує браузером у видимому вікні — ви можете спостерігати за діями в реальному часі. Коли браузер натрапляє на сторінку входу або CAPTCHA, Claude зупиняється і чекає, поки ви вручну обробите це, перш ніж продовжити. + +### Відомі обмеження + +- **Підтримка браузерів**: Тільки Chrome та Edge — Brave, Arc та інші браузери на базі Chromium не підтримуються +- **WSL**: Недоступно у Windows Subsystem for Linux +- **Сторонні провайдери**: Не підтримується з провайдерами API Bedrock, Vertex або Foundry +- **Idle service worker**: Service worker розширення Chrome може переходити у неактивний стан під час тривалих сесій + +> **Порада**: Інтеграція Chrome є бета-функцією. Підтримка браузерів може розширитись у майбутніх релізах. + +--- + +## Remote Control + +Remote Control дозволяє продовжити локально запущену сесію Claude Code з телефону, планшета або будь-якого браузера. Ваша локальна сесія продовжує працювати на вашому компʼютері — нічого не переміщується у хмару. Доступно на планах Pro, Max, Team та Enterprise (v2.1.51+). + +### Запуск Remote Control + +**З CLI**: + +```bash +# Запуск із назвою сесії за замовчуванням +claude remote-control + +# Запуск із власною назвою +claude remote-control --name "Auth Refactor" +``` + +**Зсередини сесії**: + +``` +/remote-control +/remote-control "Auth Refactor" +``` + +**Доступні прапорці**: + +| Прапорець | Опис | +|------|-------------| +| `--name "title"` | Власна назва сесії для зручної ідентифікації | +| `--verbose` | Показувати детальні логи зʼєднання | +| `--sandbox` | Увімкнути ізоляцію файлової системи та мережі | +| `--no-sandbox` | Вимкнути пісочницю (за замовчуванням) | + +### Підключення до сесії + +Три способи підключення з іншого пристрою: + +1. **URL сесії** — Виводиться в термінал при запуску сесії; відкрийте у будь-якому браузері +2. **QR-код** — Натисніть `пробіл` після запуску для відображення QR-коду для сканування +3. **Пошук за назвою** — Перегляньте ваші сесії на claude.ai/code або у мобільному додатку Claude (iOS/Android) + +### Безпека + +- **Жодних вхідних портів** не відкривається на вашому компʼютері +- **Тільки вихідний HTTPS** через TLS +- **Обмежені облікові дані** — кілька короткоживучих токенів з вузькою областю дії +- **Ізоляція сесій** — кожна віддалена сесія незалежна + +### Remote Control проти Claude Code у вебі + +| Аспект | Remote Control | Claude Code у вебі | +|--------|---------------|-------------------| +| **Виконання** | Працює на вашому компʼютері | Працює у хмарі Anthropic | +| **Локальні інструменти** | Повний доступ до локальних MCP-серверів, файлів та CLI | Без локальних залежностей | +| **Випадок використання** | Продовження локальної роботи з іншого пристрою | Початок роботи з нуля в будь-якому браузері | + +### Обмеження + +- Одна віддалена сесія на екземпляр Claude Code +- Термінал має залишатись відкритим на хост-машині +- Сесія закінчується через ~10 хвилин, якщо мережа недоступна + +### Випадки використання + +- Управління Claude Code з мобільного пристрою або планшета, перебуваючи далеко від робочого місця +- Використання багатшого UI claude.ai зі збереженням локального виконання інструментів +- Швидке ревʼю коду на ходу з повним локальним середовищем розробки + +--- + +## Веб-сесії + +Веб-сесії дозволяють запускати Claude Code безпосередньо у браузері на claude.ai/code або створювати веб-сесії з CLI. + +### Створення веб-сесії + +```bash +# Створення нової веб-сесії з CLI +claude --remote "implement the new API endpoints" +``` + +Це запускає сесію Claude Code на claude.ai, до якої можна отримати доступ з будь-якого браузера. + +### Відновлення веб-сесій локально + +Якщо ви почали сесію у вебі і хочете продовжити локально: + +```bash +# Відновити веб-сесію в локальному терміналі +claude --teleport +``` + +Або зсередини інтерактивного REPL: +``` +/teleport +``` + +### Випадки використання + +- Почати роботу на одному компʼютері і продовжити на іншому +- Поділитися URL сесії з членами команди +- Використовувати веб-UI для візуального перегляду diff, потім перемкнутися на термінал для виконання + +--- + +## Десктопний додаток + +Десктопний додаток Claude Code надає автономний додаток з візуальним переглядом diff, паралельними сесіями та інтегрованими конекторами. Доступний для macOS та Windows (плани Pro, Max, Team та Enterprise). + +### Встановлення + +Завантажте з [claude.ai](https://claude.ai) для вашої платформи: +- **macOS**: Універсальна збірка (Apple Silicon та Intel) +- **Windows**: Інсталятори для x64 та ARM64 + +Дивіться [Desktop Quickstart](https://code.claude.com/docs/en/desktop-quickstart) для інструкцій з налаштування. + +### Передача з CLI + +Передайте поточну CLI-сесію в десктопний додаток: + +``` +/desktop +``` + +### Основні функції + +| Функція | Опис | +|---------|-------------| +| **Перегляд diff** | Візуальний перегляд файл за файлом з inline-коментарями; Claude читає коментарі та вносить виправлення | +| **Попередній перегляд додатку** | Автозапуск dev-серверів з вбудованим браузером для живої перевірки | +| **Моніторинг PR** | Інтеграція GitHub CLI з автовиправленням помилок CI та автозлиттям при проходженні перевірок | +| **Паралельні сесії** | Кілька сесій у бічній панелі з автоматичною ізоляцією Git worktree | +| **Заплановані завдання** | Повторювані завдання (щогодини, щодня, у робочі дні, щотижня), що працюють при відкритому додатку | +| **Багатий рендеринг** | Рендеринг коду, markdown та діаграм з підсвіткою синтаксису | + +### Конфігурація попереднього перегляду додатку + +Налаштуйте поведінку dev-сервера в `.claude/launch.json`: + +```json +{ + "command": "npm run dev", + "port": 3000, + "readyPattern": "ready on", + "persistCookies": true +} +``` + +### Конектори + +Підключення зовнішніх сервісів для багатшого контексту: + +| Конектор | Можливість | +|-----------|------------| +| **GitHub** | Моніторинг PR, трекінг issues, ревʼю коду | +| **Slack** | Сповіщення, контекст каналів | +| **Linear** | Трекінг issues, управління спринтами | +| **Notion** | Документація, доступ до бази знань | +| **Asana** | Управління завданнями, трекінг проєктів | +| **Calendar** | Обізнаність про розклад, контекст зустрічей | + +> **Примітка**: Конектори недоступні для віддалених (хмарних) сесій. + +### Віддалені та SSH-сесії + +- **Віддалені сесії**: Працюють на хмарній інфраструктурі Anthropic; продовжуються навіть після закриття додатку. Доступні з claude.ai/code або мобільного додатку Claude +- **SSH-сесії**: Підключення до віддалених машин через SSH з повним доступом до віддаленої файлової системи та інструментів. Claude Code повинен бути встановлений на віддаленій машині + +### Режими дозволів у десктопному додатку + +Десктопний додаток підтримує ті самі 4 режими дозволів, що й CLI: + +| Режим | Поведінка | +|------|----------| +| **Ask permissions** (за замовчуванням) | Перегляд та затвердження кожного редагування та команди | +| **Auto accept edits** | Редагування файлів автозатверджуються; команди потребують ручного затвердження | +| **Plan mode** | Перегляд підходу перед будь-якими змінами | +| **Bypass permissions** | Автоматичне виконання (лише у пісочниці, контролюється адміністратором) | + +### Корпоративні функції + +- **Консоль адміністратора**: Контроль доступу до вкладки Code та налаштувань дозволів для організації +- **Розгортання через MDM**: Розгортання через MDM на macOS або MSIX на Windows +- **Інтеграція SSO**: Вимога єдиного входу для членів організації +- **Керовані налаштування**: Централізоване управління конфігурацією команди та доступністю моделей + +--- + +## Список завдань + +Функція списку завдань забезпечує постійне відстеження завдань, яке переживає стиснення контексту (коли історія розмови обрізається для вміщення в контекстне вікно). + +### Перемикання списку завдань + +Натисніть `Ctrl+T` для перемикання перегляду списку завдань під час сесії. + +### Постійні завдання + +Завдання зберігаються між стисненнями контексту, гарантуючи, що тривалі робочі елементи не втрачаються при обрізці контексту розмови. Це особливо корисно для складних, багатоетапних реалізацій. + +### Іменовані директорії завдань + +Використовуйте змінну оточення `CLAUDE_CODE_TASK_LIST_ID` для створення іменованих директорій завдань, спільних між сесіями: + +```bash +export CLAUDE_CODE_TASK_LIST_ID=my-project-sprint-3 +``` + +Це дозволяє кільком сесіям використовувати один список завдань, що корисно для командних робочих процесів або проєктів з кількома сесіями. + +--- + +## Підказки промптів + +Підказки промптів відображають напівпрозорі приклади команд на основі вашої git-історії та поточного контексту розмови. + +### Як це працює + +- Підказки зʼявляються як напівпрозорий текст під вашим вводом +- Натисніть `Tab` для прийняття підказки +- Натисніть `Enter` для прийняття та негайної відправки +- Підказки враховують контекст, використовуючи git-історію та стан розмови + +### Вимкнення підказок промптів + +```bash +export CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false +``` + +--- + +## Git Worktrees + +Git Worktrees дозволяють запускати Claude Code в ізольованому робочому дереві, забезпечуючи паралельну роботу на різних гілках без stash або перемикання. + +### Запуск у Worktree + +```bash +# Запуск Claude Code в ізольованому робочому дереві +claude --worktree +# або +claude -w +``` + +### Розташування Worktree + +Робочі дерева створюються за адресою: +``` +/.claude/worktrees/ +``` + +### Sparse Checkout для монорепозиторіїв + +Використовуйте налаштування `worktree.sparsePaths` для виконання sparse-checkout у монорепозиторіях, зменшуючи використання диску та час клонування: + +```json +{ + "worktree": { + "sparsePaths": ["packages/my-package", "shared/"] + } +} +``` + +### Інструменти та хуки Worktree + +| Елемент | Опис | +|------|-------------| +| `ExitWorktree` | Інструмент для виходу та очищення поточного робочого дерева | +| `WorktreeCreate` | Подія хуку при створенні робочого дерева | +| `WorktreeRemove` | Подія хуку при видаленні робочого дерева | + +### Автоочищення + +Якщо в робочому дереві не було зроблено змін, воно автоматично очищується при завершенні сесії. + +### Випадки використання + +- Робота над feature-гілкою зі збереженням незміненої основної гілки +- Запуск тестів в ізоляції без впливу на робочу директорію +- Спроба експериментальних змін у одноразовому середовищі +- Sparse-checkout конкретних пакетів у монорепозиторіях для швидшого запуску + +--- + +## Пісочниця + +Пісочниця забезпечує ізоляцію файлової системи та мережі на рівні ОС для Bash-команд, що виконуються Claude Code. Це доповнює правила дозволів і забезпечує додатковий рівень безпеки. + +### Увімкнення пісочниці + +**Слеш-команда**: +``` +/sandbox +``` + +**Прапорці CLI**: +```bash +claude --sandbox # Увімкнути пісочницю +claude --no-sandbox # Вимкнути пісочницю +``` + +### Налаштування конфігурації + +| Налаштування | Опис | +|---------|-------------| +| `sandbox.enabled` | Увімкнути або вимкнути пісочницю | +| `sandbox.failIfUnavailable` | Зупинитись, якщо пісочницю неможливо активувати | +| `sandbox.filesystem.allowWrite` | Шляхи з дозволом на запис | +| `sandbox.filesystem.allowRead` | Шляхи з дозволом на читання | +| `sandbox.filesystem.denyRead` | Шляхи з забороною читання | +| `sandbox.enableWeakerNetworkIsolation` | Увімкнути слабшу ізоляцію мережі на macOS | + +### Приклад конфігурації + +```json +{ + "sandbox": { + "enabled": true, + "failIfUnavailable": true, + "filesystem": { + "allowWrite": ["/Users/me/project"], + "allowRead": ["/Users/me/project", "/usr/local/lib"], + "denyRead": ["/Users/me/.ssh", "/Users/me/.aws"] + }, + "enableWeakerNetworkIsolation": true + } +} +``` + +### Як це працює + +- Bash-команди виконуються у пісочниці з обмеженим доступом до файлової системи +- Мережевий доступ може бути ізольований для запобігання небажаним зовнішнім зʼєднанням +- Працює разом з правилами дозволів для глибокого захисту +- На macOS використовуйте `sandbox.enableWeakerNetworkIsolation` для мережевих обмежень (повна ізоляція мережі недоступна на macOS) + +### Випадки використання + +- Безпечний запуск ненадійного або згенерованого коду +- Запобігання випадковим змінам файлів за межами проєкту +- Обмеження мережевого доступу під час автоматизованих завдань + +--- + +## Керовані налаштування (Enterprise) + +Керовані налаштування дозволяють корпоративним адміністраторам розгортати конфігурацію Claude Code по всій організації за допомогою платформних засобів управління. + +### Методи розгортання + +| Платформа | Метод | Починаючи з | +|----------|--------|-------| +| macOS | Керовані plist-файли (MDM) | v2.1.51+ | +| Windows | Реєстр Windows | v2.1.51+ | +| Кросплатформний | Керовані файли конфігурації | v2.1.51+ | +| Кросплатформний | Керовані drop-ins (директорія `managed-settings.d/`) | v2.1.83+ | + +### Керовані Drop-ins + +Починаючи з v2.1.83, адміністратори можуть розгортати кілька файлів керованих налаштувань у директорію `managed-settings.d/`. Файли обʼєднуються в алфавітному порядку, дозволяючи модульну конфігурацію між командами: + +``` +~/.claude/managed-settings.d/ + 00-org-defaults.json + 10-team-policies.json + 20-project-overrides.json +``` + +### Доступні керовані налаштування + +| Налаштування | Опис | +|---------|-------------| +| `disableBypassPermissionsMode` | Заборонити користувачам вмикати обхід дозволів | +| `availableModels` | Обмежити моделі, доступні для вибору | +| `allowedChannelPlugins` | Контролювати дозволені плагіни каналів | +| `autoMode.environment` | Налаштувати довірену інфраструктуру для auto mode | +| Власні політики | Організаційні політики дозволів та інструментів | + +### Приклад: macOS Plist + +```xml + + + + + disableBypassPermissionsMode + + availableModels + + claude-sonnet-4-6 + claude-haiku-4-5 + + + +``` + +--- + +## Конфігурація та налаштування + +### Розташування файлів конфігурації + +1. **Глобальна конфігурація**: `~/.claude/config.json` +2. **Конфігурація проєкту**: `./.claude/config.json` +3. **Конфігурація користувача**: `~/.config/claude-code/settings.json` + +### Повний приклад конфігурації + +**Конфігурація основних розширених функцій:** + +```json +{ + "permissions": { + "mode": "default" + }, + "hooks": { + "PreToolUse:Edit": "eslint --fix ${file_path}", + "PostToolUse:Write": "~/.claude/hooks/security-scan.sh" + }, + "mcp": { + "enabled": true, + "servers": { + "github": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"] + } + } + } +} +``` + +**Розширений приклад конфігурації:** + +```json +{ + "permissions": { + "mode": "default", + "allowedTools": ["Bash(git log:*)", "Read"], + "disallowedTools": ["Bash(rm -rf:*)"] + }, + + "hooks": { + "PreToolUse": [{ "matcher": "Edit", "hooks": ["eslint --fix ${file_path}"] }], + "PostToolUse": [{ "matcher": "Write", "hooks": ["~/.claude/hooks/security-scan.sh"] }], + "Stop": [{ "hooks": ["~/.claude/hooks/notify.sh"] }] + }, + + "mcp": { + "enabled": true, + "servers": { + "github": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } + } +} +``` + +### Змінні оточення + +Перевизначення конфігурації через змінні оточення: + +```bash +# Вибір моделі +export ANTHROPIC_MODEL=claude-opus-4-6 +export ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-6 +export ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 +export ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-4-5 + +# Конфігурація API +export ANTHROPIC_API_KEY=sk-ant-... + +# Конфігурація мислення +export MAX_THINKING_TOKENS=16000 +export CLAUDE_CODE_EFFORT_LEVEL=high + +# Перемикачі функцій +export CLAUDE_CODE_DISABLE_AUTO_MEMORY=true +export CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=true +export CLAUDE_CODE_DISABLE_CRON=1 +export CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS=true +export CLAUDE_CODE_DISABLE_TERMINAL_TITLE=true +export CLAUDE_CODE_DISABLE_1M_CONTEXT=true +export CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=true +export CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false +export CLAUDE_CODE_ENABLE_TASKS=true +export CLAUDE_CODE_SIMPLE=true # Встановлюється прапорцем --bare + +# Конфігурація MCP +export MAX_MCP_OUTPUT_TOKENS=50000 +export ENABLE_TOOL_SEARCH=true + +# Управління завданнями +export CLAUDE_CODE_TASK_LIST_ID=my-project-tasks + +# Agent teams (експериментально) +export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 + +# Конфігурація субагентів та плагінів +export CLAUDE_CODE_SUBAGENT_MODEL=sonnet +export CLAUDE_CODE_PLUGIN_SEED_DIR=./my-plugins +export CLAUDE_CODE_NEW_INIT=1 + +# Підпроцеси та стрімінг +export CLAUDE_CODE_SUBPROCESS_ENV_SCRUB="SECRET_KEY,DB_PASSWORD" +export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80 +export CLAUDE_STREAM_IDLE_TIMEOUT_MS=30000 +export ANTHROPIC_CUSTOM_MODEL_OPTION=my-custom-model +export SLASH_COMMAND_TOOL_CHAR_BUDGET=50000 +``` + +### Команди управління конфігурацією + +``` +User: /config +[Opens interactive configuration menu] +``` + +Команда `/config` надає інтерактивне меню для перемикання налаштувань, таких як: +- Розширене мислення увімк./вимк. +- Детальний вивід +- Режим дозволів +- Вибір моделі + +### Конфігурація на рівні проєкту + +Створіть `.claude/config.json` у вашому проєкті: + +```json +{ + "hooks": { + "PreToolUse": [{ "matcher": "Bash", "hooks": ["npm test && npm run lint"] }] + }, + "permissions": { + "mode": "default" + }, + "mcp": { + "servers": { + "project-db": { + "command": "mcp-postgres", + "env": { + "DATABASE_URL": "${PROJECT_DB_URL}" + } + } + } + } +} +``` + +--- + +## Agent Teams + +Agent Teams — це експериментальна функція, яка дозволяє кільком екземплярам Claude Code співпрацювати над завданням. Вимкнена за замовчуванням. + +### Увімкнення Agent Teams + +Увімкнення через змінну оточення або налаштування: + +```bash +# Змінна оточення +export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 +``` + +Або додайте до вашого JSON-файлу налаштувань: + +```json +{ + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" +} +``` + +### Як працюють Agent Teams + +- **Лідер команди** координує загальне завдання та делегує підзавдання товаришам по команді +- **Товариші по команді** працюють незалежно, кожен зі своїм контекстним вікном +- **Спільний список завдань** забезпечує самокоординацію між членами команди +- Використовуйте визначення субагентів (`.claude/agents/` або прапорець `--agents`) для визначення ролей та спеціалізацій товаришів + +### Режими відображення + +Agent Teams підтримують два режими відображення, що налаштовуються прапорцем `--teammate-mode`: + +| Режим | Опис | +|------|-------------| +| `in-process` (за замовчуванням) | Товариші працюють у тому ж процесі терміналу | +| `tmux` | Кожен товариш отримує окрему розділену панель (потрібен tmux або iTerm2) | +| `auto` | Автоматичний вибір найкращого режиму відображення | + +```bash +# Використання tmux для відображення товаришів +claude --teammate-mode tmux + +# Явне використання in-process режиму +claude --teammate-mode in-process +``` + +### Випадки використання + +- Великі завдання рефакторингу, де різні товариші обробляють різні модулі +- Паралельне ревʼю коду та реалізація +- Координовані зміни кількох файлів по всій кодовій базі + +> **Примітка**: Agent Teams є експериментальною функцією і може змінитися у майбутніх релізах. Дивіться [code.claude.com/docs/en/agent-teams](https://code.claude.com/docs/en/agent-teams) для повного довідника. + +--- + +## Найкращі практики + +### Режим планування +- ✅ Використовуйте для складних багатоетапних завдань +- ✅ Переглядайте плани перед затвердженням +- ✅ Модифікуйте плани за потреби +- ❌ Не використовуйте для простих завдань + +### Розширене мислення +- ✅ Використовуйте для архітектурних рішень +- ✅ Використовуйте для вирішення складних проблем +- ✅ Переглядайте процес мислення +- ❌ Не використовуйте для простих запитів + +### Фонові завдання +- ✅ Використовуйте для тривалих операцій +- ✅ Моніторте прогрес завдань +- ✅ Коректно обробляйте помилки завдань +- ❌ Не запускайте занадто багато паралельних завдань + +### Дозволи +- ✅ Використовуйте `plan` для ревʼю коду (тільки читання) +- ✅ Використовуйте `default` для інтерактивної розробки +- ✅ Використовуйте `acceptEdits` для автоматизованих робочих процесів +- ✅ Використовуйте `auto` для автономної роботи із запобіжниками безпеки +- ❌ Не використовуйте `bypassPermissions` без крайньої необхідності + +### Сесії +- ✅ Використовуйте окремі сесії для різних завдань +- ✅ Зберігайте важливі стани сесій +- ✅ Очищайте старі сесії +- ❌ Не змішуйте неповʼязану роботу в одній сесії + +--- + +## Додаткові ресурси + +Для отримання додаткової інформації про Claude Code та повʼязані функції: + +- [Офіційна документація інтерактивного режиму](https://code.claude.com/docs/en/interactive-mode) +- [Офіційна документація Headless Mode](https://code.claude.com/docs/en/headless) +- [Довідник CLI](https://code.claude.com/docs/en/cli-reference) +- [Посібник з контрольних точок](../08-checkpoints/) — Управління сесіями та відкат +- [Слеш-команди](../01-slash-commands/) — Довідник команд +- [Посібник з памʼяті](../02-memory/) — Постійний контекст +- [Посібник з навичок](../03-skills/) — Автономні можливості +- [Посібник з субагентів](../04-subagents/) — Делеговане виконання завдань +- [Посібник з MCP](../05-mcp/) — Доступ до зовнішніх даних +- [Посібник з хуків](../06-hooks/) — Автоматизація на основі подій +- [Посібник з плагінів](../07-plugins/) — Пакетні розширення +- [Офіційна документація запланованих завдань](https://code.claude.com/docs/en/scheduled-tasks) +- [Офіційна документація інтеграції Chrome](https://code.claude.com/docs/en/chrome) +- [Офіційна документація Remote Control](https://code.claude.com/docs/en/remote-control) +- [Офіційна документація клавіатурних скорочень](https://code.claude.com/docs/en/keybindings) +- [Офіційна документація десктопного додатку](https://code.claude.com/docs/en/desktop) +- [Офіційна документація Agent Teams](https://code.claude.com/docs/en/agent-teams) + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/10-cli/README.md b/uk/10-cli/README.md new file mode 100644 index 0000000..403b187 --- /dev/null +++ b/uk/10-cli/README.md @@ -0,0 +1,841 @@ + + + + + + + Claude How To + + +# Довідник CLI + +## Огляд + +Claude Code CLI (інтерфейс командного рядка — основний інструмент для роботи з терміналом) — це головний спосіб взаємодії з Claude Code. Він надає потужні опції для виконання запитів, управління сесіями, конфігурації моделей та інтеграції Claude у ваші робочі процеси розробки. + +## Архітектура + +```mermaid +graph TD + A["User Terminal"] -->|"claude [options] [query]"| B["Claude Code CLI"] + B -->|Interactive| C["REPL Mode"] + B -->|"--print"| D["Print Mode (SDK)"] + B -->|"--resume"| E["Session Resume"] + C -->|Conversation| F["Claude API"] + D -->|Single Query| F + E -->|Load Context| F + F -->|Response| G["Output"] + G -->|text/json/stream-json| H["Terminal/Pipe"] +``` + +## CLI-команди + +| Команда | Опис | Приклад | +|---------|------|---------| +| `claude` | Запуск інтерактивного REPL (циклу читання-виконання-виводу) | `claude` | +| `claude "query"` | Запуск REPL з початковим промптом | `claude "explain this project"` | +| `claude -p "query"` | Print-режим — запит і вихід | `claude -p "explain this function"` | +| `cat file \| claude -p "query"` | Обробка вмісту через pipe (конвеєр) | `cat logs.txt \| claude -p "explain"` | +| `claude -c` | Продовжити останню розмову | `claude -c` | +| `claude -c -p "query"` | Продовжити в print-режимі | `claude -c -p "check for type errors"` | +| `claude -r "" "query"` | Відновити сесію за ID або назвою | `claude -r "auth-refactor" "finish this PR"` | +| `claude update` | Оновити до останньої версії | `claude update` | +| `claude mcp` | Налаштування MCP-серверів | Див. [документацію MCP](../05-mcp/) | +| `claude mcp serve` | Запуск Claude Code як MCP-сервера | `claude mcp serve` | +| `claude agents` | Список усіх налаштованих субагентів | `claude agents` | +| `claude auto-mode defaults` | Вивести стандартні правила auto mode як JSON | `claude auto-mode defaults` | +| `claude remote-control` | Запуск сервера Remote Control | `claude remote-control` | +| `claude plugin` | Управління плагінами (встановлення, увімкнення, вимкнення) | `claude plugin install my-plugin` | +| `claude auth login` | Вхід (підтримує `--email`, `--sso`) | `claude auth login --email user@example.com` | +| `claude auth logout` | Вихід з поточного облікового запису | `claude auth logout` | +| `claude auth status` | Перевірка статусу авторизації (код виходу 0 = увійшов, 1 = ні) | `claude auth status` | + +## Основні прапорці + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `-p, --print` | Вивести відповідь без інтерактивного режиму | `claude -p "query"` | +| `-c, --continue` | Завантажити останню розмову | `claude --continue` | +| `-r, --resume` | Відновити конкретну сесію за ID або назвою | `claude --resume auth-refactor` | +| `-v, --version` | Показати номер версії | `claude -v` | +| `-w, --worktree` | Запуск в ізольованому git worktree (робочому дереві) | `claude -w` | +| `-n, --name` | Відображувана назва сесії | `claude -n "auth-refactor"` | +| `--from-pr ` | Відновити сесії, привʼязані до GitHub PR | `claude --from-pr 42` | +| `--remote "task"` | Створити веб-сесію на claude.ai | `claude --remote "implement API"` | +| `--remote-control, --rc` | Інтерактивна сесія з Remote Control | `claude --rc` | +| `--teleport` | Відновити веб-сесію локально | `claude --teleport` | +| `--teammate-mode` | Режим відображення Agent Teams | `claude --teammate-mode tmux` | +| `--bare` | Мінімальний режим (без хуків, навичок, плагінів, MCP, auto memory, CLAUDE.md) | `claude --bare` | +| `--enable-auto-mode` | Розблокувати auto permission mode | `claude --enable-auto-mode` | +| `--channels` | Підписка на MCP channel plugins | `claude --channels discord,telegram` | +| `--chrome` / `--no-chrome` | Увімкнути/вимкнути інтеграцію з браузером Chrome | `claude --chrome` | +| `--effort` | Встановити рівень зусиль мислення | `claude --effort high` | +| `--init` / `--init-only` | Запуск хуків ініціалізації | `claude --init` | +| `--maintenance` | Запуск хуків обслуговування та вихід | `claude --maintenance` | +| `--disable-slash-commands` | Вимкнути всі навички та слеш-команди | `claude --disable-slash-commands` | +| `--no-session-persistence` | Вимкнути збереження сесії (print mode) | `claude -p --no-session-persistence "query"` | + +### Інтерактивний vs Print-режим + +```mermaid +graph LR + A["claude"] -->|Default| B["Interactive REPL"] + A -->|"-p flag"| C["Print Mode"] + B -->|Features| D["Multi-turn conversation
Tab completion
History
Slash commands"] + C -->|Features| E["Single query
Scriptable
Pipeable
JSON output"] +``` + +**Інтерактивний режим** (за замовчуванням): +```bash +# Запуск інтерактивної сесії +claude + +# Запуск з початковим промптом +claude "explain the authentication flow" +``` + +**Print-режим** (неінтерактивний): +```bash +# Один запит, потім вихід +claude -p "what does this function do?" + +# Обробка вмісту файлу +cat error.log | claude -p "explain this error" + +# Ланцюжок з іншими інструментами +claude -p "list todos" | grep "URGENT" +``` + +## Модель та конфігурація + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--model` | Встановити модель (sonnet, opus, haiku або повна назва) | `claude --model opus` | +| `--fallback-model` | Автоматичний фолбек (запасна модель) при перевантаженні | `claude -p --fallback-model sonnet "query"` | +| `--agent` | Вказати агента для сесії | `claude --agent my-custom-agent` | +| `--agents` | Визначити кастомних субагентів через JSON | Див. [Конфігурація агентів](#конфігурація-агентів) | +| `--effort` | Встановити рівень зусиль (low, medium, high, max) | `claude --effort high` | + +### Приклади вибору моделі + +```bash +# Opus 4.6 для складних завдань +claude --model opus "design a caching strategy" + +# Haiku 4.5 для швидких завдань +claude --model haiku -p "format this JSON" + +# Повна назва моделі +claude --model claude-sonnet-4-6-20250929 "review this code" + +# З фолбеком для надійності +claude -p --model opus --fallback-model sonnet "analyze architecture" + +# opusplan (Opus планує, Sonnet виконує) +claude --model opusplan "design and implement the caching layer" +``` + +## Кастомізація системного промпта + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--system-prompt` | Замінити весь стандартний промпт | `claude --system-prompt "You are a Python expert"` | +| `--system-prompt-file` | Завантажити промпт з файлу (print mode) | `claude -p --system-prompt-file ./prompt.txt "query"` | +| `--append-system-prompt` | Додати до стандартного промпта | `claude --append-system-prompt "Always use TypeScript"` | + +### Приклади системного промпта + +```bash +# Повністю кастомна персона +claude --system-prompt "You are a senior security engineer. Focus on vulnerabilities." + +# Додавання конкретних інструкцій +claude --append-system-prompt "Always include unit tests with code examples" + +# Завантаження складного промпта з файлу +claude -p --system-prompt-file ./prompts/code-reviewer.txt "review main.py" +``` + +### Порівняння прапорців системного промпта + +| Прапорець | Поведінка | Інтерактивний | Print | +|-----------|----------|---------------|-------| +| `--system-prompt` | Замінює весь стандартний системний промпт | ✅ | ✅ | +| `--system-prompt-file` | Замінює промптом з файлу | ❌ | ✅ | +| `--append-system-prompt` | Додає до стандартного системного промпта | ✅ | ✅ | + +**Використовуйте `--system-prompt-file` лише в print-режимі. Для інтерактивного режиму використовуйте `--system-prompt` або `--append-system-prompt`.** + +## Управління інструментами та дозволами + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--tools` | Обмежити доступні вбудовані інструменти | `claude -p --tools "Bash,Edit,Read" "query"` | +| `--allowedTools` | Інструменти, що виконуються без запиту дозволу | `"Bash(git log:*)" "Read"` | +| `--disallowedTools` | Інструменти, видалені з контексту | `"Bash(rm:*)" "Edit"` | +| `--dangerously-skip-permissions` | Пропустити всі запити дозволів | `claude --dangerously-skip-permissions` | +| `--permission-mode` | Починати у вказаному режимі дозволів | `claude --permission-mode auto` | +| `--permission-prompt-tool` | MCP-інструмент для обробки дозволів | `claude -p --permission-prompt-tool mcp_auth "query"` | +| `--enable-auto-mode` | Розблокувати auto permission mode | `claude --enable-auto-mode` | + +### Приклади дозволів + +```bash +# Режим тільки для читання — код-рев'ю +claude --permission-mode plan "review this codebase" + +# Обмеження до безпечних інструментів +claude --tools "Read,Grep,Glob" -p "find all TODO comments" + +# Дозволити конкретні git-команди без запитів +claude --allowedTools "Bash(git status:*)" "Bash(git log:*)" + +# Заблокувати небезпечні операції +claude --disallowedTools "Bash(rm -rf:*)" "Bash(git push --force:*)" +``` + +## Вивід та формат + +| Прапорець | Опис | Опції | Приклад | +|-----------|------|-------|---------| +| `--output-format` | Формат виводу (print mode) | `text`, `json`, `stream-json` | `claude -p --output-format json "query"` | +| `--input-format` | Формат вводу (print mode) | `text`, `stream-json` | `claude -p --input-format stream-json` | +| `--verbose` | Увімкнути детальне логування | | `claude --verbose` | +| `--include-partial-messages` | Включити потокові (streaming) події | Потребує `stream-json` | `claude -p --output-format stream-json --include-partial-messages "query"` | +| `--json-schema` | Отримати валідований JSON за схемою | | `claude -p --json-schema '{"type":"object"}' "query"` | +| `--max-budget-usd` | Максимальні витрати для print mode | | `claude -p --max-budget-usd 5.00 "query"` | + +### Приклади формату виводу + +```bash +# Звичайний текст (за замовчуванням) +claude -p "explain this code" + +# JSON для програмного використання +claude -p --output-format json "list all functions in main.py" + +# Потоковий JSON для обробки в реальному часі +claude -p --output-format stream-json "generate a long report" + +# Структурований вивід із валідацією за схемою +claude -p --json-schema '{"type":"object","properties":{"bugs":{"type":"array"}}}' \ + "find bugs in this code and return as JSON" +``` + +## Робочий простір та каталог + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--add-dir` | Додати додаткові робочі каталоги | `claude --add-dir ../apps ../lib` | +| `--setting-sources` | Джерела налаштувань через кому | `claude --setting-sources user,project` | +| `--settings` | Завантажити налаштування з файлу або JSON | `claude --settings ./settings.json` | +| `--plugin-dir` | Завантажити плагіни з каталогу (повторюваний) | `claude --plugin-dir ./my-plugin` | + +### Приклад роботи з кількома каталогами + +```bash +# Робота в кількох каталогах проєкту одночасно +claude --add-dir ../frontend ../backend ../shared "find all API endpoints" + +# Завантаження кастомних налаштувань +claude --settings '{"model":"opus","verbose":true}' "complex task" +``` + +## Конфігурація MCP + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--mcp-config` | Завантажити MCP-сервери з JSON | `claude --mcp-config ./mcp.json` | +| `--strict-mcp-config` | Використовувати тільки вказану MCP-конфігурацію | `claude --strict-mcp-config --mcp-config ./mcp.json` | +| `--channels` | Підписка на MCP channel plugins | `claude --channels discord,telegram` | + +### Приклади MCP + +```bash +# Завантаження GitHub MCP-сервера +claude --mcp-config ./github-mcp.json "list open PRs" + +# Суворий режим — тільки вказані сервери +claude --strict-mcp-config --mcp-config ./production-mcp.json "deploy to staging" +``` + +## Управління сесіями + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--session-id` | Використовувати конкретний ID сесії (UUID) | `claude --session-id "550e8400-..."` | +| `--fork-session` | Створити нову сесію при відновленні | `claude --resume abc123 --fork-session` | + +### Приклади сесій + +```bash +# Продовжити останню розмову +claude -c + +# Відновити іменовану сесію +claude -r "feature-auth" "continue implementing login" + +# Форк сесії для експериментів +claude --resume feature-auth --fork-session "try alternative approach" + +# Використання конкретного ID сесії +claude --session-id "550e8400-e29b-41d4-a716-446655440000" "continue" +``` + +### Форк сесії + +Створення відгалуження від існуючої сесії для експериментів: + +```bash +# Форк сесії для альтернативного підходу +claude --resume abc123 --fork-session "try alternative implementation" + +# Форк з кастомним повідомленням +claude -r "feature-auth" --fork-session "test with different architecture" +``` + +**Випадки використання:** +- Спроба альтернативних реалізацій без втрати оригінальної сесії +- Паралельне експериментування з різними підходами +- Створення відгалужень від успішної роботи для варіацій +- Тестування зламуючих змін (breaking changes) без впливу на основну сесію + +Оригінальна сесія залишається без змін, а форк стає новою незалежною сесією. + +## Розширені функції + +| Прапорець | Опис | Приклад | +|-----------|------|---------| +| `--chrome` | Увімкнути інтеграцію з браузером Chrome | `claude --chrome` | +| `--no-chrome` | Вимкнути інтеграцію з Chrome | `claude --no-chrome` | +| `--ide` | Автопідключення до IDE, якщо доступна | `claude --ide` | +| `--max-turns` | Обмежити кількість агентних кроків (неінтерактивний режим) | `claude -p --max-turns 3 "query"` | +| `--debug` | Увімкнути режим налагодження з фільтрацією | `claude --debug "api,mcp"` | +| `--enable-lsp-logging` | Увімкнути детальне логування LSP | `claude --enable-lsp-logging` | +| `--betas` | Beta-заголовки для API-запитів | `claude --betas interleaved-thinking` | +| `--plugin-dir` | Завантажити плагіни з каталогу (повторюваний) | `claude --plugin-dir ./my-plugin` | +| `--enable-auto-mode` | Розблокувати auto permission mode | `claude --enable-auto-mode` | +| `--effort` | Встановити рівень зусиль мислення | `claude --effort high` | +| `--bare` | Мінімальний режим (без хуків, навичок, плагінів, MCP, auto memory, CLAUDE.md) | `claude --bare` | +| `--channels` | Підписка на MCP channel plugins | `claude --channels discord` | +| `--tmux` | Створити tmux-сесію для worktree | `claude --tmux` | +| `--fork-session` | Створити новий ID сесії при відновленні | `claude --resume abc --fork-session` | +| `--max-budget-usd` | Максимальні витрати (print mode) | `claude -p --max-budget-usd 5.00 "query"` | +| `--json-schema` | Валідований JSON-вивід | `claude -p --json-schema '{"type":"object"}' "q"` | + +### Приклади розширених функцій + +```bash +# Обмежити автономні дії +claude -p --max-turns 5 "refactor this module" + +# Налагодження API-викликів +claude --debug "api" "test query" + +# Увімкнути інтеграцію з IDE +claude --ide "help me with this file" +``` + +## Конфігурація агентів + +Прапорець `--agents` приймає JSON-обʼєкт, що визначає кастомних субагентів для сесії. + +### Формат JSON для агентів + +```json +{ + "agent-name": { + "description": "Обовʼязково: коли викликати цього агента", + "prompt": "Обовʼязково: системний промпт для агента", + "tools": ["Необовʼязково", "масив", "інструментів"], + "model": "необовʼязково: sonnet|opus|haiku" + } +} +``` + +**Обовʼязкові поля:** +- `description` — опис природною мовою, коли використовувати цього агента +- `prompt` — системний промпт, що визначає роль та поведінку агента + +**Необовʼязкові поля:** +- `tools` — масив доступних інструментів (якщо не вказано, успадковує всі) + - Формат: `["Read", "Grep", "Glob", "Bash"]` +- `model` — модель: `sonnet`, `opus` або `haiku` + +### Повний приклад агентів + +```json +{ + "code-reviewer": { + "description": "Expert code reviewer. Use proactively after code changes.", + "prompt": "You are a senior code reviewer. Focus on code quality, security, and best practices.", + "tools": ["Read", "Grep", "Glob", "Bash"], + "model": "sonnet" + }, + "debugger": { + "description": "Debugging specialist for errors and test failures.", + "prompt": "You are an expert debugger. Analyze errors, identify root causes, and provide fixes.", + "tools": ["Read", "Edit", "Bash", "Grep"], + "model": "opus" + }, + "documenter": { + "description": "Documentation specialist for generating guides.", + "prompt": "You are a technical writer. Create clear, comprehensive documentation.", + "tools": ["Read", "Write"], + "model": "haiku" + } +} +``` + +### Приклади команд з агентами + +```bash +# Визначення кастомних агентів інлайн +claude --agents '{ + "security-auditor": { + "description": "Security specialist for vulnerability analysis", + "prompt": "You are a security expert. Find vulnerabilities and suggest fixes.", + "tools": ["Read", "Grep", "Glob"], + "model": "opus" + } +}' "audit this codebase for security issues" + +# Завантаження агентів з файлу +claude --agents "$(cat ~/.claude/agents.json)" "review the auth module" + +# Комбінація з іншими прапорцями +claude -p --agents "$(cat agents.json)" --model sonnet "analyze performance" +``` + +### Пріоритет агентів + +При наявності кількох визначень агентів вони завантажуються в такому порядку пріоритету: +1. **CLI-визначені** (прапорець `--agents`) — для конкретної сесії +2. **Рівень користувача** (`~/.claude/agents/`) — для всіх проєктів +3. **Рівень проєкту** (`.claude/agents/`) — для поточного проєкту + +CLI-визначені агенти перевизначають агентів рівня користувача та проєкту на час сесії. + +--- + +## Високоцінні сценарії використання + +### 1. Інтеграція CI/CD + +Використання Claude Code у CI/CD-пайплайнах (конвеєрах безперервної інтеграції/доставки) для автоматизованого код-рев'ю, тестування та документації. + +**Приклад GitHub Actions:** + +```yaml +name: AI Code Review + +on: [pull_request] + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Claude Code + run: npm install -g @anthropic-ai/claude-code + + - name: Run Code Review + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + claude -p --output-format json \ + --max-turns 1 \ + "Review the changes in this PR for: + - Security vulnerabilities + - Performance issues + - Code quality + Output as JSON with 'issues' array" > review.json + + - name: Post Review Comment + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const review = JSON.parse(fs.readFileSync('review.json', 'utf8')); + // Обробка та публікація коментарів рев'ю +``` + +**Пайплайн Jenkins:** + +```groovy +pipeline { + agent any + stages { + stage('AI Review') { + steps { + sh ''' + claude -p --output-format json \ + --max-turns 3 \ + "Analyze test coverage and suggest missing tests" \ + > coverage-analysis.json + ''' + } + } + } +} +``` + +### 2. Pipe-обробка скриптів + +Обробка файлів, журналів та даних через Claude для аналізу. + +**Аналіз журналів:** + +```bash +# Аналіз журналів помилок +tail -1000 /var/log/app/error.log | claude -p "summarize these errors and suggest fixes" + +# Пошук патернів у журналах доступу +cat access.log | claude -p "identify suspicious access patterns" + +# Аналіз git-історії +git log --oneline -50 | claude -p "summarize recent development activity" +``` + +**Обробка коду:** + +```bash +# Рев'ю конкретного файлу +cat src/auth.ts | claude -p "review this authentication code for security issues" + +# Генерація документації +cat src/api/*.ts | claude -p "generate API documentation in markdown" + +# Пошук TODO та пріоритезація +grep -r "TODO" src/ | claude -p "prioritize these TODOs by importance" +``` + +### 3. Мультисесійні робочі процеси + +Управління складними проєктами з кількома потоками розмов. + +```bash +# Запуск сесії для гілки функції +claude -r "feature-auth" "let's implement user authentication" + +# Пізніше — продовження сесії +claude -r "feature-auth" "add password reset functionality" + +# Форк для альтернативного підходу +claude --resume feature-auth --fork-session "try OAuth instead" + +# Переключення між різними сесіями функцій +claude -r "feature-payments" "continue with Stripe integration" +``` + +### 4. Кастомна конфігурація агентів + +Визначення спеціалізованих агентів для робочих процесів вашої команди. + +```bash +# Збереження конфігурації агентів у файл +cat > ~/.claude/agents.json << 'EOF' +{ + "reviewer": { + "description": "Code reviewer for PR reviews", + "prompt": "Review code for quality, security, and maintainability.", + "model": "opus" + }, + "documenter": { + "description": "Documentation specialist", + "prompt": "Generate clear, comprehensive documentation.", + "model": "sonnet" + }, + "refactorer": { + "description": "Code refactoring expert", + "prompt": "Suggest and implement clean code refactoring.", + "tools": ["Read", "Edit", "Glob"] + } +} +EOF + +# Використання агентів у сесії +claude --agents "$(cat ~/.claude/agents.json)" "review the auth module" +``` + +### 5. Пакетна обробка + +Обробка кількох запитів з однаковими налаштуваннями. + +```bash +# Обробка кількох файлів +for file in src/*.ts; do + echo "Processing $file..." + claude -p --model haiku "summarize this file: $(cat $file)" >> summaries.md +done + +# Пакетне код-рев'ю +find src -name "*.py" -exec sh -c ' + echo "## $1" >> review.md + cat "$1" | claude -p "brief code review" >> review.md +' _ {} \; + +# Генерація тестів для всіх модулів +for module in $(ls src/modules/); do + claude -p "generate unit tests for src/modules/$module" > "tests/$module.test.ts" +done +``` + +### 6. Безпечна розробка + +Використання контролю дозволів для безпечної роботи. + +```bash +# Аудит безпеки тільки для читання +claude --permission-mode plan \ + --tools "Read,Grep,Glob" \ + "audit this codebase for security vulnerabilities" + +# Блокування небезпечних команд +claude --disallowedTools "Bash(rm:*)" "Bash(curl:*)" "Bash(wget:*)" \ + "help me clean up this project" + +# Обмежена автоматизація +claude -p --max-turns 2 \ + --allowedTools "Read" "Glob" \ + "find all hardcoded credentials" +``` + +### 7. JSON API інтеграція + +Використання Claude як програмного API для ваших інструментів з парсингом через `jq`. + +```bash +# Структурований аналіз +claude -p --output-format json \ + --json-schema '{"type":"object","properties":{"functions":{"type":"array"},"complexity":{"type":"string"}}}' \ + "analyze main.py and return function list with complexity rating" + +# Інтеграція з jq для обробки +claude -p --output-format json "list all API endpoints" | jq '.endpoints[]' + +# Використання в скриптах +RESULT=$(claude -p --output-format json "is this code secure? answer with {secure: boolean, issues: []}" < code.py) +if echo "$RESULT" | jq -e '.secure == false' > /dev/null; then + echo "Security issues found!" + echo "$RESULT" | jq '.issues[]' +fi +``` + +### Приклади парсингу jq + +Парсинг та обробка JSON-виводу Claude за допомогою `jq`: + +```bash +# Витяг конкретних полів +claude -p --output-format json "analyze this code" | jq '.result' + +# Фільтрація елементів масиву +claude -p --output-format json "list issues" | jq -r '.issues[] | select(.severity=="high")' + +# Витяг кількох полів +claude -p --output-format json "describe the project" | jq -r '.{name, version, description}' + +# Конвертація в CSV +claude -p --output-format json "list functions" | jq -r '.functions[] | [.name, .lineCount] | @csv' + +# Умовна обробка +claude -p --output-format json "check security" | jq 'if .vulnerabilities | length > 0 then "UNSAFE" else "SAFE" end' + +# Витяг вкладених значень +claude -p --output-format json "analyze performance" | jq '.metrics.cpu.usage' + +# Обробка всього масиву +claude -p --output-format json "find todos" | jq '.todos | length' + +# Трансформація виводу +claude -p --output-format json "list improvements" | jq 'map({title: .title, priority: .priority})' +``` + +--- + +## Моделі + +Claude Code підтримує кілька моделей з різними можливостями: + +| Модель | ID | Контекстне вікно | Примітки | +|--------|-----|-----------------|----------| +| Opus 4.6 | `claude-opus-4-6` | 1M токенів | Найпотужніша, адаптивні рівні зусиль | +| Sonnet 4.6 | `claude-sonnet-4-6` | 1M токенів | Баланс швидкості та можливостей | +| Haiku 4.5 | `claude-haiku-4-5` | 1M токенів | Найшвидша, оптимальна для швидких завдань | + +### Вибір моделі + +```bash +# Використання коротких назв +claude --model opus "complex architectural review" +claude --model sonnet "implement this feature" +claude --model haiku -p "format this JSON" + +# Використання alias opusplan (Opus планує, Sonnet виконує) +claude --model opusplan "design and implement the API" + +# Перемикання на швидкий режим під час сесії +/fast +``` + +### Рівні зусиль (Opus 4.6) + +Opus 4.6 підтримує адаптивне міркування з рівнями зусиль: + +```bash +# Через прапорець CLI +claude --effort high "complex review" + +# Через слеш-команду +/effort high + +# Через змінну оточення +export CLAUDE_CODE_EFFORT_LEVEL=high # low, medium, high або max (лише Opus 4.6) +``` + +Ключове слово "ultrathink" у промптах активує глибоке міркування. Рівень `max` — ексклюзивний для Opus 4.6. + +--- + +## Ключові змінні оточення + +| Змінна | Опис | +|--------|------| +| `ANTHROPIC_API_KEY` | API-ключ для автентифікації | +| `ANTHROPIC_MODEL` | Перевизначення стандартної моделі | +| `ANTHROPIC_CUSTOM_MODEL_OPTION` | Кастомна опція моделі для API | +| `ANTHROPIC_DEFAULT_OPUS_MODEL` | Перевизначення стандартного ID моделі Opus | +| `ANTHROPIC_DEFAULT_SONNET_MODEL` | Перевизначення стандартного ID моделі Sonnet | +| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | Перевизначення стандартного ID моделі Haiku | +| `MAX_THINKING_TOKENS` | Бюджет токенів розширеного мислення | +| `CLAUDE_CODE_EFFORT_LEVEL` | Рівень зусиль (`low`/`medium`/`high`/`max`) | +| `CLAUDE_CODE_SIMPLE` | Мінімальний режим, встановлюється прапорцем `--bare` | +| `CLAUDE_CODE_DISABLE_AUTO_MEMORY` | Вимкнути автоматичне оновлення CLAUDE.md | +| `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS` | Вимкнути виконання фонових завдань | +| `CLAUDE_CODE_DISABLE_CRON` | Вимкнути заплановані/cron-завдання | +| `CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS` | Вимкнути git-інструкції | +| `CLAUDE_CODE_DISABLE_TERMINAL_TITLE` | Вимкнути оновлення заголовка терміналу | +| `CLAUDE_CODE_DISABLE_1M_CONTEXT` | Вимкнути контекстне вікно 1M токенів | +| `CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK` | Вимкнути фолбек без стрімінгу | +| `CLAUDE_CODE_ENABLE_TASKS` | Увімкнути функцію списку завдань | +| `CLAUDE_CODE_TASK_LIST_ID` | Іменований каталог завдань, спільний між сесіями | +| `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION` | Увімкнути/вимкнути пропозиції промптів (`true`/`false`) | +| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | Увімкнути експериментальні Agent Teams | +| `CLAUDE_CODE_NEW_INIT` | Використовувати новий потік ініціалізації | +| `CLAUDE_CODE_SUBAGENT_MODEL` | Модель для виконання субагентів | +| `CLAUDE_CODE_PLUGIN_SEED_DIR` | Каталог для seed-файлів плагінів | +| `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB` | Змінні оточення для видалення з підпроцесів | +| `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` | Перевизначити відсоток автокомпакції | +| `CLAUDE_STREAM_IDLE_TIMEOUT_MS` | Таймаут простою потоку в мілісекундах | +| `SLASH_COMMAND_TOOL_CHAR_BUDGET` | Бюджет символів для інструментів слеш-команд | +| `ENABLE_TOOL_SEARCH` | Увімкнути пошук інструментів | +| `MAX_MCP_OUTPUT_TOKENS` | Максимум токенів для виводу MCP-інструмента | + +--- + +## Швидкий довідник + +### Найпоширеніші команди + +```bash +# Інтерактивна сесія +claude + +# Швидке питання +claude -p "how do I..." + +# Продовжити розмову +claude -c + +# Обробити файл +cat file.py | claude -p "review this" + +# JSON-вивід для скриптів +claude -p --output-format json "query" +``` + +### Комбінації прапорців + +| Сценарій | Команда | +|----------|---------| +| Швидке код-рев'ю | `cat file \| claude -p "review"` | +| Структурований вивід | `claude -p --output-format json "query"` | +| Безпечне дослідження | `claude --permission-mode plan` | +| Автономність з безпекою | `claude --enable-auto-mode --permission-mode auto` | +| CI/CD інтеграція | `claude -p --max-turns 3 --output-format json` | +| Відновлення роботи | `claude -r "session-name"` | +| Кастомна модель | `claude --model opus "complex task"` | +| Мінімальний режим | `claude --bare "quick query"` | +| Ліміт бюджету | `claude -p --max-budget-usd 2.00 "analyze code"` | + +--- + +## Усунення несправностей + +### Команда не знайдена + +**Проблема:** `claude: command not found` + +**Рішення:** +- Встановіть Claude Code: `npm install -g @anthropic-ai/claude-code` +- Перевірте, що PATH включає глобальний bin-каталог npm +- Спробуйте запуск з повним шляхом: `npx claude` + +### Проблеми з API-ключем + +**Проблема:** Помилка автентифікації + +**Рішення:** +- Встановіть API-ключ: `export ANTHROPIC_API_KEY=your-key` +- Перевірте валідність ключа та наявність достатнього балансу +- Перевірте дозволи ключа для запитуваної моделі + +### Сесія не знайдена + +**Проблема:** Неможливо відновити сесію + +**Рішення:** +- Перегляньте доступні сесії, щоб знайти правильну назву/ID +- Сесії можуть закінчуватися після періоду неактивності +- Використовуйте `-c` для продовження останньої сесії + +### Проблеми з форматом виводу + +**Проблема:** JSON-вивід пошкоджений + +**Рішення:** +- Використовуйте `--json-schema` для примусового дотримання структури +- Додайте явні інструкції щодо JSON у промпті +- Використовуйте `--output-format json` (а не просто просіть JSON у промпті) + +### Відмова в дозволі + +**Проблема:** Виконання інструменту заблоковане + +**Рішення:** +- Перевірте налаштування `--permission-mode` +- Перегляньте прапорці `--allowedTools` та `--disallowedTools` +- Використовуйте `--dangerously-skip-permissions` для автоматизації (з обережністю) + +--- + +## Додаткові ресурси + +- **[Офіційний довідник CLI](https://code.claude.com/docs/en/cli-reference)** — повний довідник команд +- **[Документація Headless Mode](https://code.claude.com/docs/en/headless)** — автоматизоване виконання +- **[Слеш-команди](../01-slash-commands/)** — кастомні ярлики в Claude +- **[Посібник з памʼяті](../02-memory/)** — постійний контекст через CLAUDE.md +- **[Протокол MCP](../05-mcp/)** — інтеграція зовнішніх інструментів +- **[Розширені функції](../09-advanced-features/)** — режим планування, розширене мислення +- **[Посібник субагентів](../04-subagents/)** — делеговане виконання завдань + +--- + +*Частина серії посібників [Claude How To](../)* + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 From 6172aacfd52f056befd980071de68dd07b2b775c Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 22:31:43 +0300 Subject: [PATCH 08/20] feat(uk): translate P3 examples for modules 01, 02 01-slash-commands: 7 slash command examples 02-memory: 3 CLAUDE.md examples Progress: 25/67 files Ref: luongnv89/claude-howto#63 --- uk/01-slash-commands/commit.md | 29 + uk/01-slash-commands/doc-refactor.md | 27 + uk/01-slash-commands/generate-api-docs.md | 22 + uk/01-slash-commands/optimize.md | 22 + uk/01-slash-commands/pr.md | 29 + uk/01-slash-commands/push-all.md | 155 +++ uk/01-slash-commands/setup-ci-cd.md | 28 + uk/01-slash-commands/unit-test-expand.md | 28 + uk/02-memory/README.md | 1159 +++++++++++++++++++++ uk/02-memory/directory-api-CLAUDE.md | 64 ++ uk/02-memory/personal-CLAUDE.md | 63 ++ uk/02-memory/project-CLAUDE.md | 91 ++ 12 files changed, 1717 insertions(+) create mode 100644 uk/01-slash-commands/commit.md create mode 100644 uk/01-slash-commands/doc-refactor.md create mode 100644 uk/01-slash-commands/generate-api-docs.md create mode 100644 uk/01-slash-commands/optimize.md create mode 100644 uk/01-slash-commands/pr.md create mode 100644 uk/01-slash-commands/push-all.md create mode 100644 uk/01-slash-commands/setup-ci-cd.md create mode 100644 uk/01-slash-commands/unit-test-expand.md create mode 100644 uk/02-memory/README.md create mode 100644 uk/02-memory/directory-api-CLAUDE.md create mode 100644 uk/02-memory/personal-CLAUDE.md create mode 100644 uk/02-memory/project-CLAUDE.md diff --git a/uk/01-slash-commands/commit.md b/uk/01-slash-commands/commit.md new file mode 100644 index 0000000..be705c8 --- /dev/null +++ b/uk/01-slash-commands/commit.md @@ -0,0 +1,29 @@ +--- +allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git diff:*) +argument-hint: [message] +description: Створити git-коміт з контекстом +--- + +## Контекст + +- Поточний статус git: !`git status` +- Поточний git diff: !`git diff HEAD` +- Поточна гілка: !`git branch --show-current` +- Останні коміти: !`git log --oneline -10` + +## Ваше завдання + +На основі наведених вище змін створіть один git-коміт. + +Якщо повідомлення було передано через аргументи, використовуйте його: $ARGUMENTS + +Інакше проаналізуйте зміни та створіть відповідне повідомлення коміту відповідно до формату conventional commits: +- `feat:` для нових функцій +- `fix:` для виправлення помилок +- `docs:` для змін документації +- `refactor:` для рефакторингу коду +- `test:` для додавання тестів +- `chore:` для задач обслуговування + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/doc-refactor.md b/uk/01-slash-commands/doc-refactor.md new file mode 100644 index 0000000..e56a8a6 --- /dev/null +++ b/uk/01-slash-commands/doc-refactor.md @@ -0,0 +1,27 @@ +--- +name: Documentation Refactor +description: Реструктуризація документації проєкту для ясності та доступності +tags: documentation, refactoring, organization +--- + +# Рефакторинг документації + +Рефакторинг структури документації проєкту з адаптацією до типу проєкту: + +1. **Аналіз проєкту**: Визначити тип (бібліотека/API/веб-додаток/CLI/мікросервіси), архітектуру та персони користувачів +2. **Централізація документації**: Перемістити технічну документацію до `docs/` з належними перехресними посиланнями +3. **Кореневий README.md**: Оптимізувати як точку входу з оглядом, швидким стартом, резюме модулів/компонентів, ліцензією, контактами +4. **Документація компонентів**: Додати README файли на рівні модулів/пакетів/сервісів з інструкціями налаштування та тестування +5. **Організація `docs/`** за відповідними категоріями: + - Архітектура, Довідник API, База даних, Дизайн, Усунення несправностей, Деплой, Контрибʼюція (адаптувати до потреб проєкту) +6. **Створення посібників** (оберіть застосовні): + - Посібник користувача: Документація для кінцевих користувачів додатків + - Документація API: Ендпоінти, автентифікація, приклади для API + - Посібник розробника: Налаштування, тестування, процес контрибʼюції + - Посібник деплою: Деплой на продакшн для сервісів/додатків +7. **Використання Mermaid** для всіх діаграм (архітектура, потоки, схеми) + +Тримайте документацію лаконічною, зручною для сканування та контекстно відповідною типу проєкту. + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/generate-api-docs.md b/uk/01-slash-commands/generate-api-docs.md new file mode 100644 index 0000000..1d0717f --- /dev/null +++ b/uk/01-slash-commands/generate-api-docs.md @@ -0,0 +1,22 @@ +--- +description: Створення вичерпної документації API з вихідного коду +--- + +# Генератор документації API + +Генерація документації API шляхом: + +1. Сканування всіх файлів у `/src/api/` +2. Витягу сигнатур функцій та коментарів JSDoc +3. Організації за ендпоінтом/модулем +4. Створення markdown з прикладами +5. Включення схем запитів/відповідей +6. Додавання документації помилок + +Формат виводу: +- Markdown-файл у `/docs/api.md` +- Включити приклади curl для всіх ендпоінтів +- Додати типи TypeScript + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/optimize.md b/uk/01-slash-commands/optimize.md new file mode 100644 index 0000000..9f56ac5 --- /dev/null +++ b/uk/01-slash-commands/optimize.md @@ -0,0 +1,22 @@ +--- +description: Аналіз коду на проблеми продуктивності та пропозиції оптимізацій +--- + +# Оптимізація коду + +Перегляньте наданий код на наявність таких проблем у порядку пріоритету: + +1. **Вузькі місця продуктивності** — виявлення операцій O(n²), неефективних циклів +2. **Витоки памʼяті** — пошук невивільнених ресурсів, циклічних посилань +3. **Покращення алгоритмів** — пропозиція кращих алгоритмів або структур даних +4. **Можливості кешування** — виявлення повторюваних обчислень +5. **Проблеми конкурентності** — пошук станів гонки (race conditions) або проблем з потоками + +Формат відповіді: +- Серйозність проблеми (Критична/Висока/Середня/Низька) +- Місце в коді +- Пояснення +- Рекомендоване виправлення з прикладом коду + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/pr.md b/uk/01-slash-commands/pr.md new file mode 100644 index 0000000..fd45139 --- /dev/null +++ b/uk/01-slash-commands/pr.md @@ -0,0 +1,29 @@ +--- +description: Очистити код, підготувати зміни та створити pull request +allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git diff:*), Bash(npm test:*), Bash(npm run lint:*) +--- + +# Контрольний список підготовки Pull Request + +Перед створенням PR виконайте ці кроки: + +1. Запустити лінтинг: `prettier --write .` +2. Запустити тести: `npm test` +3. Переглянути git diff: `git diff HEAD` +4. Додати зміни до індексу: `git add .` +5. Створити повідомлення коміту відповідно до conventional commits: + - `fix:` для виправлення помилок + - `feat:` для нових функцій + - `docs:` для документації + - `refactor:` для реструктуризації коду + - `test:` для додавання тестів + - `chore:` для обслуговування + +6. Згенерувати опис PR, що включає: + - Що змінилося + - Чому змінилося + - Проведене тестування + - Потенційні наслідки + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/push-all.md b/uk/01-slash-commands/push-all.md new file mode 100644 index 0000000..169d2b4 --- /dev/null +++ b/uk/01-slash-commands/push-all.md @@ -0,0 +1,155 @@ +--- +description: Додати всі зміни до індексу, створити коміт та відправити на віддалений сервер (використовуйте з обережністю) +allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git push:*), Bash(git diff:*), Bash(git log:*), Bash(git pull:*) +--- + +# Коміт та Push усього + +⚠️ **УВАГА**: Додає ВСІ зміни до індексу, створює коміт та відправляє на віддалений сервер. Використовуйте лише коли впевнені, що всі зміни належать разом. + +## Робочий процес + +### 1. Аналіз змін +Запустити паралельно: +- `git status` — показати змінені/додані/видалені/невідстежувані файли +- `git diff --stat` — показати статистику змін +- `git log -1 --oneline` — показати останній коміт для стилю повідомлення + +### 2. Перевірки безпеки + +**❌ ЗУПИНИТИ та ПОПЕРЕДИТИ при виявленні:** +- Секрети: `.env*`, `*.key`, `*.pem`, `credentials.json`, `secrets.yaml`, `id_rsa`, `*.p12`, `*.pfx`, `*.cer` +- API-ключі: Будь-які змінні `*_API_KEY`, `*_SECRET`, `*_TOKEN` з реальними значеннями (не заповнювачі типу `your-api-key`, `xxx`, `placeholder`) +- Великі файли: `>10MB` без Git LFS +- Артефакти збірки: `node_modules/`, `dist/`, `build/`, `__pycache__/`, `*.pyc`, `.venv/` +- Тимчасові файли: `.DS_Store`, `thumbs.db`, `*.swp`, `*.tmp` + +**Валідація API-ключів:** +Перевірити змінені файли на патерни: +```bash +OPENAI_API_KEY=sk-proj-xxxxx # ❌ Виявлено реальний ключ! +AWS_SECRET_KEY=AKIA... # ❌ Виявлено реальний ключ! +STRIPE_API_KEY=sk_live_... # ❌ Виявлено реальний ключ! + +# ✅ Допустимі заповнювачі: +API_KEY=your-api-key-here +SECRET_KEY=placeholder +TOKEN=xxx +API_KEY= +SECRET=${YOUR_SECRET} +``` + +**✅ Перевірити:** +- `.gitignore` правильно налаштований +- Немає конфліктів злиття +- Правильна гілка (попередити якщо main/master) +- API-ключі є лише заповнювачами + +### 3. Запит підтвердження + +Представити резюме: +``` +📊 Резюме змін: +- X файлів змінено, Y додано, Z видалено +- Загалом: +AAA вставок, -BBB видалень + +🔒 Безпека: ✅ Без секретів | ✅ Без великих файлів | ⚠️ [попередження] +🌿 Гілка: [назва] → origin/[назва] + +Я виконаю: git add . → commit → push + +Введіть 'yes' для продовження або 'no' для скасування. +``` + +**ЧЕКАТИ явного "yes" перед продовженням.** + +### 4. Виконання (після підтвердження) + +Запустити послідовно: +```bash +git add . +git status # Перевірка індексу +``` + +### 5. Генерація повідомлення коміту + +Проаналізувати зміни та створити conventional commit: + +**Формат:** +``` +[тип]: Короткий опис (макс. 72 символи) + +- Ключова зміна 1 +- Ключова зміна 2 +- Ключова зміна 3 +``` + +**Типи:** `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `build`, `ci` + +**Приклад:** +``` +docs: Update concept README files with comprehensive documentation + +- Add architecture diagrams and tables +- Include practical examples +- Expand best practices sections +``` + +### 6. Коміт та Push + +```bash +git commit -m "$(cat <<'EOF' +[Згенероване повідомлення коміту] +EOF +)" +git push # Якщо невдача: git pull --rebase && git push +git log -1 --oneline --decorate # Перевірка +``` + +### 7. Підтвердження успіху + +``` +✅ Успішно відправлено на віддалений сервер! + +Коміт: [хеш] [повідомлення] +Гілка: [гілка] → origin/[гілка] +Змінено файлів: X (+вставок, -видалень) +``` + +## Обробка помилок + +- **git add невдача**: Перевірити дозволи, заблоковані файли, переконатися що репо ініціалізовано +- **git commit невдача**: Виправити pre-commit хуки, перевірити git config (user.name/email) +- **git push невдача**: + - Non-fast-forward: `git pull --rebase && git push` + - Немає віддаленої гілки: `git push -u origin [гілка]` + - Захищена гілка: Використати PR-процес замість цього + +## Коли використовувати + +✅ **Доцільно:** +- Оновлення документації в кількох файлах +- Функція з тестами та документацією +- Виправлення помилок у кількох файлах +- Форматування/рефакторинг всього проєкту +- Зміни конфігурації + +❌ **Уникати:** +- Невпевненість у тому, що комітиться +- Містить секрети/чутливі дані +- Захищені гілки без рев'ю +- Присутні конфлікти злиття +- Потрібна гранулярна історія комітів +- Pre-commit хуки не проходять + +## Альтернативи + +Якщо користувач хоче більше контролю, запропонувати: +1. **Вибіркове додавання**: Переглянути/додати конкретні файли +2. **Інтерактивне додавання**: `git add -p` для вибору патчів +3. **PR-процес**: Створити гілку → push → PR (використати команду `/pr`) + +**⚠️ Памʼятайте**: Завжди переглядайте зміни перед push. Якщо сумніваєтесь, використовуйте окремі git-команди для більшого контролю. + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/setup-ci-cd.md b/uk/01-slash-commands/setup-ci-cd.md new file mode 100644 index 0000000..e6af565 --- /dev/null +++ b/uk/01-slash-commands/setup-ci-cd.md @@ -0,0 +1,28 @@ +--- +name: Setup CI/CD Pipeline +description: Реалізація pre-commit хуків та GitHub Actions для забезпечення якості +tags: ci-cd, devops, automation +--- + +# Налаштування CI/CD пайплайну + +Реалізація комплексних шлюзів якості DevOps з адаптацією до типу проєкту: + +1. **Аналіз проєкту**: Визначити мову(и), фреймворк, систему збірки та наявний інструментарій +2. **Налаштування pre-commit хуків** з інструментами для конкретної мови: + - Форматування: Prettier/Black/gofmt/rustfmt/тощо + - Лінтинг: ESLint/Ruff/golangci-lint/Clippy/тощо + - Безпека: Bandit/gosec/cargo-audit/npm audit/тощо + - Перевірка типів: TypeScript/mypy/flow (якщо застосовно) + - Тести: Запуск відповідних тестових наборів +3. **Створення GitHub Actions workflows** (.github/workflows/): + - Дзеркалювання pre-commit перевірок на push/PR + - Матриця версій/платформ (якщо застосовно) + - Верифікація збірки та тестів + - Кроки деплою (за потреби) +4. **Верифікація пайплайну**: Тестування локально, створення тестового PR, підтвердження проходження всіх перевірок + +Використовуйте безкоштовні/відкриті інструменти. Поважайте існуючі конфігурації. Тримайте виконання швидким. + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/01-slash-commands/unit-test-expand.md b/uk/01-slash-commands/unit-test-expand.md new file mode 100644 index 0000000..6568ff4 --- /dev/null +++ b/uk/01-slash-commands/unit-test-expand.md @@ -0,0 +1,28 @@ +--- +name: Expand Unit Tests +description: Збільшення покриття тестами шляхом тестування невідстежених гілок та граничних випадків +tags: testing, coverage, unit-tests +--- + +# Розширення юніт-тестів + +Розширення існуючих юніт-тестів з адаптацією до тестового фреймворку проєкту: + +1. **Аналіз покриття**: Запустити звіт покриття для виявлення неперевірених гілок, граничних випадків та зон з низьким покриттям +2. **Виявлення прогалин**: Переглянути код на предмет логічних гілок, шляхів помилок, граничних умов, null/порожніх вхідних даних +3. **Написання тестів** з використанням фреймворку проєкту: + - Jest/Vitest/Mocha (JavaScript/TypeScript) + - pytest/unittest (Python) + - Go testing/testify (Go) + - Rust test framework (Rust) +4. **Цільові сценарії**: + - Обробка помилок та виключень + - Граничні значення (мін/макс, порожні, null) + - Крайні та кутові випадки (edge/corner cases) + - Переходи станів та побічні ефекти +5. **Верифікація покращення**: Запустити покриття повторно, підтвердити вимірюване збільшення + +Представляти лише нові блоки тестового коду. Дотримуватися існуючих патернів та конвенцій іменування тестів. + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/02-memory/README.md b/uk/02-memory/README.md new file mode 100644 index 0000000..66bbf45 --- /dev/null +++ b/uk/02-memory/README.md @@ -0,0 +1,1159 @@ + + + + + + + Claude How To + + +# Посібник з пам'яті + +Пам'ять дозволяє Claude зберігати контекст між сесіями та розмовами. Вона існує у двох формах: автоматичний синтез у claude.ai та файлова система CLAUDE.md у Claude Code. + +## Огляд + +Пам'ять у Claude Code забезпечує постійний контекст, який зберігається між кількома сесіями та розмовами. На відміну від тимчасового контекстного вікна, файли пам'яті дозволяють: + +- Поширювати стандарти проєкту на всю команду +- Зберігати персональні налаштування розробки +- Підтримувати правила та конфігурації для конкретних каталогів +- Імпортувати зовнішню документацію +- Версіонувати пам'ять як частину проєкту + +Система пам'яті працює на кількох рівнях — від глобальних персональних налаштувань до конкретних підкаталогів — забезпечуючи детальний контроль над тим, що Claude запам'ятовує і як застосовує ці знання. + +## Короткий довідник команд пам'яті + +| Команда | Призначення | Використання | Коли застосовувати | +|---------|------------|--------------|-------------------| +| `/init` | Ініціалізація пам'яті проєкту | `/init` | Початок нового проєкту, перше налаштування CLAUDE.md | +| `/memory` | Редагування файлів пам'яті в редакторі | `/memory` | Великі оновлення, реорганізація, перегляд вмісту | +| Префікс `#` | ~~Швидке додавання однорядкового правила~~ **Припинено** | — | Використовуйте `/memory` або просіть у розмові | +| `@шлях/до/файлу` | Імпорт зовнішнього вмісту | `@README.md` або `@docs/api.md` | Посилання на наявну документацію в CLAUDE.md | + +## Швидкий старт: ініціалізація пам'яті + +### Команда `/init` + +Команда `/init` — найшвидший спосіб налаштувати пам'ять проєкту в Claude Code. Вона ініціалізує файл CLAUDE.md з базовою документацією проєкту. + +**Використання:** + +```bash +/init +``` + +**Що вона робить:** + +- Створює новий файл CLAUDE.md у проєкті (зазвичай `./CLAUDE.md` або `./.claude/CLAUDE.md`) +- Встановлює конвенції та рекомендації проєкту +- Закладає основу для збереження контексту між сесіями +- Надає шаблонну структуру для документування стандартів проєкту + +**Покращений інтерактивний режим:** Встановіть `CLAUDE_CODE_NEW_INIT=1`, щоб увімкнути багатофазний інтерактивний потік, який крок за кроком проведе вас через налаштування проєкту: + +```bash +CLAUDE_CODE_NEW_INIT=1 claude +/init +``` + +**Коли використовувати `/init`:** + +- Початок нового проєкту з Claude Code +- Встановлення командних стандартів кодування +- Створення документації про структуру кодової бази +- Налаштування ієрархії пам'яті для колективної розробки + +**Приклад робочого процесу:** + +```markdown +# У каталозі вашого проєкту +/init + +# Claude створює CLAUDE.md зі структурою: +# Конфігурація проєкту +## Огляд проєкту +- Назва: Ваш Проєкт +- Стек технологій: [Ваші технології] +- Розмір команди: [Кількість розробників] + +## Стандарти розробки +- Стиль коду +- Вимоги до тестування +- Конвенції Git-воркфлову +``` + +### Швидкі оновлення пам'яті + +> **Примітка**: Ярлик `#` для вбудованого додавання до пам'яті було припинено. Використовуйте `/memory` для прямого редагування файлів пам'яті або попросіть Claude в розмові запам'ятати щось (наприклад, "запам'ятай, що ми завжди використовуємо TypeScript strict mode"). + +Рекомендовані способи додавання інформації до пам'яті: + +**Варіант 1: Команда `/memory`** + +```bash +/memory +``` + +Відкриває файли пам'яті у вашому системному редакторі для прямого редагування. + +**Варіант 2: Запит у розмові** + +``` +Remember that we always use TypeScript strict mode in this project. +Please add to memory: prefer async/await over promise chains. +``` + +Claude оновить відповідний файл CLAUDE.md на основі вашого запиту. + +**Історична довідка** (більше не працює): + +Ярлик із префіксом `#` раніше дозволяв додавати правила прямо в розмові: + +```markdown +# Always use TypeScript strict mode in this project ← більше не працює +``` + +Якщо ви використовували цей шаблон, перейдіть на команду `/memory` або запити в розмові. + +### Команда `/memory` + +Команда `/memory` надає прямий доступ до редагування файлів пам'яті CLAUDE.md у сесіях Claude Code. Вона відкриває файли пам'яті у вашому системному редакторі для комплексного редагування. + +**Використання:** + +```bash +/memory +``` + +**Що вона робить:** + +- Відкриває файли пам'яті у стандартному редакторі системи +- Дозволяє робити великі доповнення, модифікації та реорганізацію +- Надає прямий доступ до всіх файлів пам'яті в ієрархії +- Дає змогу керувати постійним контекстом між сесіями + +**Коли використовувати `/memory`:** + +- Перегляд наявного вмісту пам'яті +- Великі оновлення стандартів проєкту +- Реорганізація структури пам'яті +- Додавання детальної документації чи рекомендацій +- Підтримка та оновлення пам'яті в міру розвитку проєкту + +**Порівняння: `/memory` та `/init`** + +| Аспект | `/memory` | `/init` | +|--------|-----------|---------| +| **Призначення** | Редагування наявних файлів пам'яті | Ініціалізація нового CLAUDE.md | +| **Коли** | Оновлення/модифікація контексту проєкту | Початок нового проєкту | +| **Дія** | Відкриває редактор для змін | Генерує стартовий шаблон | +| **Воркфлов** | Постійна підтримка | Одноразове налаштування | + +**Приклад робочого процесу:** + +```markdown +# Відкрити пам'ять для редагування +/memory + +# Claude пропонує варіанти: +# 1. Managed Policy Memory +# 2. Project Memory (./CLAUDE.md) +# 3. User Memory (~/.claude/CLAUDE.md) +# 4. Local Project Memory + +# Оберіть варіант 2 (Project Memory) +# Стандартний редактор відкриє вміст ./CLAUDE.md + +# Внесіть зміни, збережіть і закрийте редактор +# Claude автоматично перезавантажить оновлену пам'ять +``` + +**Використання імпортів у пам'яті:** + +Файли CLAUDE.md підтримують синтаксис `@шлях/до/файлу` для включення зовнішнього вмісту: + +```markdown +# Документація проєкту +See @README.md for project overview +See @package.json for available npm commands +See @docs/architecture.md for system design + +# Імпорт з домашнього каталогу за абсолютним шляхом +@~/.claude/my-project-instructions.md +``` + +**Можливості імпорту:** + +- Підтримуються відносні та абсолютні шляхи (наприклад, `@docs/api.md` або `@~/.claude/my-project-instructions.md`) +- Підтримуються рекурсивні імпорти з максимальною глибиною 5 +- Перший імпорт із зовнішнього розташування викликає діалог підтвердження для безпеки +- Директиви імпорту не обробляються всередині code span та code block у Markdown (тому їх безпечно документувати в прикладах) +- Допомагає уникнути дублювання, посилаючись на наявну документацію +- Автоматично включає вміст посилань у контекст Claude + +## Архітектура пам'яті + +Пам'ять у Claude Code побудована за ієрархічною системою, де різні рівні виконують різні функції: + +```mermaid +graph TB + A["Claude Session"] + B["User Input"] + C["Memory System"] + D["Memory Storage"] + + B -->|User provides info| C + C -->|Synthesizes every 24h| D + D -->|Loads automatically| A + A -->|Uses context| C +``` + +## Ієрархія пам'яті в Claude Code + +Claude Code використовує багаторівневу ієрархічну систему пам'яті. Файли пам'яті автоматично завантажуються при запуску Claude Code, причому файли вищого рівня мають більший пріоритет. + +**Повна ієрархія пам'яті (за пріоритетом):** + +1. **Managed Policy** — загальноорганізаційні інструкції + - macOS: `/Library/Application Support/ClaudeCode/CLAUDE.md` + - Linux/WSL: `/etc/claude-code/CLAUDE.md` + - Windows: `C:\Program Files\ClaudeCode\CLAUDE.md` + +2. **Managed Drop-ins** — модульні файли політик, об'єднані за алфавітом (v2.1.83+) + - Каталог `managed-settings.d/` поруч із файлом managed policy CLAUDE.md + +3. **Project Memory** — спільний контекст команди (версіонований) + - `./.claude/CLAUDE.md` або `./CLAUDE.md` (у корені репозиторію) + +4. **Project Rules** — модульні, тематичні інструкції проєкту + - `./.claude/rules/*.md` + +5. **User Memory** — персональні налаштування (для всіх проєктів) + - `~/.claude/CLAUDE.md` + +6. **User-Level Rules** — персональні правила (для всіх проєктів) + - `~/.claude/rules/*.md` + +7. **Local Project Memory** — персональні налаштування конкретного проєкту + - `./CLAUDE.local.md` + +> **Примітка**: `CLAUDE.local.md` повністю підтримується та задокументований в [офіційній документації](https://code.claude.com/docs/en/memory). Він зберігає персональні налаштування проєкту, які не комітяться у систему контролю версій. Додайте `CLAUDE.local.md` до `.gitignore`. + +8. **Auto Memory** — автоматичні нотатки та висновки Claude + - `~/.claude/projects//memory/` + +**Поведінка пошуку пам'яті:** + +Claude шукає файли пам'яті у такому порядку, причому раніші розташування мають більший пріоритет: + +```mermaid +graph TD + A["Managed Policy
/Library/.../ClaudeCode/CLAUDE.md"] -->|highest priority| A2["Managed Drop-ins
managed-settings.d/"] + A2 --> B["Project Memory
./CLAUDE.md"] + B --> C["Project Rules
./.claude/rules/*.md"] + C --> D["User Memory
~/.claude/CLAUDE.md"] + D --> E["User Rules
~/.claude/rules/*.md"] + E --> F["Local Project Memory
./CLAUDE.local.md"] + F --> G["Auto Memory
~/.claude/projects/.../memory/"] + + B -->|imports| H["@docs/architecture.md"] + H -->|imports| I["@docs/api-standards.md"] + + style A fill:#fce4ec,stroke:#333,color:#333 + style A2 fill:#fce4ec,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#e1f5fe,stroke:#333,color:#333 + style D fill:#f3e5f5,stroke:#333,color:#333 + style E fill:#f3e5f5,stroke:#333,color:#333 + style F fill:#e8f5e9,stroke:#333,color:#333 + style G fill:#fff3e0,stroke:#333,color:#333 + style H fill:#e1f5fe,stroke:#333,color:#333 + style I fill:#e1f5fe,stroke:#333,color:#333 +``` + +## Виключення файлів CLAUDE.md за допомогою `claudeMdExcludes` + +У великих монорепозиторіях деякі файли CLAUDE.md можуть бути нерелевантними для вашої поточної роботи. Налаштування `claudeMdExcludes` дозволяє пропускати певні файли CLAUDE.md, щоб вони не завантажувались у контекст: + +```jsonc +// В ~/.claude/settings.json або .claude/settings.json +{ + "claudeMdExcludes": [ + "packages/legacy-app/CLAUDE.md", + "vendors/**/CLAUDE.md" + ] +} +``` + +Патерни зіставляються зі шляхами відносно кореня проєкту. Це особливо корисно для: + +- Монорепозиторіїв з багатьма підпроєктами, де релевантні лише деякі +- Репозиторіїв із вендорними або сторонніми файлами CLAUDE.md +- Зменшення шуму в контекстному вікні Claude виключенням застарілих або нерелевантних інструкцій + +## Ієрархія файлів налаштувань + +Налаштування Claude Code (включаючи `autoMemoryDirectory`, `claudeMdExcludes` та іншу конфігурацію) визначаються з п'ятирівневої ієрархії, де вищі рівні мають більший пріоритет: + +| Рівень | Розташування | Область дії | +|--------|-------------|-------------| +| 1 (Найвищий) | Managed policy (системний рівень) | Загальноорганізаційне застосування | +| 2 | `managed-settings.d/` (v2.1.83+) | Модульні drop-in політики, об'єднані за алфавітом | +| 3 | `~/.claude/settings.json` | Налаштування користувача | +| 4 | `.claude/settings.json` | Рівень проєкту (комітиться в git) | +| 5 (Найнижчий) | `.claude/settings.local.json` | Локальні перевизначення (ігнорується git) | + +**Платформо-специфічна конфігурація (v2.1.51+):** + +Налаштування також можна конфігурувати через: +- **macOS**: файли Property list (plist) +- **Windows**: Реєстр Windows + +Ці платформо-нативні механізми зчитуються разом з JSON-файлами налаштувань і підпорядковуються тим самим правилам пріоритетності. + +## Модульна система правил + +Створюйте організовані, специфічні для шляхів правила за допомогою структури каталогу `.claude/rules/`. Правила можна визначати як на рівні проєкту, так і на рівні користувача: + +``` +your-project/ +├── .claude/ +│ ├── CLAUDE.md +│ └── rules/ +│ ├── code-style.md +│ ├── testing.md +│ ├── security.md +│ └── api/ # Підкаталоги підтримуються +│ ├── conventions.md +│ └── validation.md + +~/.claude/ +├── CLAUDE.md +└── rules/ # Правила рівня користувача (для всіх проєктів) + ├── personal-style.md + └── preferred-patterns.md +``` + +Правила знаходяться рекурсивно в каталозі `rules/`, включаючи підкаталоги. Правила рівня користувача з `~/.claude/rules/` завантажуються перед правилами рівня проєкту, дозволяючи персональні значення за замовчуванням, які проєкти можуть перевизначити. + +### Правила для конкретних шляхів із YAML-фронтматером + +Визначайте правила, що застосовуються лише до конкретних шляхів файлів: + +```markdown +--- +paths: src/api/**/*.ts +--- + +# API Development Rules + +- All API endpoints must include input validation +- Use Zod for schema validation +- Document all parameters and response types +- Include error handling for all operations +``` + +**Приклади glob-патернів:** + +- `**/*.ts` — всі TypeScript-файли +- `src/**/*` — всі файли в src/ +- `src/**/*.{ts,tsx}` — кілька розширень +- `{src,lib}/**/*.ts, tests/**/*.test.ts` — кілька патернів + +### Підкаталоги та симлінки + +Правила в `.claude/rules/` підтримують дві організаційні можливості: + +- **Підкаталоги**: правила знаходяться рекурсивно, тому їх можна організувати в тематичні папки (наприклад, `rules/api/`, `rules/testing/`, `rules/security/`) +- **Симлінки**: підтримуються для спільного використання правил між кількома проєктами. Наприклад, можна створити симлінк на спільний файл правил з центрального розташування в каталог `.claude/rules/` кожного проєкту + +## Таблиця розташувань пам'яті + +| Розташування | Область дії | Пріоритет | Спільний | Доступ | Найкраще для | +|-------------|-------------|-----------|---------|--------|-------------| +| `/Library/Application Support/ClaudeCode/CLAUDE.md` (macOS) | Managed Policy | 1 (Найвищий) | Організація | Система | Загальноорганізаційні політики | +| `/etc/claude-code/CLAUDE.md` (Linux/WSL) | Managed Policy | 1 (Найвищий) | Організація | Система | Стандарти організації | +| `C:\Program Files\ClaudeCode\CLAUDE.md` (Windows) | Managed Policy | 1 (Найвищий) | Організація | Система | Корпоративні рекомендації | +| `managed-settings.d/*.md` (поруч з policy) | Managed Drop-ins | 1.5 | Організація | Система | Модульні файли політик (v2.1.83+) | +| `./CLAUDE.md` або `./.claude/CLAUDE.md` | Project Memory | 2 | Команда | Git | Командні стандарти, спільна архітектура | +| `./.claude/rules/*.md` | Project Rules | 3 | Команда | Git | Модульні правила для конкретних шляхів | +| `~/.claude/CLAUDE.md` | User Memory | 4 | Індивідуальний | Файлова система | Персональні налаштування (всі проєкти) | +| `~/.claude/rules/*.md` | User Rules | 5 | Індивідуальний | Файлова система | Персональні правила (всі проєкти) | +| `./CLAUDE.local.md` | Project Local | 6 | Індивідуальний | Git (ігнорується) | Персональні налаштування проєкту | +| `~/.claude/projects//memory/` | Auto Memory | 7 (Найнижчий) | Індивідуальний | Файлова система | Автоматичні нотатки та висновки Claude | + +## Життєвий цикл оновлення пам'яті + +Ось як оновлення пам'яті проходять через сесії Claude Code: + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Editor as File System + participant Memory as CLAUDE.md + + User->>Claude: "Remember: use async/await" + Claude->>User: "Which memory file?" + User->>Claude: "Project memory" + Claude->>Editor: Open ~/.claude/settings.json + Claude->>Memory: Write to ./CLAUDE.md + Memory-->>Claude: File saved + Claude->>Claude: Load updated memory + Claude-->>User: "Memory saved!" +``` + +## Auto Memory + +Auto memory — це постійний каталог, куди Claude автоматично записує висновки, патерни та інсайти під час роботи з вашим проєктом. На відміну від файлів CLAUDE.md, які ви пишете та підтримуєте вручну, auto memory записується самим Claude під час сесій. + +### Як працює Auto Memory + +- **Розташування**: `~/.claude/projects//memory/` +- **Точка входу**: `MEMORY.md` — головний файл у каталозі auto memory +- **Тематичні файли**: додаткові файли для конкретних тем (наприклад, `debugging.md`, `api-conventions.md`) +- **Поведінка завантаження**: перші 200 рядків `MEMORY.md` (або перші 25 КБ — що менше) завантажуються в контекст на початку сесії. Тематичні файли завантажуються за потребою, не при запуску. +- **Читання/запис**: Claude читає та записує файли пам'яті під час сесій, виявляючи патерни та знання, специфічні для проєкту + +### Архітектура Auto Memory + +```mermaid +graph TD + A["Claude Session Starts"] --> B["Load MEMORY.md
(first 200 lines / 25KB)"] + B --> C["Session Active"] + C --> D["Claude discovers
patterns & insights"] + D --> E{"Write to
auto memory"} + E -->|General notes| F["MEMORY.md"] + E -->|Topic-specific| G["debugging.md"] + E -->|Topic-specific| H["api-conventions.md"] + C --> I["On-demand load
topic files"] + I --> C + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#e8f5e9,stroke:#333,color:#333 + style D fill:#f3e5f5,stroke:#333,color:#333 + style E fill:#fff3e0,stroke:#333,color:#333 + style F fill:#fce4ec,stroke:#333,color:#333 + style G fill:#fce4ec,stroke:#333,color:#333 + style H fill:#fce4ec,stroke:#333,color:#333 + style I fill:#f3e5f5,stroke:#333,color:#333 +``` + +### Структура каталогу Auto Memory + +``` +~/.claude/projects//memory/ +├── MEMORY.md # Точка входу (перші 200 рядків / 25 КБ завантажуються при запуску) +├── debugging.md # Тематичний файл (завантажується за потребою) +├── api-conventions.md # Тематичний файл (завантажується за потребою) +└── testing-patterns.md # Тематичний файл (завантажується за потребою) +``` + +### Вимога до версії + +Auto memory потребує **Claude Code v2.1.59 або новішої версії**. Якщо у вас старіша версія, спочатку оновіть: + +```bash +npm install -g @anthropic-ai/claude-code@latest +``` + +### Власний каталог Auto Memory + +За замовчуванням auto memory зберігається в `~/.claude/projects//memory/`. Ви можете змінити це розташування за допомогою налаштування `autoMemoryDirectory` (доступне з **v2.1.74**): + +```jsonc +// В ~/.claude/settings.json або .claude/settings.local.json (тільки налаштування користувача/локальні) +{ + "autoMemoryDirectory": "/path/to/custom/memory/directory" +} +``` + +> **Примітка**: `autoMemoryDirectory` можна встановити лише в налаштуваннях рівня користувача (`~/.claude/settings.json`) або локальних налаштуваннях (`.claude/settings.local.json`), а не в налаштуваннях проєкту чи managed policy. + +Це корисно, коли ви хочете: + +- Зберігати auto memory у спільному або синхронізованому розташуванні +- Відокремити auto memory від стандартного каталогу конфігурації Claude +- Використовувати шлях, специфічний для проєкту, поза стандартною ієрархією + +### Спільне використання Worktree та репозиторію + +Усі робочі дерева (worktrees) та підкаталоги в межах одного git-репозиторію використовують один каталог auto memory. Це означає, що перемикання між worktrees або робота в різних підкаталогах одного репо читатиме та записуватиме ті самі файли пам'яті. + +### Пам'ять субагентів + +Субагенти (створені через інструменти на кшталт Task або паралельного виконання) можуть мати власний контекст пам'яті. Використовуйте поле `memory` у фронтматері визначення субагента, щоб вказати, які рівні пам'яті завантажувати: + +```yaml +memory: user # Завантажити лише пам'ять рівня користувача +memory: project # Завантажити лише пам'ять рівня проєкту +memory: local # Завантажити лише локальну пам'ять +``` + +Це дозволяє субагентам працювати з фокусованим контекстом, а не успадковувати повну ієрархію пам'яті. + +> **Примітка**: Субагенти також можуть підтримувати власну auto memory. Див. [офіційну документацію пам'яті субагентів](https://code.claude.com/docs/en/sub-agents#enable-persistent-memory) для деталей. + +### Керування Auto Memory + +Auto memory можна контролювати через змінну оточення `CLAUDE_CODE_DISABLE_AUTO_MEMORY`: + +| Значення | Поведінка | +|----------|----------| +| `0` | Примусово **увімкнути** auto memory | +| `1` | Примусово **вимкнути** auto memory | +| *(не встановлено)* | Стандартна поведінка (auto memory увімкнено) | + +```bash +# Вимкнути auto memory для сесії +CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 claude + +# Примусово увімкнути auto memory +CLAUDE_CODE_DISABLE_AUTO_MEMORY=0 claude +``` + +## Додаткові каталоги з `--add-dir` + +Прапорець `--add-dir` дозволяє Claude Code завантажувати файли CLAUDE.md з додаткових каталогів, окрім поточного робочого каталогу. Це корисно для монорепозиторіїв або мультипроєктних конфігурацій, де контекст з інших каталогів є релевантним. + +Для увімкнення цієї функції встановіть змінну оточення: + +```bash +CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 +``` + +Потім запустіть Claude Code з прапорцем: + +```bash +claude --add-dir /path/to/other/project +``` + +Claude завантажить CLAUDE.md із зазначеного додаткового каталогу разом з файлами пам'яті з вашого поточного робочого каталогу. + +## Практичні приклади + +### Приклад 1: Структура пам'яті проєкту + +**Файл:** `./CLAUDE.md` + +```markdown +# Project Configuration + +## Project Overview +- **Name**: E-commerce Platform +- **Tech Stack**: Node.js, PostgreSQL, React 18, Docker +- **Team Size**: 5 developers +- **Deadline**: Q4 2025 + +## Architecture +@docs/architecture.md +@docs/api-standards.md +@docs/database-schema.md + +## Development Standards + +### Code Style +- Use Prettier for formatting +- Use ESLint with airbnb config +- Maximum line length: 100 characters +- Use 2-space indentation + +### Naming Conventions +- **Files**: kebab-case (user-controller.js) +- **Classes**: PascalCase (UserService) +- **Functions/Variables**: camelCase (getUserById) +- **Constants**: UPPER_SNAKE_CASE (API_BASE_URL) +- **Database Tables**: snake_case (user_accounts) + +### Git Workflow +- Branch names: `feature/description` or `fix/description` +- Commit messages: Follow conventional commits +- PR required before merge +- All CI/CD checks must pass +- Minimum 1 approval required + +### Testing Requirements +- Minimum 80% code coverage +- All critical paths must have tests +- Use Jest for unit tests +- Use Cypress for E2E tests +- Test filenames: `*.test.ts` or `*.spec.ts` + +### API Standards +- RESTful endpoints only +- JSON request/response +- Use HTTP status codes correctly +- Version API endpoints: `/api/v1/` +- Document all endpoints with examples + +### Database +- Use migrations for schema changes +- Never hardcode credentials +- Use connection pooling +- Enable query logging in development +- Regular backups required + +### Deployment +- Docker-based deployment +- Kubernetes orchestration +- Blue-green deployment strategy +- Automatic rollback on failure +- Database migrations run before deploy + +## Common Commands + +| Command | Purpose | +|---------|---------| +| `npm run dev` | Start development server | +| `npm test` | Run test suite | +| `npm run lint` | Check code style | +| `npm run build` | Build for production | +| `npm run migrate` | Run database migrations | + +## Team Contacts +- Tech Lead: Sarah Chen (@sarah.chen) +- Product Manager: Mike Johnson (@mike.j) +- DevOps: Alex Kim (@alex.k) + +## Known Issues & Workarounds +- PostgreSQL connection pooling limited to 20 during peak hours +- Workaround: Implement query queuing +- Safari 14 compatibility issues with async generators +- Workaround: Use Babel transpiler + +## Related Projects +- Analytics Dashboard: `/projects/analytics` +- Mobile App: `/projects/mobile` +- Admin Panel: `/projects/admin` +``` + +### Приклад 2: Пам'ять для конкретного каталогу + +**Файл:** `./src/api/CLAUDE.md` + +````markdown +# API Module Standards + +This file overrides root CLAUDE.md for everything in /src/api/ + +## API-Specific Standards + +### Request Validation +- Use Zod for schema validation +- Always validate input +- Return 400 with validation errors +- Include field-level error details + +### Authentication +- All endpoints require JWT token +- Token in Authorization header +- Token expires after 24 hours +- Implement refresh token mechanism + +### Response Format + +All responses must follow this structure: + +```json +{ + "success": true, + "data": { /* actual data */ }, + "timestamp": "2025-11-06T10:30:00Z", + "version": "1.0" +} +``` + +Error responses: +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "User message", + "details": { /* field errors */ } + }, + "timestamp": "2025-11-06T10:30:00Z" +} +``` + +### Pagination +- Use cursor-based pagination (not offset) +- Include `hasMore` boolean +- Limit max page size to 100 +- Default page size: 20 + +### Rate Limiting +- 1000 requests per hour for authenticated users +- 100 requests per hour for public endpoints +- Return 429 when exceeded +- Include retry-after header + +### Caching +- Use Redis for session caching +- Cache duration: 5 minutes default +- Invalidate on write operations +- Tag cache keys with resource type +```` + +### Приклад 3: Персональна пам'ять + +**Файл:** `~/.claude/CLAUDE.md` + +```markdown +# My Development Preferences + +## About Me +- **Experience Level**: 8 years full-stack development +- **Preferred Languages**: TypeScript, Python +- **Communication Style**: Direct, with examples +- **Learning Style**: Visual diagrams with code + +## Code Preferences + +### Error Handling +I prefer explicit error handling with try-catch blocks and meaningful error messages. +Avoid generic errors. Always log errors for debugging. + +### Comments +Use comments for WHY, not WHAT. Code should be self-documenting. +Comments should explain business logic or non-obvious decisions. + +### Testing +I prefer TDD (test-driven development). +Write tests first, then implementation. +Focus on behavior, not implementation details. + +### Architecture +I prefer modular, loosely-coupled design. +Use dependency injection for testability. +Separate concerns (Controllers, Services, Repositories). + +## Debugging Preferences +- Use console.log with prefix: `[DEBUG]` +- Include context: function name, relevant variables +- Use stack traces when available +- Always include timestamps in logs + +## Communication +- Explain complex concepts with diagrams +- Show concrete examples before explaining theory +- Include before/after code snippets +- Summarize key points at the end + +## Project Organization +I organize my projects as: + + project/ + ├── src/ + │ ├── api/ + │ ├── services/ + │ ├── models/ + │ └── utils/ + ├── tests/ + ├── docs/ + └── docker/ + +## Tooling +- **IDE**: VS Code with vim keybindings +- **Terminal**: Zsh with Oh-My-Zsh +- **Format**: Prettier (100 char line length) +- **Linter**: ESLint with airbnb config +- **Test Framework**: Jest with React Testing Library +``` + +_Мій тест_ +Попросіть Claude зберегти нове правило + +![Попросіть Claude зберегти нове правило](memory-ask-claude.png) +Claude не зберіг правило, бо у мене ніде не було файлу `Claude.md`. Потім попросив Claude підтвердити розташування. + +![Попросіть Claude зберегти нове правило](memory-saved.png) + +### Приклад 4: Оновлення пам'яті під час сесії + +Ви можете додавати нові правила до пам'яті під час активної сесії Claude Code. Є два способи це зробити: + +#### Метод 1: Прямий запит + +```markdown +User: Remember that I prefer using React hooks instead of class components + for all new components. + +Claude: I'm adding that to your memory. Which memory file should this go in? + 1. Project memory (./CLAUDE.md) + 2. Personal memory (~/.claude/CLAUDE.md) + +User: Project memory + +Claude: ✅ Memory saved! + +Added to ./CLAUDE.md: +--- + +### Component Development +- Use functional components with React Hooks +- Prefer hooks over class components +- Custom hooks for reusable logic +- Use useCallback for event handlers +- Use useMemo for expensive computations +``` + +#### Метод 2: Використання шаблону "# new rule into memory" + +Також можна використовувати явний шаблон "# new rule into memory" для оновлення пам'яті: + +```markdown +User: # new rule into memory + Always validate user input with Zod schemas before processing. + +Claude: I'm saving this rule to memory. Which memory file should I use? + 1. Project memory (./CLAUDE.md) + 2. Personal memory (~/.claude/CLAUDE.md) + +User: Project memory + +Claude: ✅ Memory saved! + +Added to ./CLAUDE.md: +--- + +### Input Validation +- Always validate user input with Zod schemas before processing +- Define schemas at the top of each API handler file +- Return 400 status with validation errors +``` + +#### Поради щодо додавання до пам'яті + +- Формулюйте правила конкретно та дієво +- Групуйте пов'язані правила під заголовком секції +- Оновлюйте наявні секції замість дублювання вмісту +- Обирайте відповідний рівень пам'яті (проєкт чи персональний) + +## Порівняння функцій пам'яті + +| Функція | Claude Web/Desktop | Claude Code (CLAUDE.md) | +|---------|-------------------|------------------------| +| Автосинтез | ✅ Кожні 24 год | ✅ Auto memory | +| Крос-проєктність | ✅ Спільна | ❌ Специфічна для проєкту | +| Командний доступ | ✅ Спільні проєкти | ✅ Відстежується через Git | +| Пошук | ✅ Вбудований | ✅ Через `/memory` | +| Редагування | ✅ У чаті | ✅ Пряме редагування файлу | +| Імпорт/Експорт | ✅ Так | ✅ Копіювання/вставлення | +| Постійність | ✅ 24+ год | ✅ Необмежена | + +### Пам'ять у Claude Web/Desktop + +#### Хронологія синтезу пам'яті + +```mermaid +graph LR + A["Day 1: User
Conversations"] -->|24 hours| B["Day 2: Memory
Synthesis"] + B -->|Automatic| C["Memory Updated
Summarized"] + C -->|Loaded in| D["Day 2-N:
New Conversations"] + D -->|Add to| E["Memory"] + E -->|24 hours later| F["Memory Refreshed"] +``` + +**Приклад зведення пам'яті:** + +```markdown +## Claude's Memory of User + +### Professional Background +- Senior full-stack developer with 8 years experience +- Focus on TypeScript/Node.js backends and React frontends +- Active open source contributor +- Interested in AI and machine learning + +### Project Context +- Currently building e-commerce platform +- Tech stack: Node.js, PostgreSQL, React 18, Docker +- Working with team of 5 developers +- Using CI/CD and blue-green deployments + +### Communication Preferences +- Prefers direct, concise explanations +- Likes visual diagrams and examples +- Appreciates code snippets +- Explains business logic in comments + +### Current Goals +- Improve API performance +- Increase test coverage to 90% +- Implement caching strategy +- Document architecture +``` + +## Найкращі практики + +### Рекомендовано — що включати + +- **Будьте конкретними та детальними**: використовуйте чіткі, детальні інструкції замість розпливчастих рекомендацій + - ✅ Добре: "Use 2-space indentation for all JavaScript files" + - ❌ Уникайте: "Follow best practices" + +- **Підтримуйте порядок**: структуруйте файли пам'яті з чіткими Markdown-секціями та заголовками + +- **Використовуйте відповідні рівні ієрархії**: + - **Managed policy**: загальноорганізаційні політики, стандарти безпеки, вимоги відповідності + - **Project memory**: командні стандарти, архітектура, конвенції кодування (комітити в git) + - **User memory**: персональні налаштування, стиль спілкування, вибір інструментів + - **Directory memory**: правила та перевизначення для конкретних модулів + +- **Використовуйте імпорти**: синтаксис `@шлях/до/файлу` для посилання на наявну документацію + - Підтримує до 5 рівнів рекурсивного вкладення + - Уникає дублювання між файлами пам'яті + - Приклад: `See @README.md for project overview` + +- **Документуйте часті команди**: включайте команди, які часто використовуєте, для економії часу + +- **Версіонуйте пам'ять проєкту**: комітьте файли CLAUDE.md рівня проєкту в git на користь команди + +- **Періодично переглядайте**: оновлюйте пам'ять регулярно в міру розвитку проєкту та зміни вимог + +- **Надавайте конкретні приклади**: включайте фрагменти коду та конкретні сценарії + +### Не рекомендовано — чого уникати + +- **Не зберігайте секрети**: ніколи не включайте API-ключі, паролі, токени чи облікові дані + +- **Не включайте конфіденційні дані**: жодних персональних даних, приватної інформації чи комерційних таємниць + +- **Не дублюйте вміст**: використовуйте імпорти (`@шлях`) для посилання на наявну документацію + +- **Не будьте розпливчастими**: уникайте загальних фраз на кшталт "follow best practices" або "write good code" + +- **Не робіть файли занадто довгими**: тримайте окремі файли пам'яті сфокусованими та до 500 рядків + +- **Не переорганізовуйте**: використовуйте ієрархію стратегічно; не створюйте надмірних перевизначень підкаталогів + +- **Не забувайте оновлювати**: застаріла пам'ять може спричинити плутанину та використання застарілих практик + +- **Не перевищуйте ліміти вкладення**: імпорти пам'яті підтримують до 5 рівнів вкладення + +### Поради з управління пам'яттю + +**Оберіть правильний рівень пам'яті:** + +| Випадок використання | Рівень пам'яті | Обґрунтування | +|---------------------|----------------|--------------| +| Корпоративна політика безпеки | Managed Policy | Застосовується до всіх проєктів організації | +| Стайлгайд коду команди | Project | Спільний з командою через git | +| Ваші улюблені ярлики редактора | User | Персональне налаштування, не спільне | +| Стандарти API-модуля | Directory | Специфічно лише для цього модуля | + +**Швидкий воркфлов оновлення:** + +1. Для окремих правил: використовуйте префікс `#` у розмові +2. Для кількох змін: використовуйте `/memory` для відкриття редактора +3. Для початкового налаштування: використовуйте `/init` для створення шаблону + +**Найкращі практики імпорту:** + +```markdown +# Добре: посилання на наявні документи +@README.md +@docs/architecture.md +@package.json + +# Уникайте: копіювання вмісту, що існує деінде +# Замість копіювання вмісту README в CLAUDE.md — просто імпортуйте його +``` + +## Інструкції з встановлення + +### Налаштування пам'яті проєкту + +#### Метод 1: Команда `/init` (рекомендовано) + +Найшвидший спосіб налаштувати пам'ять проєкту: + +1. **Перейдіть у каталог проєкту:** + ```bash + cd /path/to/your/project + ``` + +2. **Виконайте команду init у Claude Code:** + ```bash + /init + ``` + +3. **Claude створить та заповнить CLAUDE.md** шаблонною структурою + +4. **Налаштуйте згенерований файл** відповідно до потреб проєкту + +5. **Закомітьте в git:** + ```bash + git add CLAUDE.md + git commit -m "Initialize project memory with /init" + ``` + +#### Метод 2: Ручне створення + +Якщо ви надаєте перевагу ручному налаштуванню: + +1. **Створіть CLAUDE.md у корені проєкту:** + ```bash + cd /path/to/your/project + touch CLAUDE.md + ``` + +2. **Додайте стандарти проєкту:** + ```bash + cat > CLAUDE.md << 'EOF' + # Project Configuration + + ## Project Overview + - **Name**: Your Project Name + - **Tech Stack**: List your technologies + - **Team Size**: Number of developers + + ## Development Standards + - Your coding standards + - Naming conventions + - Testing requirements + EOF + ``` + +3. **Закомітьте в git:** + ```bash + git add CLAUDE.md + git commit -m "Add project memory configuration" + ``` + +#### Метод 3: Швидкі оновлення з `#` + +Коли CLAUDE.md вже існує, швидко додавайте правила під час розмов: + +```markdown +# Use semantic versioning for all releases + +# Always run tests before committing + +# Prefer composition over inheritance +``` + +Claude запропонує обрати, який файл пам'яті оновити. + +### Налаштування персональної пам'яті + +1. **Створіть каталог ~/.claude:** + ```bash + mkdir -p ~/.claude + ``` + +2. **Створіть персональний CLAUDE.md:** + ```bash + touch ~/.claude/CLAUDE.md + ``` + +3. **Додайте ваші налаштування:** + ```bash + cat > ~/.claude/CLAUDE.md << 'EOF' + # My Development Preferences + + ## About Me + - Experience Level: [Your level] + - Preferred Languages: [Your languages] + - Communication Style: [Your style] + + ## Code Preferences + - [Your preferences] + EOF + ``` + +### Налаштування пам'яті для конкретного каталогу + +1. **Створіть пам'ять для конкретних каталогів:** + ```bash + mkdir -p /path/to/directory/.claude + touch /path/to/directory/CLAUDE.md + ``` + +2. **Додайте правила, специфічні для каталогу:** + ```bash + cat > /path/to/directory/CLAUDE.md << 'EOF' + # [Directory Name] Standards + + This file overrides root CLAUDE.md for this directory. + + ## [Specific Standards] + EOF + ``` + +3. **Закомітьте у систему контролю версій:** + ```bash + git add /path/to/directory/CLAUDE.md + git commit -m "Add [directory] memory configuration" + ``` + +### Перевірка налаштування + +1. **Перевірте розташування пам'яті:** + ```bash + # Пам'ять кореня проєкту + ls -la ./CLAUDE.md + + # Персональна пам'ять + ls -la ~/.claude/CLAUDE.md + ``` + +2. **Claude Code автоматично завантажить** ці файли при запуску сесії + +3. **Протестуйте з Claude Code**, запустивши нову сесію у вашому проєкті + +## Офіційна документація + +Для найактуальнішої інформації зверніться до офіційної документації Claude Code: + +- **[Документація пам'яті](https://code.claude.com/docs/en/memory)** — повний довідник системи пам'яті +- **[Довідник слеш-команд](https://code.claude.com/docs/en/interactive-mode)** — всі вбудовані команди, включаючи `/init` та `/memory` +- **[Довідник CLI](https://code.claude.com/docs/en/cli-reference)** — документація інтерфейсу командного рядка + +### Ключові технічні деталі з офіційної документації + +**Завантаження пам'яті:** + +- Усі файли пам'яті автоматично завантажуються при запуску Claude Code +- Claude проходить вгору від поточного робочого каталогу для виявлення файлів CLAUDE.md +- Файли піддерев виявляються та завантажуються контекстно при доступі до цих каталогів + +**Синтаксис імпорту:** + +- Використовуйте `@шлях/до/файлу` для включення зовнішнього вмісту (наприклад, `@~/.claude/my-project-instructions.md`) +- Підтримуються відносні та абсолютні шляхи +- Рекурсивні імпорти підтримуються з максимальною глибиною 5 +- Перший зовнішній імпорт викликає діалог підтвердження +- Не обробляються всередині code span та code block у Markdown +- Автоматично включає вміст посилань у контекст Claude + +**Пріоритет ієрархії пам'яті:** + +1. Managed Policy (найвищий пріоритет) +2. Managed Drop-ins (`managed-settings.d/`, v2.1.83+) +3. Project Memory +4. Project Rules (`.claude/rules/`) +5. User Memory +6. User-Level Rules (`~/.claude/rules/`) +7. Local Project Memory +8. Auto Memory (найнижчий пріоритет) + +## Посилання на пов'язані концепції + +### Точки інтеграції +- [Протокол MCP](../05-mcp/) — доступ до даних у реальному часі поруч з пам'яттю +- [Слеш-команди](../01-slash-commands/) — ярлики для сесій +- [Навички](../03-skills/) — автоматизовані воркфлови з контекстом пам'яті + +### Пов'язані функції Claude +- [Пам'ять Claude Web](https://claude.ai) — автоматичний синтез +- [Офіційна документація пам'яті](https://code.claude.com/docs/en/memory) — документація Anthropic + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/02-memory/directory-api-CLAUDE.md b/uk/02-memory/directory-api-CLAUDE.md new file mode 100644 index 0000000..f943c70 --- /dev/null +++ b/uk/02-memory/directory-api-CLAUDE.md @@ -0,0 +1,64 @@ +# Стандарти модуля API + +Цей файл перевизначає кореневий CLAUDE.md для всього у /src/api/ + +## Специфічні стандарти API + +### Валідація запитів +- Використовувати Zod для валідації схем +- Завжди валідувати вхідні дані +- Повертати 400 з помилками валідації +- Включати деталі помилок на рівні полів + +### Автентифікація +- Усі ендпоінти вимагають JWT-токен +- Токен у заголовку Authorization +- Токен закінчується через 24 години +- Реалізувати механізм refresh-токенів + +### Формат відповіді + +Усі відповіді мають дотримуватися цієї структури: + +```json +{ + "success": true, + "data": { /* фактичні дані */ }, + "timestamp": "2025-11-06T10:30:00Z", + "version": "1.0" +} +``` + +Відповіді з помилками: +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "Повідомлення для користувача", + "details": { /* помилки полів */ } + }, + "timestamp": "2025-11-06T10:30:00Z" +} +``` + +### Пагінація +- Використовувати пагінацію на основі курсора (не зсуву/offset) +- Включати булеве поле `hasMore` +- Максимальний розмір сторінки: 100 +- Розмір сторінки за замовчуванням: 20 + +### Обмеження частоти запитів (Rate Limiting) +- 1000 запитів на годину для автентифікованих користувачів +- 100 запитів на годину для публічних ендпоінтів +- Повертати 429 при перевищенні +- Включати заголовок retry-after + +### Кешування +- Використовувати Redis для кешування сесій +- Тривалість кешу: 5 хвилин за замовчуванням +- Інвалідувати при операціях запису +- Тегувати ключі кешу типом ресурсу + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/02-memory/personal-CLAUDE.md b/uk/02-memory/personal-CLAUDE.md new file mode 100644 index 0000000..7b42b03 --- /dev/null +++ b/uk/02-memory/personal-CLAUDE.md @@ -0,0 +1,63 @@ +# Мої уподобання розробки + +## Про мене +- **Рівень досвіду**: 8 років full-stack розробки +- **Бажані мови**: TypeScript, Python +- **Стиль комунікації**: Прямий, з прикладами +- **Стиль навчання**: Візуальні діаграми з кодом + +## Уподобання коду + +### Обробка помилок +Я віддаю перевагу явній обробці помилок з блоками try-catch та змістовними повідомленнями. +Уникайте загальних помилок. Завжди логуйте помилки для налагодження. + +### Коментарі +Коментарі для ЧОМУ, а не ЩО. Код має бути самодокументованим. +Коментарі мають пояснювати бізнес-логіку або неочевидні рішення. + +### Тестування +Я віддаю перевагу TDD (розробка через тестування). +Спочатку писати тести, потім реалізацію. +Фокус на поведінці, а не деталях реалізації. + +### Архітектура +Я віддаю перевагу модульному, слабкоповʼязаному дизайну. +Використовувати впровадження залежностей (dependency injection) для тестовності. +Розділення відповідальностей (Controllers, Services, Repositories). + +## Уподобання налагодження +- Використовувати console.log з префіксом: `[DEBUG]` +- Включати контекст: назву функції, відповідні змінні +- Використовувати стеки викликів (stack traces), коли доступні +- Завжди включати мітки часу в журналах + +## Комунікація +- Пояснювати складні концепції діаграмами +- Показувати конкретні приклади перед поясненням теорії +- Включати фрагменти коду до/після +- Підсумовувати ключові моменти наприкінці + +## Організація проєкту +Я організовую проєкти так: +``` +project/ + ├── src/ + │ ├── api/ + │ ├── services/ + │ ├── models/ + │ └── utils/ + ├── tests/ + ├── docs/ + └── docker/ +``` + +## Інструментарій +- **IDE**: VS Code з vim-клавішами +- **Термінал**: Zsh з Oh-My-Zsh +- **Форматування**: Prettier (довжина рядка 100 символів) +- **Лінтер**: ESLint з конфігурацією airbnb +- **Тестовий фреймворк**: Jest з React Testing Library + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/02-memory/project-CLAUDE.md b/uk/02-memory/project-CLAUDE.md new file mode 100644 index 0000000..0e99e33 --- /dev/null +++ b/uk/02-memory/project-CLAUDE.md @@ -0,0 +1,91 @@ +# Конфігурація проєкту + +## Огляд проєкту +- **Назва**: Платформа електронної комерції +- **Технологічний стек**: Node.js, PostgreSQL, React 18, Docker +- **Розмір команди**: 5 розробників +- **Дедлайн**: Q4 2025 + +## Архітектура +@docs/architecture.md +@docs/api-standards.md +@docs/database-schema.md + +## Стандарти розробки + +### Стиль коду +- Використовувати Prettier для форматування +- Використовувати ESLint з конфігурацією airbnb +- Максимальна довжина рядка: 100 символів +- Використовувати відступ 2 пробіли + +### Конвенції іменування +- **Файли**: kebab-case (user-controller.js) +- **Класи**: PascalCase (UserService) +- **Функції/Змінні**: camelCase (getUserById) +- **Константи**: UPPER_SNAKE_CASE (API_BASE_URL) +- **Таблиці БД**: snake_case (user_accounts) + +### Git-процес +- Назви гілок: `feature/description` або `fix/description` +- Повідомлення комітів: дотримуватися conventional commits +- PR обовʼязковий перед злиттям +- Усі CI/CD перевірки мають пройти +- Мінімум 1 затвердження (approval) обовʼязкове + +### Вимоги до тестування +- Мінімум 80% покриття коду +- Усі критичні шляхи мають мати тести +- Використовувати Jest для юніт-тестів +- Використовувати Cypress для E2E-тестів +- Назви тестових файлів: `*.test.ts` або `*.spec.ts` + +### Стандарти API +- Лише RESTful ендпоінти +- JSON запит/відповідь +- Правильно використовувати HTTP-статус-коди +- Версіонування API-ендпоінтів: `/api/v1/` +- Документувати всі ендпоінти з прикладами + +### База даних +- Використовувати міграції для змін схеми +- Ніколи не зашивати облікові дані в код +- Використовувати пул зʼєднань (connection pooling) +- Увімкнути логування запитів у середовищі розробки +- Регулярне резервне копіювання обовʼязкове + +### Деплой +- Деплой на основі Docker +- Оркестрація Kubernetes +- Стратегія blue-green деплою +- Автоматичний відкат при невдачі +- Міграції БД виконуються перед деплоєм + +## Типові команди + +| Команда | Призначення | +|---------|-------------| +| `npm run dev` | Запуск сервера розробки | +| `npm test` | Запуск тестового набору | +| `npm run lint` | Перевірка стилю коду | +| `npm run build` | Збірка для продакшну | +| `npm run migrate` | Запуск міграцій БД | + +## Контакти команди +- Техлід: Sarah Chen (@sarah.chen) +- Продакт-менеджер: Mike Johnson (@mike.j) +- DevOps: Alex Kim (@alex.k) + +## Відомі проблеми та обхідні рішення +- Пул зʼєднань PostgreSQL обмежений до 20 у пікові години +- Обхідне рішення: реалізувати чергу запитів +- Проблеми сумісності Safari 14 з async generators +- Обхідне рішення: використовувати транспілятор Babel + +## Повʼязані проєкти +- Аналітична панель: `/projects/analytics` +- Мобільний додаток: `/projects/mobile` +- Адмін-панель: `/projects/admin` + +--- +**Останнє оновлення**: 9 квітня 2026 From cea0a7d4ef97d030041d52571acdc134bb7215cf Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 22:46:03 +0300 Subject: [PATCH 09/20] feat(uk): translate P3 examples for module 03-skills 6 SKILL.md files + 3 templates translated. Remaining: references/code-smells.md and references/refactoring-catalog.md Ref: luongnv89/claude-howto#63 --- uk/03-skills/README.md | 815 ++++++++++++++++++ uk/03-skills/blog-draft/SKILL.md | 274 ++++++ .../blog-draft/templates/draft-template.md | 67 ++ .../blog-draft/templates/outline-template.md | 97 +++ uk/03-skills/brand-voice/SKILL.md | 72 ++ uk/03-skills/claude-md/SKILL.md | 212 +++++ uk/03-skills/code-review/SKILL.md | 70 ++ uk/03-skills/doc-generator/SKILL.md | 76 ++ uk/03-skills/refactor/SKILL.md | 426 +++++++++ .../refactor/templates/refactoring-plan.md | 284 ++++++ 10 files changed, 2393 insertions(+) create mode 100644 uk/03-skills/README.md create mode 100644 uk/03-skills/blog-draft/SKILL.md create mode 100644 uk/03-skills/blog-draft/templates/draft-template.md create mode 100644 uk/03-skills/blog-draft/templates/outline-template.md create mode 100644 uk/03-skills/brand-voice/SKILL.md create mode 100644 uk/03-skills/claude-md/SKILL.md create mode 100644 uk/03-skills/code-review/SKILL.md create mode 100644 uk/03-skills/doc-generator/SKILL.md create mode 100644 uk/03-skills/refactor/SKILL.md create mode 100644 uk/03-skills/refactor/templates/refactoring-plan.md diff --git a/uk/03-skills/README.md b/uk/03-skills/README.md new file mode 100644 index 0000000..66127bc --- /dev/null +++ b/uk/03-skills/README.md @@ -0,0 +1,815 @@ + + + + + + + Claude How To + + +# Посібник з навичок агента + +Навички агента (Agent Skills) — це повторно використовувані, файлові можливості, які розширюють функціональність Claude. Вони пакують доменну експертизу, воркфлови та найкращі практики в компоненти, що автоматично виявляються, і Claude використовує їх, коли це доречно. + +## Огляд + +**Навички агента** — це модульні можливості, які перетворюють агентів загального призначення на спеціалістів. На відміну від промптів (інструкцій рівня розмови для одноразових завдань), навички завантажуються за потребою і усувають необхідність повторно надавати ті самі рекомендації в кількох розмовах. + +### Ключові переваги + +- **Спеціалізація Claude**: налаштування можливостей для доменних завдань +- **Зменшення повторень**: створити один раз, використовувати автоматично в усіх розмовах +- **Комбінування можливостей**: поєднання навичок для побудови складних воркфловів +- **Масштабування воркфловів**: повторне використання навичок у кількох проєктах і командах +- **Підтримка якості**: вбудовування найкращих практик безпосередньо у воркфлов + +Навички відповідають відкритому стандарту [Agent Skills](https://agentskills.io), який працює з кількома AI-інструментами. Claude Code розширює стандарт додатковими функціями: керування викликом, виконання в субагенті та динамічне впровадження контексту. + +> **Примітка**: Користувацькі слеш-команди об'єднано з навичками. Файли `.claude/commands/` все ще працюють і підтримують ті самі поля фронтматера. Навички рекомендовано для нової розробки. Коли обидва існують за одним шляхом (наприклад, `.claude/commands/review.md` та `.claude/skills/review/SKILL.md`), навичка має пріоритет. + +## Як працюють навички: прогресивне розкриття + +Навички використовують архітектуру **прогресивного розкриття** (progressive disclosure) — Claude завантажує інформацію поетапно за потребою, а не споживає весь контекст одразу. Це забезпечує ефективне управління контекстом із необмеженою масштабованістю. + +### Три рівні завантаження + +```mermaid +graph TB + subgraph "Level 1: Metadata (Always Loaded)" + A["YAML Frontmatter"] + A1["~100 tokens per skill"] + A2["name + description"] + end + + subgraph "Level 2: Instructions (When Triggered)" + B["SKILL.md Body"] + B1["Under 5k tokens"] + B2["Workflows & guidance"] + end + + subgraph "Level 3: Resources (As Needed)" + C["Bundled Files"] + C1["Effectively unlimited"] + C2["Scripts, templates, docs"] + end + + A --> B + B --> C +``` + +| Рівень | Коли завантажується | Вартість токенів | Вміст | +|--------|-------------------|-----------------|-------| +| **Рівень 1: Метадані** | Завжди (при запуску) | ~100 токенів на навичку | `name` та `description` з YAML-фронтматера | +| **Рівень 2: Інструкції** | Коли навичка активована | До 5k токенів | Тіло SKILL.md з інструкціями та рекомендаціями | +| **Рівень 3+: Ресурси** | За потребою | Фактично необмежено | Файли-пакети, що виконуються через bash без завантаження в контекст | + +Це означає, що ви можете встановити багато навичок без штрафу за контекст — Claude лише знає, що кожна навичка існує і коли її використовувати, доки вона фактично не активована. + +## Процес завантаження навички + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude + participant System as System + participant Skill as Skill + + User->>Claude: "Review this code for security issues" + Claude->>System: Check available skills (metadata) + System-->>Claude: Skill descriptions loaded at startup + Claude->>Claude: Match request to skill description + Claude->>Skill: bash: read code-review/SKILL.md + Skill-->>Claude: Instructions loaded into context + Claude->>Claude: Determine: Need templates? + Claude->>Skill: bash: read templates/checklist.md + Skill-->>Claude: Template loaded + Claude->>Claude: Execute skill instructions + Claude->>User: Comprehensive code review +``` + +## Типи та розташування навичок + +| Тип | Розташування | Область дії | Спільний | Найкраще для | +|-----|-------------|-------------|---------|-------------| +| **Enterprise** | Managed settings | Всі користувачі організації | Так | Загальноорганізаційні стандарти | +| **Personal** | `~/.claude/skills//SKILL.md` | Індивідуальний | Ні | Персональні воркфлови | +| **Project** | `.claude/skills//SKILL.md` | Команда | Так (через git) | Командні стандарти | +| **Plugin** | `/skills//SKILL.md` | Де увімкнено | Залежить | В складі плагінів | + +Коли навички мають однакову назву на різних рівнях, вищі пріоритетні розташування перемагають: **enterprise > personal > project**. Навички плагінів використовують простір імен `plugin-name:skill-name`, тому конфлікти неможливі. + +### Автоматичне виявлення + +**Вкладені каталоги**: коли ви працюєте з файлами в підкаталогах, Claude Code автоматично виявляє навички з вкладених каталогів `.claude/skills/`. Наприклад, якщо ви редагуєте файл у `packages/frontend/`, Claude Code також шукає навички в `packages/frontend/.claude/skills/`. Це підтримує конфігурації монорепо, де пакети мають власні навички. + +**Каталоги `--add-dir`**: навички з каталогів, доданих через `--add-dir`, завантажуються автоматично з виявленням змін у реальному часі. Будь-які зміни файлів навичок у цих каталогах набувають чинності негайно без перезапуску Claude Code. + +**Бюджет опису**: описи навичок (метадані рівня 1) обмежені **1% контекстного вікна** (резерв: **8 000 символів**). Якщо встановлено багато навичок, описи можуть бути скорочені. Назви всіх навичок завжди включаються, але описи обрізаються для вписування. Розміщуйте ключовий випадок використання на початку описів. Перевизначте бюджет змінною оточення `SLASH_COMMAND_TOOL_CHAR_BUDGET`. + +## Створення власних навичок + +### Базова структура каталогу + +``` +my-skill/ +├── SKILL.md # Головні інструкції (обов'язковий) +├── template.md # Шаблон для заповнення Claude +├── examples/ +│ └── sample.md # Приклад результату з очікуваним форматом +└── scripts/ + └── validate.sh # Скрипт, який Claude може виконати +``` + +### Формат SKILL.md + +```yaml +--- +name: your-skill-name +description: Brief description of what this Skill does and when to use it +--- + +# Your Skill Name + +## Instructions +Provide clear, step-by-step guidance for Claude. + +## Examples +Show concrete examples of using this Skill. +``` + +### Обов'язкові поля + +- **name**: тільки малі літери, цифри, дефіси (макс. 64 символи). Не може містити "anthropic" або "claude". +- **description**: що навичка робить І коли її використовувати (макс. 1024 символи). Це критично для того, щоб Claude знав, коли активувати навичку. + +### Додаткові поля фронтматера + +```yaml +--- +name: my-skill +description: What this skill does and when to use it +argument-hint: "[filename] [format]" # Підказка для автодоповнення +disable-model-invocation: true # Тільки користувач може викликати +user-invocable: false # Приховати з меню слеш-команд +allowed-tools: Read, Grep, Glob # Обмежити доступ до інструментів +model: opus # Конкретна модель +effort: high # Рівень зусиль (low, medium, high, max) +context: fork # Запуск в ізольованому субагенті +agent: Explore # Тип агента (з context: fork) +shell: bash # Оболонка: bash (за замовч.) або powershell +hooks: # Хуки, обмежені навичкою + PreToolUse: + - matcher: "Bash" + hooks: + - type: command + command: "./scripts/validate.sh" +paths: "src/api/**/*.ts" # Glob-патерни, що обмежують активацію +--- +``` + +| Поле | Опис | +|------|------| +| `name` | Тільки малі літери, цифри, дефіси (макс. 64 символи). Не може містити "anthropic" або "claude". | +| `description` | Що навичка робить І коли її використовувати (макс. 1024 символи). Критично для автоматичного зіставлення. | +| `argument-hint` | Підказка в меню автодоповнення `/` (наприклад, `"[filename] [format]"`). | +| `disable-model-invocation` | `true` = тільки користувач може викликати через `/name`. Claude ніколи не викличе автоматично. | +| `user-invocable` | `false` = приховано з меню `/`. Тільки Claude може викликати автоматично. | +| `allowed-tools` | Список інструментів через кому, які навичка може використовувати без запитів дозволу. | +| `model` | Перевизначення моделі під час активності навички (наприклад, `opus`, `sonnet`). | +| `effort` | Перевизначення рівня зусиль: `low`, `medium`, `high` або `max`. | +| `context` | `fork` для запуску навички у відгалуженому контексті субагента з власним контекстним вікном. | +| `agent` | Тип субагента при `context: fork` (наприклад, `Explore`, `Plan`, `general-purpose`). | +| `shell` | Оболонка для підстановок `!`command`` та скриптів: `bash` (за замовч.) або `powershell`. | +| `hooks` | Хуки, обмежені життєвим циклом цієї навички (той самий формат, що й глобальні хуки). | +| `paths` | Glob-патерни, що обмежують автоактивацію. Рядок через кому або YAML-список. Формат як у правилах для конкретних шляхів. | + +## Типи вмісту навичок + +Навички можуть містити два типи вмісту, кожен для різних цілей: + +### Довідковий вміст + +Додає знання, які Claude застосовує до вашої поточної роботи — конвенції, патерни, стайлгайди, доменні знання. Виконується в контексті вашої розмови. + +```yaml +--- +name: api-conventions +description: API design patterns for this codebase +--- + +When writing API endpoints: +- Use RESTful naming conventions +- Return consistent error formats +- Include request validation +``` + +### Вміст завдань + +Покрокові інструкції для конкретних дій. Часто викликається безпосередньо через `/skill-name`. + +```yaml +--- +name: deploy +description: Deploy the application to production +context: fork +disable-model-invocation: true +--- + +Deploy the application: +1. Run the test suite +2. Build the application +3. Push to the deployment target +``` + +## Керування викликом навичок + +За замовчуванням і ви, і Claude можете викликати будь-яку навичку. Два поля фронтматера контролюють три режими виклику: + +| Фронтматер | Ви можете викликати | Claude може викликати | +|---|---|---| +| (за замовч.) | Так | Так | +| `disable-model-invocation: true` | Так | Ні | +| `user-invocable: false` | Ні | Так | + +**Використовуйте `disable-model-invocation: true`** для воркфловів з побічними ефектами: `/commit`, `/deploy`, `/send-slack-message`. Ви не хочете, щоб Claude вирішив задеплоїти, бо ваш код виглядає готовим. + +**Використовуйте `user-invocable: false`** для фонових знань, які не є дієвими як команда. Навичка `legacy-system-context` пояснює, як працює стара система — корисно для Claude, але не має сенсу як дія для користувачів. + +## Підстановки рядків + +Навички підтримують динамічні значення, які розв'язуються до того, як вміст навички потрапляє до Claude: + +| Змінна | Опис | +|--------|------| +| `$ARGUMENTS` | Всі аргументи, передані при виклику навички | +| `$ARGUMENTS[N]` або `$N` | Доступ до конкретного аргументу за індексом (починаючи з 0) | +| `${CLAUDE_SESSION_ID}` | ID поточної сесії | +| `${CLAUDE_SKILL_DIR}` | Каталог, що містить файл SKILL.md навички | +| `` !`command` `` | Динамічне впровадження контексту — виконує команду оболонки та вставляє результат | + +**Приклад:** + +```yaml +--- +name: fix-issue +description: Fix a GitHub issue +--- + +Fix GitHub issue $ARGUMENTS following our coding standards. +1. Read the issue description +2. Implement the fix +3. Write tests +4. Create a commit +``` + +Виконання `/fix-issue 123` замінює `$ARGUMENTS` на `123`. + +## Впровадження динамічного контексту + +Синтаксис `` !`command` `` виконує команди оболонки до того, як вміст навички відправляється до Claude: + +```yaml +--- +name: pr-summary +description: Summarize changes in a pull request +context: fork +agent: Explore +--- + +## Pull request context +- PR diff: !`gh pr diff` +- PR comments: !`gh pr view --comments` +- Changed files: !`gh pr diff --name-only` + +## Your task +Summarize this pull request... +``` + +Команди виконуються негайно; Claude бачить лише кінцевий результат. За замовчуванням команди виконуються в `bash`. Встановіть `shell: powershell` у фронтматері для використання PowerShell. + +## Запуск навичок у субагентах + +Додайте `context: fork` для запуску навички в ізольованому контексті субагента. Вміст навички стає завданням для виділеного субагента з власним контекстним вікном, зберігаючи основну розмову чистою. + +Поле `agent` вказує тип агента: + +| Тип агента | Найкраще для | +|---|---| +| `Explore` | Дослідження лише для читання, аналіз кодової бази | +| `Plan` | Створення планів реалізації | +| `general-purpose` | Широкі завдання, що потребують усіх інструментів | +| Custom agents | Спеціалізовані агенти, визначені у вашій конфігурації | + +**Приклад фронтматера:** + +```yaml +--- +context: fork +agent: Explore +--- +``` + +**Повний приклад навички:** + +```yaml +--- +name: deep-research +description: Research a topic thoroughly +context: fork +agent: Explore +--- + +Research $ARGUMENTS thoroughly: +1. Find relevant files using Glob and Grep +2. Read and analyze the code +3. Summarize findings with specific file references +``` + +## Практичні приклади + +### Приклад 1: Навичка код-рев'ю + +**Структура каталогу:** + +``` +~/.claude/skills/code-review/ +├── SKILL.md +├── templates/ +│ ├── review-checklist.md +│ └── finding-template.md +└── scripts/ + ├── analyze-metrics.py + └── compare-complexity.py +``` + +**Файл:** `~/.claude/skills/code-review/SKILL.md` + +```yaml +--- +name: code-review-specialist +description: Comprehensive code review with security, performance, and quality analysis. Use when users ask to review code, analyze code quality, evaluate pull requests, or mention code review, security analysis, or performance optimization. +--- + +# Code Review Skill + +This skill provides comprehensive code review capabilities focusing on: + +1. **Security Analysis** + - Authentication/authorization issues + - Data exposure risks + - Injection vulnerabilities + - Cryptographic weaknesses + +2. **Performance Review** + - Algorithm efficiency (Big O analysis) + - Memory optimization + - Database query optimization + - Caching opportunities + +3. **Code Quality** + - SOLID principles + - Design patterns + - Naming conventions + - Test coverage + +4. **Maintainability** + - Code readability + - Function size (should be < 50 lines) + - Cyclomatic complexity + - Type safety + +## Review Template + +For each piece of code reviewed, provide: + +### Summary +- Overall quality assessment (1-5) +- Key findings count +- Recommended priority areas + +### Critical Issues (if any) +- **Issue**: Clear description +- **Location**: File and line number +- **Impact**: Why this matters +- **Severity**: Critical/High/Medium +- **Fix**: Code example + +For detailed checklists, see [templates/review-checklist.md](templates/review-checklist.md). +``` + +### Приклад 2: Навичка візуалізації кодової бази + +Навичка, що генерує інтерактивні HTML-візуалізації: + +**Структура каталогу:** + +``` +~/.claude/skills/codebase-visualizer/ +├── SKILL.md +└── scripts/ + └── visualize.py +``` + +**Файл:** `~/.claude/skills/codebase-visualizer/SKILL.md` + +````yaml +--- +name: codebase-visualizer +description: Generate an interactive collapsible tree visualization of your codebase. Use when exploring a new repo, understanding project structure, or identifying large files. +allowed-tools: Bash(python *) +--- + +# Codebase Visualizer + +Generate an interactive HTML tree view showing your project's file structure. + +## Usage + +Run the visualization script from your project root: + +```bash +python ~/.claude/skills/codebase-visualizer/scripts/visualize.py . +``` + +This creates `codebase-map.html` and opens it in your default browser. + +## What the visualization shows + +- **Collapsible directories**: Click folders to expand/collapse +- **File sizes**: Displayed next to each file +- **Colors**: Different colors for different file types +- **Directory totals**: Shows aggregate size of each folder +```` + +Python-скрипт у пакеті виконує важку роботу, а Claude займається оркестрацією. + +### Приклад 3: Навичка деплою (тільки виклик користувачем) + +```yaml +--- +name: deploy +description: Deploy the application to production +disable-model-invocation: true +allowed-tools: Bash(npm *), Bash(git *) +--- + +Deploy $ARGUMENTS to production: + +1. Run the test suite: `npm test` +2. Build the application: `npm run build` +3. Push to the deployment target +4. Verify the deployment succeeded +5. Report deployment status +``` + +### Приклад 4: Навичка голосу бренду (фонові знання) + +```yaml +--- +name: brand-voice +description: Ensure all communication matches brand voice and tone guidelines. Use when creating marketing copy, customer communications, or public-facing content. +user-invocable: false +--- + +## Tone of Voice +- **Friendly but professional** - approachable without being casual +- **Clear and concise** - avoid jargon +- **Confident** - we know what we're doing +- **Empathetic** - understand user needs + +## Writing Guidelines +- Use "you" when addressing readers +- Use active voice +- Keep sentences under 20 words +- Start with value proposition + +For templates, see [templates/](templates/). +``` + +### Приклад 5: Навичка генератора CLAUDE.md + +```yaml +--- +name: claude-md +description: Create or update CLAUDE.md files following best practices for optimal AI agent onboarding. Use when users mention CLAUDE.md, project documentation, or AI onboarding. +--- + +## Core Principles + +**LLMs are stateless**: CLAUDE.md is the only file automatically included in every conversation. + +### The Golden Rules + +1. **Less is More**: Keep under 300 lines (ideally under 100) +2. **Universal Applicability**: Only include information relevant to EVERY session +3. **Don't Use Claude as a Linter**: Use deterministic tools instead +4. **Never Auto-Generate**: Craft it manually with careful consideration + +## Essential Sections + +- **Project Name**: Brief one-line description +- **Tech Stack**: Primary language, frameworks, database +- **Development Commands**: Install, test, build commands +- **Critical Conventions**: Only non-obvious, high-impact conventions +- **Known Issues / Gotchas**: Things that trip up developers +``` + +### Приклад 6: Навичка рефакторингу зі скриптами + +**Структура каталогу:** + +``` +refactor/ +├── SKILL.md +├── references/ +│ ├── code-smells.md +│ └── refactoring-catalog.md +├── templates/ +│ └── refactoring-plan.md +└── scripts/ + ├── analyze-complexity.py + └── detect-smells.py +``` + +**Файл:** `refactor/SKILL.md` + +```yaml +--- +name: code-refactor +description: Systematic code refactoring based on Martin Fowler's methodology. Use when users ask to refactor code, improve code structure, reduce technical debt, or eliminate code smells. +--- + +# Code Refactoring Skill + +A phased approach emphasizing safe, incremental changes backed by tests. + +## Workflow + +Phase 1: Research & Analysis → Phase 2: Test Coverage Assessment → +Phase 3: Code Smell Identification → Phase 4: Refactoring Plan Creation → +Phase 5: Incremental Implementation → Phase 6: Review & Iteration + +## Core Principles + +1. **Behavior Preservation**: External behavior must remain unchanged +2. **Small Steps**: Make tiny, testable changes +3. **Test-Driven**: Tests are the safety net +4. **Continuous**: Refactoring is ongoing, not a one-time event + +For code smell catalog, see [references/code-smells.md](references/code-smells.md). +For refactoring techniques, see [references/refactoring-catalog.md](references/refactoring-catalog.md). +``` + +## Допоміжні файли + +Навички можуть включати кілька файлів у каталозі крім `SKILL.md`. Ці допоміжні файли (шаблони, приклади, скрипти, довідкові документи) дозволяють тримати головний файл навички сфокусованим, надаючи Claude додаткові ресурси, які він завантажує за потребою. + +``` +my-skill/ +├── SKILL.md # Головні інструкції (обов'язковий, до 500 рядків) +├── templates/ # Шаблони для заповнення Claude +│ └── output-format.md +├── examples/ # Приклади результатів з очікуваним форматом +│ └── sample-output.md +├── references/ # Доменні знання та специфікації +│ └── api-spec.md +└── scripts/ # Скрипти, які Claude може виконати + └── validate.sh +``` + +Рекомендації щодо допоміжних файлів: + +- Тримайте `SKILL.md` до **500 рядків**. Переносіть детальний довідковий матеріал, великі приклади та специфікації в окремі файли. +- Посилайтесь на додаткові файли з `SKILL.md` за допомогою **відносних шляхів** (наприклад, `[API reference](references/api-spec.md)`). +- Допоміжні файли завантажуються на рівні 3 (за потребою), тому вони не споживають контекст, поки Claude фактично їх не прочитає. + +## Управління навичками + +### Перегляд доступних навичок + +Запитайте Claude безпосередньо: +``` +What Skills are available? +``` + +Або перевірте файлову систему: +```bash +# Список персональних навичок +ls ~/.claude/skills/ + +# Список навичок проєкту +ls .claude/skills/ +``` + +### Тестування навички + +Два способи тестування: + +**Дозвольте Claude викликати автоматично**, запитавши щось, що відповідає опису: +``` +Can you help me review this code for security issues? +``` + +**Або викличте безпосередньо** за назвою навички: +``` +/code-review src/auth/login.ts +``` + +### Оновлення навички + +Редагуйте файл `SKILL.md` безпосередньо. Зміни набувають чинності при наступному запуску Claude Code. + +```bash +# Персональна навичка +code ~/.claude/skills/my-skill/SKILL.md + +# Навичка проєкту +code .claude/skills/my-skill/SKILL.md +``` + +### Обмеження доступу Claude до навичок + +Три способи контролювати, які навички Claude може викликати: + +**Вимкнути всі навички** в `/permissions`: +``` +# Додати до правил заборони: +Skill +``` + +**Дозволити або заборонити конкретні навички**: +``` +# Дозволити лише конкретні навички +Skill(commit) +Skill(review-pr *) + +# Заборонити конкретні навички +Skill(deploy *) +``` + +**Приховати окремі навички**, додавши `disable-model-invocation: true` до їхнього фронтматера. + +## Найкращі практики + +### 1. Робіть описи конкретними + +- **Погано (розпливчасто)**: "Helps with documents" +- **Добре (конкретно)**: "Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction." + +### 2. Тримайте навички сфокусованими + +- Одна навичка = одна можливість +- ✅ "PDF form filling" +- ❌ "Document processing" (занадто широко) + +### 3. Включайте тригерні терміни + +Додавайте ключові слова в описи, що відповідають запитам користувачів: +```yaml +description: Analyze Excel spreadsheets, generate pivot tables, create charts. Use when working with Excel files, spreadsheets, or .xlsx files. +``` + +### 4. Тримайте SKILL.md до 500 рядків + +Переносіть детальний довідковий матеріал в окремі файли, які Claude завантажує за потребою. + +### 5. Посилайтесь на допоміжні файли + +```markdown +## Additional resources + +- For complete API details, see [reference.md](reference.md) +- For usage examples, see [examples.md](examples.md) +``` + +### Рекомендовано + +- Використовуйте зрозумілі, описові назви +- Включайте вичерпні інструкції +- Додавайте конкретні приклади +- Пакуйте пов'язані скрипти та шаблони +- Тестуйте з реальними сценаріями +- Документуйте залежності + +### Не рекомендовано + +- Не створюйте навички для одноразових завдань +- Не дублюйте наявну функціональність +- Не робіть навички занадто широкими +- Не пропускайте поле description +- Не встановлюйте навички з ненадійних джерел без аудиту + +## Усунення несправностей + +### Короткий довідник + +| Проблема | Рішення | +|----------|---------| +| Claude не використовує навичку | Зробіть опис конкретнішим з тригерними термінами | +| Файл навички не знайдено | Перевірте шлях: `~/.claude/skills/name/SKILL.md` | +| Помилки YAML | Перевірте маркери `---`, відступи, відсутність табів | +| Конфлікт навичок | Використовуйте різні тригерні терміни в описах | +| Скрипти не запускаються | Перевірте дозволи: `chmod +x scripts/*.py` | +| Claude не бачить всі навички | Занадто багато навичок; перевірте `/context` на попередження | + +### Навичка не спрацьовує + +Якщо Claude не використовує навичку, коли очікується: + +1. Перевірте, що опис містить ключові слова, які користувачі природно вживають +2. Переконайтесь, що навичка відображається при запиті "What skills are available?" +3. Спробуйте переформулювати запит відповідно до опису +4. Викличте безпосередньо через `/skill-name` для тестування + +### Навичка спрацьовує занадто часто + +Якщо Claude використовує навичку, коли ви цього не хочете: + +1. Зробіть опис конкретнішим +2. Додайте `disable-model-invocation: true` для виклику лише вручну + +### Claude не бачить усі навички + +Описи навичок завантажуються з лімітом **1% контекстного вікна** (резерв: **8 000 символів**). Кожен запис обмежений 250 символами незалежно від бюджету. Запустіть `/context`, щоб перевірити попередження про виключені навички. Перевизначте бюджет змінною оточення `SLASH_COMMAND_TOOL_CHAR_BUDGET`. + +## Питання безпеки + +**Використовуйте навички лише з надійних джерел.** Навички надають Claude можливості через інструкції та код — шкідлива навичка може направити Claude на виклик інструментів або виконання коду небезпечними способами. + +**Ключові питання безпеки:** + +- **Ретельний аудит**: перевіряйте всі файли в каталозі навички +- **Зовнішні джерела ризиковані**: навички, що завантажують із зовнішніх URL, можуть бути скомпрометовані +- **Зловживання інструментами**: шкідливі навички можуть викликати інструменти небезпечними способами +- **Ставтесь як до встановлення ПЗ**: використовуйте навички лише з надійних джерел + +## Навички vs інші функції + +| Функція | Виклик | Найкраще для | +|---------|--------|-------------| +| **Навички** | Авто або `/name` | Повторно використовувана експертиза, воркфлови | +| **Слеш-команди** | Користувач через `/name` | Швидкі ярлики (об'єднано з навичками) | +| **Субагенти** | Автоделегування | Ізольоване виконання завдань | +| **Пам'ять (CLAUDE.md)** | Завжди завантажена | Постійний контекст проєкту | +| **MCP** | У реальному часі | Доступ до зовнішніх даних/сервісів | +| **Хуки** | За подіями | Автоматизовані побічні ефекти | + +## Вбудовані навички + +Claude Code постачається з кількома вбудованими навичками, доступними без встановлення: + +| Навичка | Опис | +|---------|------| +| `/simplify` | Перевірка змінених файлів на повторне використання, якість та ефективність; запускає 3 паралельних агенти рев'ю | +| `/batch ` | Оркестрація масштабних паралельних змін по кодовій базі з використанням git worktrees | +| `/debug [description]` | Усунення несправностей поточної сесії через читання журналу налагодження | +| `/loop [interval] ` | Циклічне виконання промпта з інтервалом (наприклад, `/loop 5m check the deploy`) | +| `/claude-api` | Завантаження довідника Claude API/SDK; автоактивується при імпортах `anthropic`/`@anthropic-ai/sdk` | + +Ці навички доступні одразу і не потребують встановлення чи конфігурації. Вони використовують той самий формат SKILL.md, що й власні навички. + +## Поширення навичок + +### Навички проєкту (командне поширення) + +1. Створіть навичку в `.claude/skills/` +2. Закомітьте в git +3. Члени команди витягують зміни — навички доступні одразу + +### Персональні навички + +```bash +# Копіювання в персональний каталог +cp -r my-skill ~/.claude/skills/ + +# Зробити скрипти виконуваними +chmod +x ~/.claude/skills/my-skill/scripts/*.py +``` + +### Дистрибуція через плагіни + +Пакуйте навички в каталог `skills/` плагіна для ширшої дистрибуції. + +## Далі: колекція навичок та менеджер навичок + +Коли ви починаєте серйозно створювати навички, дві речі стають необхідними: бібліотека перевірених навичок та інструмент для їх управління. + +**[luongnv89/skills](https://github.com/luongnv89/skills)** — колекція навичок, які автор використовує щодня майже у всіх проєктах. Серед цікавих: `logo-designer` (генерація логотипів проєктів на льоту) та `ollama-optimizer` (налаштування продуктивності локальних LLM під ваше обладнання). Хороша відправна точка для готових до використання навичок. + +**[luongnv89/asm](https://github.com/luongnv89/asm)** — Agent Skill Manager. Керує розробкою навичок, виявленням дублікатів та тестуванням. Команда `asm link` дозволяє тестувати навичку в будь-якому проєкті без копіювання файлів — це необхідно, коли навичок більше кількох. + +## Додаткові ресурси + +- [Офіційна документація навичок](https://code.claude.com/docs/en/skills) +- [Блог про архітектуру Agent Skills](https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills) +- [Репозиторій навичок](https://github.com/luongnv89/skills) — колекція готових навичок +- [Посібник слеш-команд](../01-slash-commands/) — ярлики, ініційовані користувачем +- [Посібник субагентів](../04-subagents/) — делеговані AI-агенти +- [Посібник з пам'яті](../02-memory/) — постійний контекст +- [MCP (Model Context Protocol)](../05-mcp/) — зовнішні дані в реальному часі +- [Посібник хуків](../06-hooks/) — автоматизація за подіями + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/03-skills/blog-draft/SKILL.md b/uk/03-skills/blog-draft/SKILL.md new file mode 100644 index 0000000..71c5a6b --- /dev/null +++ b/uk/03-skills/blog-draft/SKILL.md @@ -0,0 +1,274 @@ +--- +name: blog-draft +description: Створення чернетки блог-посту з ідей та ресурсів. Використовуйте, коли користувачі хочуть написати блог-пост, створити контент з дослідження або підготувати статтю. Проводить через дослідження, мозковий штурм, складання плану та ітеративне написання з контролем версій. +--- + +## Введення користувача + +```text +$ARGUMENTS +``` + +Ви **ПОВИННІ** врахувати введення користувача перед продовженням. Користувач має надати: +- **Ідея/Тема**: Основна концепція або тематика блог-посту +- **Ресурси**: URL, файли або посилання на дослідження (необовʼязково, але рекомендовано) +- **Цільова аудиторія**: Для кого блог-пост (необовʼязково) +- **Тон/Стиль**: Формальний, невимушений, технічний тощо (необовʼязково) + +**ВАЖЛИВО**: Якщо користувач запитує оновлення **існуючого блог-посту**, пропустіть кроки 0-8 і починайте безпосередньо з **Кроку 9**. Спочатку прочитайте існуючий файл(и) чернетки, потім продовжуйте з процесом ітерації. + +## Потік виконання + +Виконуйте ці кроки послідовно. **Не пропускайте кроки та не продовжуйте без затвердження користувача, де це зазначено.** + +### Крок 0: Створення папки проєкту + +1. Згенерувати назву папки у форматі: `YYYY-MM-DD-short-topic-name` + - Використати сьогоднішню дату + - Створити короткий, URL-дружній slug з теми (малі літери, дефіси, макс. 5 слів) + +2. Створити структуру папок: + ``` + blog-posts/ + └── YYYY-MM-DD-short-topic-name/ + └── resources/ + ``` + +3. Підтвердити створення папки з користувачем перед продовженням. + +### Крок 1: Дослідження та збір ресурсів + +1. Створити підпапку `resources/` у каталозі блог-посту + +2. Для кожного наданого ресурсу: + - **URL-адреси**: Отримати та зберегти ключову інформацію до `resources/` як markdown-файли + - **Файли**: Прочитати та підсумувати в `resources/` + - **Теми**: Використати веб-пошук для збору актуальної інформації + +3. Для кожного ресурсу створити файл резюме в `resources/`: + - `resources/source-1-[short-name].md` + - `resources/source-2-[short-name].md` + - тощо + +4. Кожне резюме має включати: + ```markdown + # Джерело: [Назва/URL] + + ## Ключові тези + - Теза 1 + - Теза 2 + + ## Релевантні цитати/дані + - Цитата або статистика 1 + - Цитата або статистика 2 + + ## Як це стосується теми + Короткий опис релевантності + ``` + +5. Представити резюме дослідження користувачу. + +### Крок 2: Мозковий штурм та уточнення + +1. На основі ідеї та досліджених ресурсів представити: + - **Основні теми**, виявлені з дослідження + - **Потенційні ракурси** для блог-посту + - **Ключові тези**, які слід розкрити + - **Прогалини** в інформації, що потребують уточнення + +2. Поставити уточнюючі запитання: + - Який головний висновок ви хочете донести до читачів? + - Чи є конкретні тези з дослідження, які хочете виділити? + - Яка цільова довжина? (коротка: 500-800 слів, середня: 1000-1500, довга: 2000+) + - Щось хочете виключити? + +3. **Чекати відповідей користувача перед продовженням.** + +### Крок 3: Запропонувати план + +1. Створити структурований план, що включає: + + ```markdown + # План блог-посту: [Назва] + + ## Метаінформація + - **Цільова аудиторія**: [хто] + - **Тон**: [стиль] + - **Цільова довжина**: [кількість слів] + - **Головний висновок**: [ключове повідомлення] + + ## Запропонована структура + + ### Зачіпка/Вступ + - Ідея вступної зачіпки + - Встановлення контексту + - Теза + + ### Розділ 1: [Назва] + - Ключова теза A + - Ключова теза B + - Підтверджуючі докази з [джерела] + + ### Розділ 2: [Назва] + - Ключова теза A + - Ключова теза B + + [Продовжити для всіх розділів...] + + ### Висновок + - Резюме ключових тез + - Заклик до дії або завершальна думка + + ## Джерела для цитування + - Джерело 1 + - Джерело 2 + ``` + +2. Представити план користувачу та **запитати затвердження або модифікації**. + +### Крок 4: Зберегти затверджений план + +1. Після затвердження плану користувачем зберегти його як `OUTLINE.md` у папці блог-посту. + +2. Підтвердити збереження плану. + +### Крок 5: Закомітити план (якщо в git-репо) + +1. Перевірити, чи поточний каталог є git-репозиторієм. + +2. Якщо так: + - Додати нові файли до індексу: папку блог-посту, ресурси та OUTLINE.md + - Створити коміт з повідомленням: `docs: Add outline for blog post - [topic-name]` + - Відправити на віддалений сервер + +3. Якщо не git-репо, пропустити цей крок та повідомити користувача. + +### Крок 6: Написати чернетку + +1. На основі затвердженого плану написати повну чернетку блог-посту. + +2. Точно дотримуватися структури з OUTLINE.md. + +3. Включити: + - Захопливий вступ із зачіпкою + - Чіткі заголовки розділів + - Підтверджуючі докази та приклади з дослідження + - Плавні переходи між розділами + - Сильний висновок з головною тезою + - **Цитування**: Усі порівняння, статистика, дані та фактичні твердження ПОВИННІ цитувати оригінальне джерело + +4. Зберегти чернетку як `draft-v0.1.md` у папці блог-посту. + +5. Формат: + ```markdown + # [Назва блог-посту] + + *[Необовʼязково: підзаголовок або слоган]* + + [Повний вміст з інлайн-цитатами...] + + --- + + ## Список джерел + - [1] Назва джерела 1 - URL або цитата + - [2] Назва джерела 2 - URL або цитата + - [3] Назва джерела 3 - URL або цитата + ``` + +6. **Вимоги до цитування**: + - Кожна точка даних, статистика або порівняння ПОВИННІ мати інлайн-цитату + - Використовуйте нумеровані посилання [1], [2] тощо, або іменовані цитати [Назва джерела] + - Звʼязуйте цитати з розділом Список джерел наприкінці + - Приклад: «Дослідження показують, що 65% розробників віддають перевагу TypeScript [1]» + - Приклад: «React перевершує Vue за швидкістю рендерингу на 20% [React Benchmarks 2024]» + +### Крок 7: Закомітити чернетку (якщо в git-репо) + +1. Перевірити, чи в git-репозиторії. + +2. Якщо так: + - Додати файл чернетки до індексу + - Створити коміт з повідомленням: `docs: Add draft v0.1 for blog post - [topic-name]` + - Відправити на віддалений сервер + +3. Якщо не git-репо, пропустити та повідомити користувача. + +### Крок 8: Представити чернетку для перегляду + +1. Представити вміст чернетки користувачу. + +2. Запитати зворотний звʼязок: + - Загальне враження? + - Розділи, що потребують розширення або скорочення? + - Потрібні корекції тону? + - Відсутня інформація? + - Конкретні правки або переписування? + +3. **Чекати відповіді користувача.** + +### Крок 9: Ітерація або фіналізація + +**Якщо користувач запитує зміни:** +1. Зафіксувати всі запитані модифікації +2. Повернутися до Кроку 6 з такими змінами: + - Збільшити номер версії (v0.2, v0.3 тощо) + - Врахувати всі зауваження + - Зберегти як `draft-v[X.Y].md` + - Повторити Кроки 7-8 + +**Якщо користувач затверджує:** +1. Підтвердити фінальну версію чернетки +2. За бажанням перейменувати на `final.md` +3. Підсумувати процес створення блог-посту: + - Загальна кількість створених версій + - Ключові зміни між версіями + - Фінальна кількість слів + - Створені файли + +## Відстеження версій + +Усі чернетки зберігаються з інкрементальним версіонуванням: +- `draft-v0.1.md` — початкова чернетка +- `draft-v0.2.md` — після першого раунду зауважень +- `draft-v0.3.md` — після другого раунду зауважень +- тощо + +Це дозволяє відстежувати еволюцію блог-посту та повертатися до попередніх версій за потреби. + +## Структура вихідних файлів + +``` +blog-posts/ +└── YYYY-MM-DD-topic-name/ + ├── resources/ + │ ├── source-1-name.md + │ ├── source-2-name.md + │ └── ... + ├── OUTLINE.md + ├── draft-v0.1.md + ├── draft-v0.2.md (якщо ітерації) + └── draft-v0.3.md (якщо більше ітерацій) +``` + +## Поради щодо якості + +- **Зачіпка**: Починайте з питання, дивовижного факту або знайомого сценарію +- **Потік**: Кожен абзац має зʼєднуватися з наступним +- **Докази**: Підтверджуйте твердження даними з дослідження +- **Цитування**: ЗАВЖДИ цитуйте джерела для: + - Усіх статистик та даних (напр., «За даними [Джерело], 75%...») + - Порівнянь між продуктами, сервісами або підходами (напр., «X працює у 2 рази швидше за Y [Джерело]») + - Фактичних тверджень про ринкові тенденції, результати досліджень або бенчмарки + - Використовуйте інлайн-цитати у форматі: [Назва джерела] або [Автор, Рік] +- **Голос**: Підтримуйте послідовний тон протягом усього тексту +- **Довжина**: Дотримуйтесь цільової кількості слів +- **Читабельність**: Використовуйте короткі абзаци, маркери де доречно +- **CTA**: Завершуйте чітким закликом до дії або питанням, що провокує думки + +## Примітки + +- Завжди чекайте затвердження користувача у зазначених контрольних точках +- Зберігайте всі версії чернеток для історії +- Використовуйте веб-пошук для актуальної інформації, коли надані URL +- Якщо ресурсів недостатньо, попросіть користувача надати більше або запропонуйте додаткове дослідження +- Адаптуйте тон відповідно до цільової аудиторії (технічна, загальна, бізнес тощо) diff --git a/uk/03-skills/blog-draft/templates/draft-template.md b/uk/03-skills/blog-draft/templates/draft-template.md new file mode 100644 index 0000000..c03a5f9 --- /dev/null +++ b/uk/03-skills/blog-draft/templates/draft-template.md @@ -0,0 +1,67 @@ +# [Назва блог-посту] + +*[Підзаголовок або слоган — необовʼязково]* + +**[Імʼя автора]** | [Дата] + +--- + +[Вступна зачіпка — одразу захопити увагу] + +[Контекст та передісторія — чому це важливо] + +[Теза — що розкриє цей пост] + +--- + +## [Назва розділу 1] + +[Вміст розділу з чіткою, захопливою прозою] + +[Включити докази, приклади або дані для підтримки тез] + +> «Релевантна цитата з дослідження» — Джерело + +[Перехід до наступного розділу] + +--- + +## [Назва розділу 2] + +[Продовження основного контенту] + +**Ключовий висновок:** [Виділити важливі тези жирним або у виносках] + +[Ще підтверджуючий контент] + +--- + +## [Назва розділу 3] + +[Додаткові розділи за потреби] + +### Підрозділ (за потреби) + +[Вміст підрозділу] + +--- + +## Висновок + +[Підсумувати розкриті ключові тези] + +[Підкріпити головний висновок] + +[Заклик до дії або завершальне твердження, що провокує думки] + +--- + +## Список джерел + +1. [Назва джерела](#) +2. [Назва джерела](#) +3. [Назва джерела](#) + +--- + +*[Необовʼязково: біографія автора або пропозиція повʼязаних постів]* diff --git a/uk/03-skills/blog-draft/templates/outline-template.md b/uk/03-skills/blog-draft/templates/outline-template.md new file mode 100644 index 0000000..5660b01 --- /dev/null +++ b/uk/03-skills/blog-draft/templates/outline-template.md @@ -0,0 +1,97 @@ +# План блог-посту: [Назва] + +## Метаінформація + +| Атрибут | Значення | +|---------|----------| +| **Цільова аудиторія** | [Для кого це?] | +| **Тон** | [Формальний/Невимушений/Технічний/Розмовний] | +| **Цільова довжина** | [Діапазон кількості слів] | +| **Головний висновок** | [Одне речення: що мають запамʼятати читачі?] | +| **Ключові слова** | [SEO-ключові слова, якщо релевантно] | + +--- + +## Запропонована структура + +### 1. Вступ / Зачіпка + +**Варіанти вступної зачіпки:** +- [ ] Питання, що резонує з читачем +- [ ] Вражаюча статистика або факт +- [ ] Коротка історія або сценарій +- [ ] Сміливе твердження + +**Встановлення контексту:** +- Необхідна передісторія +- Чому ця тема важлива зараз + +**Теза:** +- Чітке твердження про те, що розкриє пост + +--- + +### 2. [Назва розділу] + +**Ключові тези:** +- Теза A: [опис] +- Теза B: [опис] + +**Підтверджуючі докази:** +- З [джерела]: [релевантні дані/цитата] + +**Перехід до наступного розділу:** +- [Як це повʼязується з наступним] + +--- + +### 3. [Назва розділу] + +**Ключові тези:** +- Теза A: [опис] +- Теза B: [опис] + +**Підтверджуючі докази:** +- З [джерела]: [релевантні дані/цитата] + +**Перехід до наступного розділу:** +- [Як це повʼязується з наступним] + +--- + +### 4. [Назва розділу] (додайте більше розділів за потреби) + +**Ключові тези:** +- Теза A: [опис] +- Теза B: [опис] + +**Підтверджуючі докази:** +- З [джерела]: [релевантні дані/цитата] + +--- + +### 5. Висновок + +**Резюме ключових тез:** +- Повторення тези 1 +- Повторення тези 2 +- Повторення тези 3 + +**Завершальна думка / Заклик до дії:** +- [Що мають зробити або обміркувати читачі далі?] + +--- + +## Джерела для цитування + +1. [Назва джерела](#) — використано для: [яка інформація] +2. [Назва джерела](#) — використано для: [яка інформація] +3. [Назва джерела](#) — використано для: [яка інформація] + +--- + +## Примітки для написання + +- [Будь-які конкретні вимоги або обмеження] +- [Що наголосити] +- [Чого уникати] diff --git a/uk/03-skills/brand-voice/SKILL.md b/uk/03-skills/brand-voice/SKILL.md new file mode 100644 index 0000000..b3e2cde --- /dev/null +++ b/uk/03-skills/brand-voice/SKILL.md @@ -0,0 +1,72 @@ +--- +name: brand-voice-consistency +description: Забезпечення відповідності всіх комунікацій голосу та тону бренду. Використовуйте при створенні маркетингових текстів, клієнтських комунікацій, публічного контенту, або коли користувачі згадують голос бренду, тон чи стиль написання. +--- + +# Навичка голосу бренду + +## Огляд +Ця навичка забезпечує послідовність голосу бренду, тону та повідомлень у всіх комунікаціях. + +## Ідентичність бренду + +### Місія +Допомогти командам автоматизувати робочі процеси розробки за допомогою AI + +### Цінності +- **Простота**: Робити складне простим +- **Надійність**: Непохитне виконання +- **Розширення можливостей**: Дати простір людській креативності + +### Тон голосу +- **Дружній, але професійний** — доступний, але не панібратський +- **Зрозумілий і лаконічний** — уникати жаргону, пояснювати технічні концепції просто +- **Впевнений** — ми знаємо, що робимо +- **Емпатичний** — розуміємо потреби та болі користувачів + +## Рекомендації щодо написання + +### Рекомендовано ✅ +- Використовуйте «ви» при зверненні до читачів +- Використовуйте активний стан: «Claude генерує звіти», а не «Звіти генеруються Claude» +- Починайте з ціннісної пропозиції +- Використовуйте конкретні приклади +- Тримайте речення до 20 слів +- Використовуйте списки для ясності +- Включайте заклики до дії + +### Не рекомендовано ❌ +- Не використовуйте корпоративний жаргон +- Не будьте поблажливими та не надмірно спрощуйте +- Не використовуйте «ми вважаємо» або «ми думаємо» +- Не використовуйте ВСІ ВЕЛИКІ ЛІТЕРИ, крім виділення +- Не створюйте стіни тексту +- Не припускайте наявність технічних знань + +## Словник + +### ✅ Бажані терміни +- Claude (не «AI Claude») +- Генерація коду (не «автокодування») +- Агент (не «бот») +- Оптимізувати (не «революціонізувати») +- Інтегрувати (не «синергізувати») + +### ❌ Уникати +- «Передовий» (заїжджено) +- «Проривний» (розмито) +- «Левериджити» (корпоративний жаргон) +- «Утилізувати» (використовуйте «використовувати») +- «Зміна парадигми» (незрозуміло) + +## Приклади + +### ✅ Вдалий приклад +«Claude автоматизує ваш процес код-рев'ю. Замість ручної перевірки кожного PR, Claude перевіряє безпеку, продуктивність та якість — заощаджуючи вашій команді години щотижня.» + +Чому працює: Зрозуміла цінність, конкретні переваги, орієнтація на дію + +### ❌ Невдалий приклад +«Claude левериджить передовий AI для надання комплексних рішень розробки програмного забезпечення.» + +Чому не працює: Розмито, корпоративний жаргон, немає конкретної цінності diff --git a/uk/03-skills/claude-md/SKILL.md b/uk/03-skills/claude-md/SKILL.md new file mode 100644 index 0000000..6e4b8b8 --- /dev/null +++ b/uk/03-skills/claude-md/SKILL.md @@ -0,0 +1,212 @@ +--- +name: claude-md +description: Створення або оновлення файлів CLAUDE.md відповідно до найкращих практик для оптимального онбордингу AI-агента +--- + +## Введення користувача + +```text +$ARGUMENTS +``` + +Ви **ПОВИННІ** врахувати введення користувача перед продовженням (якщо не порожнє). Користувач може вказати: +- `create` — створити новий CLAUDE.md з нуля +- `update` — покращити існуючий CLAUDE.md +- `audit` — проаналізувати та звітувати про якість поточного CLAUDE.md +- Конкретний шлях для створення/оновлення (напр., `src/api/CLAUDE.md` для інструкцій, специфічних для каталогу) + +## Основні принципи + +**LLM не мають стану**: CLAUDE.md — єдиний файл, що автоматично включається в кожну розмову. Він слугує головним документом онбордингу AI-агентів у вашу кодову базу. + +### Золоті правила + +1. **Менше — краще**: Найсучасніші LLM можуть дотримуватись ~150-200 інструкцій. Системний промпт Claude Code вже використовує ~50. Тримайте CLAUDE.md зосередженим та лаконічним. + +2. **Універсальна застосовність**: Включайте лише інформацію, релевантну для КОЖНОЇ сесії. Інструкції для конкретних завдань належать до окремих файлів. + +3. **Не використовуйте Claude як лінтер**: Рекомендації зі стилю роздувають контекст та погіршують дотримання інструкцій. Використовуйте натомість детерміністичні інструменти (prettier, eslint тощо). + +4. **Ніколи не генеруйте автоматично**: CLAUDE.md — найвпливовіша точка AI-системи. Створюйте його вручну з ретельним обмірковуванням. + +## Потік виконання + +### 1. Аналіз проєкту + +Спочатку проаналізуйте поточний стан проєкту: + +1. Перевірити наявні файли CLAUDE.md: + - Кореневий рівень: `./CLAUDE.md` або `.claude/CLAUDE.md` + - Специфічні для каталогу: `**/CLAUDE.md` + - Глобальний конфіг користувача: `~/.claude/CLAUDE.md` + +2. Визначити структуру проєкту: + - Технологічний стек (мови, фреймворки) + - Тип проєкту (монорепо, окремий додаток, бібліотека) + - Інструменти розробки (пакетний менеджер, система збірки, тест-раннер) + +3. Переглянути існуючу документацію: + - README.md + - CONTRIBUTING.md + - package.json, pyproject.toml, Cargo.toml тощо + +### 2. Стратегія контенту (ЩО, ЧОМУ, ЯК) + +Структуруйте CLAUDE.md навколо трьох вимірів: + +#### ЩО — Технологія та структура +- Огляд технологічного стеку +- Організація проєкту (особливо важливо для монорепо) +- Ключові каталоги та їхнє призначення + +#### ЧОМУ — Призначення та контекст +- Що робить проєкт +- Чому були прийняті певні архітектурні рішення +- За що відповідає кожен основний компонент + +#### ЯК — Робочий процес та конвенції +- Робочий процес розробки (bun vs node, pip vs uv тощо) +- Процедури та команди тестування +- Методи верифікації та збірки +- Критичні «підводні камені» або неочевидні вимоги + +### 3. Стратегія поступового розкриття + +Для великих проєктів рекомендуйте створити папку `agent_docs/`: + +``` +agent_docs/ + |- building_the_project.md + |- running_tests.md + |- code_conventions.md + |- architecture_decisions.md +``` + +У CLAUDE.md посилайтесь на ці файли інструкціями: +```markdown +For detailed build instructions, refer to `agent_docs/building_the_project.md` +``` + +**Важливо**: Використовуйте посилання `файл:рядок` замість фрагментів коду, щоб уникнути застарілого контексту. + +### 4. Обмеження якості + +При створенні або оновленні CLAUDE.md: + +1. **Цільова довжина**: Менше 300 рядків (ідеально — менше 100) +2. **Без правил стилю**: Видалити будь-які інструкції лінтингу/форматування +3. **Без інструкцій для конкретних завдань**: Перемістити до окремих файлів +4. **Без фрагментів коду**: Використовувати посилання на файли замість цього +5. **Без надлишкової інформації**: Не повторювати те, що є в package.json або README + +### 5. Обовʼязкові секції + +Добре структурований CLAUDE.md має включати: + +```markdown +# Назва проєкту + +Короткий однорядковий опис. + +## Технологічний стек +- Основна мова та версія +- Ключові фреймворки/бібліотеки +- База даних/сховище (якщо є) + +## Структура проєкту +[Лише для монорепо або складних структур] +- `apps/` - Точки входу додатків +- `packages/` - Спільні бібліотеки + +## Команди розробки +- Встановлення: `команда` +- Тестування: `команда` +- Збірка: `команда` + +## Критичні конвенції +[Лише неочевидні, високовпливові конвенції] +- Конвенція 1 з коротким поясненням +- Конвенція 2 з коротким поясненням + +## Відомі проблеми / Підводні камені +[Речі, що постійно створюють труднощі розробникам] +- Проблема 1 +- Проблема 2 +``` + +### 6. Антипатерни, яких слід уникати + +**НЕ включайте:** +- Рекомендації зі стилю коду (використовуйте лінтери) +- Документацію щодо використання Claude +- Довгі пояснення очевидних патернів +- Скопійовані приклади коду +- Загальні найкращі практики («пишіть чистий код») +- Інструкції для конкретних завдань +- Автозгенерований контент +- Розлогі списки TODO + +### 7. Контрольний список валідації + +Перед фіналізацією перевірте: + +- [ ] Менше 300 рядків (бажано менше 100) +- [ ] Кожен рядок застосовний до ВСІХ сесій +- [ ] Без правил стилю/форматування +- [ ] Без фрагментів коду (використані посилання на файли) +- [ ] Команди перевірені на працездатність +- [ ] Поступове розкриття використано для складних проєктів +- [ ] Критичні підводні камені задокументовані +- [ ] Немає надлишковості з README.md + +## Формат виводу + +### Для `create` або за замовчуванням: + +1. Проаналізувати проєкт +2. Створити чернетку CLAUDE.md за структурою вище +3. Представити чернетку для перегляду +4. Записати у відповідне місце після затвердження + +### Для `update`: + +1. Прочитати існуючий CLAUDE.md +2. Аудит за найкращими практиками +3. Визначити: + - Контент для видалення (правила стилю, фрагменти коду, специфічне для завдань) + - Контент для скорочення + - Відсутню важливу інформацію +4. Представити зміни для перегляду +5. Застосувати зміни після затвердження + +### Для `audit`: + +1. Прочитати існуючий CLAUDE.md +2. Згенерувати звіт з: + - Поточна кількість рядків vs ціль + - Відсоток універсально застосовного контенту + - Список знайдених антипатернів + - Рекомендації для покращення +3. НЕ модифікувати файл, лише звітувати + +## Обробка AGENTS.md + +Якщо користувач запитує створення/оновлення AGENTS.md: + +AGENTS.md використовується для визначення спеціалізованої поведінки агентів. На відміну від CLAUDE.md (який для контексту проєкту), AGENTS.md визначає: +- Кастомні ролі та можливості агентів +- Інструкції та обмеження для конкретних агентів +- Визначення робочих процесів для мультиагентних сценаріїв + +Застосовуйте аналогічні принципи: +- Тримайте зосередженим та лаконічним +- Використовуйте поступове розкриття +- Посилайтесь на зовнішні документи замість вбудовування контенту + +## Примітки + +- Завжди перевіряйте працездатність команд перед їх включенням +- Якщо сумніваєтесь — не включайте; менше — краще +- Системне нагадування повідомляє Claude, що CLAUDE.md «може бути або не бути релевантним» — чим більше шуму, тим більше він ігнорується +- Монорепо найбільше виграють від чіткої структури ЩО/ЧОМУ/ЯК +- Файли CLAUDE.md для конкретних каталогів мають бути ще більш зосередженими diff --git a/uk/03-skills/code-review/SKILL.md b/uk/03-skills/code-review/SKILL.md new file mode 100644 index 0000000..d11b215 --- /dev/null +++ b/uk/03-skills/code-review/SKILL.md @@ -0,0 +1,70 @@ +--- +name: code-review-specialist +description: Комплексне код-рев'ю з аналізом безпеки, продуктивності та якості. Використовуйте, коли користувачі просять переглянути код, проаналізувати якість коду, оцінити pull request, або згадують код-рев'ю, аналіз безпеки чи оптимізацію продуктивності. +--- + +# Навичка код-рев'ю + +Ця навичка забезпечує комплексні можливості код-рев'ю з фокусом на: + +1. **Аналіз безпеки** + - Проблеми автентифікації/авторизації + - Ризики розкриття даних + - Вразливості інʼєкцій + - Криптографічні слабкості + - Логування чутливих даних + +2. **Аналіз продуктивності** + - Ефективність алгоритмів (аналіз Big O) + - Оптимізація памʼяті + - Оптимізація запитів до БД + - Можливості кешування + - Проблеми конкурентності + +3. **Якість коду** + - Принципи SOLID + - Патерни проєктування + - Конвенції іменування + - Документація + - Покриття тестами + +4. **Супровідність** + - Читабельність коду + - Розмір функцій (має бути < 50 рядків) + - Цикломатична складність + - Управління залежностями + - Безпека типів + +## Шаблон рев'ю + +Для кожного фрагмента перевіреного коду надати: + +### Резюме +- Загальна оцінка якості (1-5) +- Кількість виявлених проблем +- Рекомендовані пріоритетні зони + +### Критичні проблеми (якщо є) +- **Проблема**: Чіткий опис +- **Розташування**: Файл і номер рядка +- **Вплив**: Чому це важливо +- **Серйозність**: Критична/Висока/Середня +- **Виправлення**: Приклад коду + +### Знахідки за категоріями + +#### Безпека (якщо знайдено проблеми) +Перелік вразливостей безпеки з прикладами + +#### Продуктивність (якщо знайдено проблеми) +Перелік проблем продуктивності з аналізом складності + +#### Якість (якщо знайдено проблеми) +Перелік проблем якості коду з пропозиціями рефакторингу + +#### Супровідність (якщо знайдено проблеми) +Перелік проблем супровідності з покращеннями + +## Історія версій + +- v1.0.0 (2024-12-10): Початковий випуск з аналізом безпеки, продуктивності, якості та супровідності diff --git a/uk/03-skills/doc-generator/SKILL.md b/uk/03-skills/doc-generator/SKILL.md new file mode 100644 index 0000000..00c7103 --- /dev/null +++ b/uk/03-skills/doc-generator/SKILL.md @@ -0,0 +1,76 @@ +--- +name: api-documentation-generator +description: Генерація вичерпної, точної документації API з вихідного коду. Використовуйте при створенні або оновленні документації API, генерації специфікацій OpenAPI, або коли користувачі згадують документацію API, ендпоінти чи документацію. +--- + +# Навичка генерації документації API + +## Генерує + +- Специфікації OpenAPI/Swagger +- Документацію ендпоінтів API +- Приклади використання SDK +- Посібники з інтеграції +- Довідники кодів помилок +- Посібники з автентифікації + +## Структура документації + +### Для кожного ендпоінту + +```markdown +## GET /api/v1/users/:id + +### Опис +Короткий опис призначення цього ендпоінту + +### Параметри + +| Назва | Тип | Обовʼязковий | Опис | +|-------|-----|-------------|------| +| id | string | Так | ID користувача | + +### Відповідь + +**200 Успіх** +```json +{ + "id": "usr_123", + "name": "John Doe", + "email": "john@example.com", + "created_at": "2025-01-15T10:30:00Z" +} +``` + +**404 Не знайдено** +```json +{ + "error": "USER_NOT_FOUND", + "message": "Користувач не існує" +} +``` + +### Приклади + +**cURL** +```bash +curl -X GET "https://api.example.com/api/v1/users/usr_123" \ + -H "Authorization: Bearer YOUR_TOKEN" +``` + +**JavaScript** +```javascript +const user = await fetch('/api/v1/users/usr_123', { + headers: { 'Authorization': 'Bearer token' } +}).then(r => r.json()); +``` + +**Python** +```python +response = requests.get( + 'https://api.example.com/api/v1/users/usr_123', + headers={'Authorization': 'Bearer token'} +) +user = response.json() +``` +``` diff --git a/uk/03-skills/refactor/SKILL.md b/uk/03-skills/refactor/SKILL.md new file mode 100644 index 0000000..ab50114 --- /dev/null +++ b/uk/03-skills/refactor/SKILL.md @@ -0,0 +1,426 @@ +--- +name: code-refactor +description: Систематичний рефакторинг коду на основі методології Мартіна Фаулера. Використовуйте, коли користувачі просять рефакторити код, покращити структуру коду, зменшити технічний борг, очистити застарілий код, усунути запахи коду (code smells) або покращити супровідність коду. Ця навичка проводить через поетапний підхід з дослідженням, плануванням та безпечною інкрементальною реалізацією. +--- + +# Навичка рефакторингу коду + +Систематичний підхід до рефакторингу коду на основі книги Мартіна Фаулера *Refactoring: Improving the Design of Existing Code* (2-ге видання). Ця навичка наголошує на безпечних, інкрементальних змінах, підкріплених тестами. + +> «Рефакторинг — це процес зміни програмної системи таким чином, що не змінює зовнішню поведінку коду, але покращує його внутрішню структуру.» — Мартін Фаулер + +## Основні принципи + +1. **Збереження поведінки**: Зовнішня поведінка повинна залишатися незмінною +2. **Малі кроки**: Робити крихітні, тестовані зміни +3. **Тест-орієнтованість**: Тести — це страхувальна сітка +4. **Безперервність**: Рефакторинг — постійний процес, а не одноразова подія +5. **Співпраця**: Затвердження користувача потрібне на кожній фазі + +## Огляд робочого процесу + +``` +Фаза 1: Дослідження та аналіз + ↓ +Фаза 2: Оцінка покриття тестами + ↓ +Фаза 3: Виявлення запахів коду + ↓ +Фаза 4: Створення плану рефакторингу + ↓ +Фаза 5: Інкрементальна реалізація + ↓ +Фаза 6: Перегляд та ітерація +``` + +--- + +## Фаза 1: Дослідження та аналіз + +### Цілі +- Зрозуміти структуру та призначення кодової бази +- Визначити обсяг рефакторингу +- Зібрати контекст про бізнес-вимоги + +### Запитання до користувача +Перед початком уточніть: + +1. **Обсяг**: Які файли/модулі/функції потребують рефакторингу? +2. **Цілі**: Які проблеми ви намагаєтесь вирішити? (читабельність, продуктивність, супровідність) +3. **Обмеження**: Чи є зони, які НЕ слід змінювати? +4. **Тиск термінів**: Чи блокує це іншу роботу? +5. **Стан тестів**: Чи існують тести? Чи проходять вони? + +### Дії +- [ ] Прочитати та зрозуміти цільовий код +- [ ] Виявити залежності та інтеграції +- [ ] Задокументувати поточну архітектуру +- [ ] Зафіксувати існуючі маркери технічного боргу (TODOs, FIXMEs) + +### Вивід +Представити знахідки користувачу: +- Резюме структури коду +- Виявлені проблемні зони +- Початкові рекомендації +- **Запросити затвердження для продовження** + +--- + +## Фаза 2: Оцінка покриття тестами + +### Чому тести важливі +> «Рефакторинг без тестів — як їзда без пасків безпеки.» — Мартін Фаулер + +Тести — **ключовий засіб** безпечного рефакторингу. Без них ви ризикуєте внести помилки. + +### Кроки оцінки + +1. **Перевірити наявні тести** + ```bash + # Пошук файлів тестів + find . -name "*test*" -o -name "*spec*" | head -20 + ``` + +2. **Запустити існуючі тести** + ```bash + # JavaScript/TypeScript + npm test + + # Python + pytest -v + + # Java + mvn test + ``` + +3. **Перевірити покриття (якщо доступно)** + ```bash + # JavaScript + npm run test:coverage + + # Python + pytest --cov=. + ``` + +### Точка рішення: Запитати користувача + +**Якщо тести існують та проходять:** +- Перейти до Фази 3 + +**Якщо тести відсутні або неповні:** +Представити варіанти: +1. Спочатку написати тести (рекомендовано) +2. Додавати тести інкрементально під час рефакторингу +3. Продовжити без тестів (ризиковано — потребує підтвердження користувача) + +**Якщо тести не проходять:** +- ЗУПИНИТИСЯ. Виправити тести перед рефакторингом +- Запитати користувача: Чи слід спочатку виправити тести? + +### Рекомендації щодо написання тестів (якщо потрібно) + +Для кожної функції, що рефакториться, забезпечити тести для: +- Успішний шлях (нормальна робота) +- Граничні випадки (порожні введення, null, межі) +- Сценарії помилок (невалідні введення, виключення) + +Використовуйте цикл «red-green-refactor»: +1. Написати тест, що не проходить (red) +2. Зробити так, щоб пройшов (green) +3. Рефакторити + +--- + +## Фаза 3: Виявлення запахів коду + +### Що таке запахи коду? +Симптоми глибших проблем у коді. Це не помилки, а індикатори того, що код можна покращити. + +### Типові запахи коду для перевірки + +Див. [references/code-smells.md](references/code-smells.md) для повного каталогу. + +#### Короткий довідник + +| Запах | Ознаки | Вплив | +|-------|--------|-------| +| **Довгий метод** | Методи > 30-50 рядків | Важко зрозуміти, тестувати, супроводжувати | +| **Дубльований код** | Та сама логіка в кількох місцях | Виправлення помилок потрібне в кількох місцях | +| **Великий клас** | Клас з занадто багатьма відповідальностями | Порушує принцип єдиної відповідальності | +| **Заздрість до функцій** | Метод використовує дані іншого класу більше | Погана інкапсуляція | +| **Одержимість примітивами** | Надмірне використання примітивів замість обʼєктів | Відсутні доменні концепції | +| **Довгий список параметрів** | Методи з 4+ параметрами | Складно викликати правильно | +| **Групи даних** | Ті самі елементи даних зʼявляються разом | Відсутня абстракція | +| **Оператори Switch** | Складні ланцюжки switch/if-else | Важко розширювати | +| **Спекулятивна загальність** | Код «на всякий випадок» | Зайва складність | +| **Мертвий код** | Невикористаний код | Плутанина, тягар супровідності | + +### Кроки аналізу + +1. **Автоматичний аналіз** (якщо скрипти доступні) + ```bash + python scripts/detect-smells.py + ``` + +2. **Ручний перегляд** + - Систематично пройти код + - Зафіксувати кожен запах з розташуванням та серйозністю + - Категоризувати за впливом (Критичний/Високий/Середній/Низький) + +3. **Пріоритезація** + Зосередитися на запахах, які: + - Блокують поточну розробку + - Спричиняють помилки або плутанину + - Впливають на найчастіше змінювані шляхи коду + +### Вивід: Звіт про запахи + +Представити користувачу: +- Список виявлених запахів з розташуванням +- Оцінку серйозності для кожного +- Рекомендований порядок пріоритету +- **Запросити затвердження пріоритетів** + +--- + +## Фаза 4: Створення плану рефакторингу + +### Вибір рефакторингів + +Для кожного запаху обрати відповідний рефакторинг з каталогу. + +Див. [references/refactoring-catalog.md](references/refactoring-catalog.md) для повного списку. + +#### Відповідність запахів рефакторингам + +| Запах коду | Рекомендований рефакторинг | +|------------|---------------------------| +| Long Method | Extract Method, Replace Temp with Query | +| Duplicated Code | Extract Method, Pull Up Method, Form Template Method | +| Large Class | Extract Class, Extract Subclass | +| Feature Envy | Move Method, Move Field | +| Primitive Obsession | Replace Primitive with Object, Replace Type Code with Class | +| Long Parameter List | Introduce Parameter Object, Preserve Whole Object | +| Data Clumps | Extract Class, Introduce Parameter Object | +| Switch Statements | Replace Conditional with Polymorphism | +| Speculative Generality | Collapse Hierarchy, Inline Class, Remove Dead Code | +| Dead Code | Remove Dead Code | + +### Структура плану + +Використовуйте шаблон [templates/refactoring-plan.md](templates/refactoring-plan.md). + +Для кожного рефакторингу: +1. **Ціль**: Який код зміниться +2. **Запах**: Яку проблему вирішує +3. **Рефакторинг**: Яку техніку застосувати +4. **Кроки**: Детальні мікрокроки +5. **Ризики**: Що може піти не так +6. **Відкат**: Як скасувати за потреби + +### Поетапний підхід + +**КРИТИЧНО**: Впроваджуйте рефакторинг поступово, фазами. + +**Фаза A: Швидкі перемоги** (Низький ризик, висока цінність) +- Перейменування змінних для ясності +- Витяг очевидного дубльованого коду +- Видалення мертвого коду + +**Фаза B: Структурні покращення** (Середній ризик) +- Витяг методів з довгих функцій +- Введення обʼєктів параметрів +- Переміщення методів до відповідних класів + +**Фаза C: Архітектурні зміни** (Вищий ризик) +- Заміна умовних конструкцій поліморфізмом +- Витяг класів +- Введення патернів проєктування + +### Точка рішення: Представити план користувачу + +Перед реалізацією: +- Показати повний план рефакторингу +- Пояснити кожну фазу та її ризики +- Отримати явне затвердження для кожної фази +- **Запитати**: «Чи продовжити з Фазою A?» + +--- + +## Фаза 5: Інкрементальна реалізація + +### Золоте правило +> «Зміна → Тест → Зелений? → Коміт → Наступний крок» + +### Ритм реалізації + +Для кожного кроку рефакторингу: + +1. **Попередня перевірка** + - Тести проходять (зелені) + - Код компілюється + +2. **Зробити ОДНУ малу зміну** + - Дотримуватися механіки з каталогу + - Тримати зміни мінімальними + +3. **Верифікація** + - Негайно запустити тести + - Перевірити на помилки компіляції + +4. **Якщо тести проходять (зелені)** + - Закомітити з описовим повідомленням + - Перейти до наступного кроку + +5. **Якщо тести не проходять (червоні)** + - ЗУПИНИТИСЯ негайно + - Скасувати зміну + - Проаналізувати, що пішло не так + - Запитати користувача, якщо незрозуміло + +### Стратегія комітів + +Кожен коміт має бути: +- **Атомарний**: Одна логічна зміна +- **Оборотний**: Легко відкатити +- **Описовий**: Зрозуміле повідомлення коміту + +Приклади повідомлень комітів: +``` +refactor: Extract calculateTotal() from processOrder() +refactor: Rename 'x' to 'customerCount' for clarity +refactor: Remove unused validateOldFormat() method +``` + +### Звіт про прогрес + +Після кожної підфази звітувати користувачу: +- Внесені зміни +- Тести досі проходять? +- Виявлені проблеми +- **Запитати**: «Продовжити з наступною порцією?» + +--- + +## Фаза 6: Перегляд та ітерація + +### Контрольний список після рефакторингу + +- [ ] Усі тести проходять +- [ ] Немає нових попереджень/помилок +- [ ] Код успішно компілюється +- [ ] Поведінка не змінилася (ручна верифікація) +- [ ] Документація оновлена за потреби +- [ ] Історія комітів чиста + +### Порівняння метрик + +Запустити аналіз складності до і після: +```bash +python scripts/analyze-complexity.py +``` + +Представити покращення: +- Зміна кількості рядків коду +- Зміна цикломатичної складності +- Зміна індексу супровідності + +### Перегляд користувачем + +Представити фінальні результати: +- Резюме всіх змін +- Порівняння коду до/після +- Покращення метрик +- Залишковий технічний борг +- **Запитати**: «Чи задоволені ви цими змінами?» + +### Наступні кроки + +Обговорити з користувачем: +- Додаткові запахи для усунення? +- Запланувати подальший рефакторинг? +- Застосувати аналогічні зміни в інших місцях? + +--- + +## Важливі рекомендації + +### Коли ЗУПИНИТИСЯ та запитати + +Завжди паузу та консультацію з користувачем, коли: +- Невпевненість щодо бізнес-логіки +- Зміна може вплинути на зовнішні API +- Покриття тестами недостатнє +- Потрібне значне архітектурне рішення +- Рівень ризику зростає +- Зустрічаєте неочікувану складність + +### Правила безпеки + +1. **Ніколи не рефакторити без тестів** (якщо користувач явно не підтвердив ризик) +2. **Ніколи не робити великих змін** — розбивати на крихітні кроки +3. **Ніколи не пропускати запуск тестів** після кожної зміни +4. **Ніколи не продовжувати, якщо тести не проходять** — виправити або відкатити +5. **Ніколи не припускати** — якщо сумніваєтесь, запитайте + +### Чого НЕ робити + +- Не поєднуйте рефакторинг з додаванням функцій +- Не рефакторте під час аварій на продакшні +- Не рефакторте код, який не розумієте +- Не переускладнюйте — тримайте просто +- Не рефакторте все одразу + +--- + +## Приклад швидкого старту + +### Сценарій: Довгий метод з дублюванням + +**До:** +```javascript +function processOrder(order) { + // 150 рядків коду з: + // - Дубльованою логікою валідації + // - Інлайн-обчисленнями + // - Змішаними відповідальностями +} +``` + +**Кроки рефакторингу:** + +1. **Переконатися, що тести існують** для processOrder() +2. **Витягти** валідацію у validateOrder() +3. **Тест** — має пройти +4. **Витягти** обчислення у calculateOrderTotal() +5. **Тест** — має пройти +6. **Витягти** сповіщення у notifyCustomer() +7. **Тест** — має пройти +8. **Перегляд** — processOrder() тепер оркеструє 3 чіткі функції + +**Після:** +```javascript +function processOrder(order) { + validateOrder(order); + const total = calculateOrderTotal(order); + notifyCustomer(order, total); + return { order, total }; +} +``` + +--- + +## Довідники + +- [Каталог запахів коду](references/code-smells.md) — повний список запахів коду +- [Каталог рефакторингів](references/refactoring-catalog.md) — техніки рефакторингу +- [Шаблон плану рефакторингу](templates/refactoring-plan.md) — шаблон планування + +## Скрипти + +- `scripts/analyze-complexity.py` — аналіз метрик складності коду +- `scripts/detect-smells.py` — автоматичне виявлення запахів + +## Історія версій + +- v1.0.0 (2025-01-15): Початковий випуск з методологією Фаулера, поетапним підходом, точками консультації з користувачем diff --git a/uk/03-skills/refactor/templates/refactoring-plan.md b/uk/03-skills/refactor/templates/refactoring-plan.md new file mode 100644 index 0000000..467cbda --- /dev/null +++ b/uk/03-skills/refactor/templates/refactoring-plan.md @@ -0,0 +1,284 @@ +# Шаблон плану рефакторингу + +Використовуйте цей шаблон для документування та відстеження вашого рефакторингу. + +--- + +## Інформація про проєкт + +| Поле | Значення | +|------|----------| +| **Проєкт/Модуль** | [Назва проєкту] | +| **Цільові файли** | [Список файлів для рефакторингу] | +| **Дата створення** | [Дата] | +| **Автор** | [Імʼя] | +| **Статус** | Чернетка / На перегляді / Затверджено / В роботі / Завершено | + +--- + +## Загальний опис + +### Цілі +- [ ] [Основна ціль: напр., Покращити читабельність обробки платежів] +- [ ] [Другорядна ціль: напр., Зменшити дублювання коду] +- [ ] [Третинна ціль: напр., Покращити тестовність] + +### Обмеження +- [ ] [Обмеження 1: напр., Не можна змінювати публічний API] +- [ ] [Обмеження 2: напр., Зберегти зворотну сумісність] +- [ ] [Обмеження 3: напр., Без змін схеми БД] + +### Рівень ризику +- [ ] Низький — незначні зміни, добре протестований код +- [ ] Середній — помірні зміни, деякий ризик +- [ ] Високий — значні зміни, потрібна ретельна увага + +--- + +## Контрольний список перед рефакторингом + +### Оцінка покриття тестами + +| Метрика | Поточне | Ціль | Статус | +|---------|---------|------|--------| +| Покриття юніт-тестами | __% | ≥80% | | +| Інтеграційні тести | Так/Ні | Так | | +| Усі тести проходять | Так/Ні | Так | | + +### Потрібно перед початком +- [ ] Усі тести проходять +- [ ] Код переглянутий та зрозумілий +- [ ] Резервне копіювання/контроль версій налаштовано +- [ ] Затвердження користувача отримано + +--- + +## Виявлені запахи коду + +### Резюме + +| # | Запах | Розташування | Серйозність | Пріоритет | +|---|-------|-------------|-------------|-----------| +| 1 | [напр., Long Method] | [файл:рядок] | Високий | P1 | +| 2 | [напр., Duplicate Code] | [файл:рядок] | Середній | P2 | +| 3 | [напр., Feature Envy] | [файл:рядок] | Низький | P3 | + +### Детальний аналіз + +#### Запах #1: [Назва] + +**Розташування**: `path/to/file.js:45-120` + +**Опис**: [Детальний опис проблеми] + +**Вплив**: +- [Вплив 1] +- [Вплив 2] + +**Запропоноване рішення**: [Короткий огляд виправлення] + +--- + +## Фази рефакторингу + +### Фаза A: Швидкі перемоги (Низький ризик) + +**Ціль**: Прості покращення з негайною цінністю + +**Орієнтовні зміни**: [X файлів, Y методів] + +**Потрібне затвердження користувача**: Так / Ні + +| # | Завдання | Файл | Рефакторинг | Статус | +|---|---------|------|-------------|--------| +| A1 | Перейменувати змінну `x` на `userCount` | utils.js:15 | Rename Variable | [ ] | +| A2 | Видалити невикористаний `oldHandler()` | api.js:89 | Remove Dead Code | [ ] | +| A3 | Витягти дубльовану валідацію | form.js:23,67 | Extract Method | [ ] | + +**План відкату**: Відкатити коміти A1-A3 + +--- + +### Фаза B: Структурні покращення (Середній ризик) + +**Ціль**: Покращити організацію та ясність коду + +**Орієнтовні зміни**: [X файлів, Y методів] + +**Потрібне затвердження користувача**: Так + +**Залежності**: Фаза A має бути завершена + +| # | Завдання | Файл | Рефакторинг | Статус | +|---|---------|------|-------------|--------| +| B1 | Витягти `calculatePrice()` з довгого методу | order.js:45 | Extract Method | [ ] | +| B2 | Ввести обʼєкт параметрів `OrderDetails` | order.js:12 | Introduce Parameter Object | [ ] | +| B3 | Перемістити `formatAddress()` до класу Address | customer.js:78 | Move Method | [ ] | + +**План відкату**: Відкатити до коміту після Фази A + +--- + +### Фаза C: Архітектурні зміни (Вищий ризик) + +**Ціль**: Усунути глибші структурні проблеми + +**Орієнтовні зміни**: [X файлів, Y методів] + +**Потрібне затвердження користувача**: Так + +**Залежності**: Фази A та B мають бути завершені + +| # | Завдання | Файл | Рефакторинг | Статус | +|---|---------|------|-------------|--------| +| C1 | Замінити switch цін на поліморфізм | pricing.js:30 | Replace Conditional with Polymorphism | [ ] | +| C2 | Витягти клас `NotificationService` | user.js:100 | Extract Class | [ ] | + +**План відкату**: Відкатити до коміту після Фази B + +--- + +## Детальні кроки рефакторингу + +### Завдання [ID]: [Назва завдання] + +**Усунений запах**: [Назва запаху] + +**Техніка рефакторингу**: [Назва техніки] + +**Рівень ризику**: Низький / Середній / Високий + +#### Контекст + +**До** (Поточний стан): +```javascript +// Вставте поточний код тут +``` + +**Після** (Очікуваний стан): +```javascript +// Вставте очікуваний код тут +``` + +#### Покрокова механіка + +1. [ ] **Крок 1**: [Опис] + - Тест: Запустити тести після цього кроку + - Очікувано: Усі тести проходять + +2. [ ] **Крок 2**: [Опис] + - Тест: Запустити тести після цього кроку + - Очікувано: Усі тести проходять + +3. [ ] **Крок 3**: [Опис] + - Тест: Запустити тести після цього кроку + - Очікувано: Усі тести проходять + +#### Верифікація + +- [ ] Усі тести проходять +- [ ] Поведінка не змінилася +- [ ] Код компілюється +- [ ] Немає нових попереджень + +#### Повідомлення коміту +``` +refactor: [Опишіть рефакторинг] +``` + +--- + +## Відстеження прогресу + +### Статус фаз + +| Фаза | Статус | Розпочато | Завершено | Тести проходять | +|------|--------|-----------|-----------|-----------------| +| A | Не розпочато / В роботі / Готово | | | | +| B | Не розпочато / В роботі / Готово | | | | +| C | Не розпочато / В роботі / Готово | | | | + +### Виявлені проблеми + +| # | Проблема | Рішення | Статус | +|---|---------|---------|--------| +| 1 | [Опис] | [Як вирішено] | Відкрито / Вирішено | + +--- + +## Порівняння метрик + +### До рефакторингу + +| Метрика | Файл 1 | Файл 2 | Загалом | +|---------|--------|--------|---------| +| Рядків коду | | | | +| Цикломатична складність | | | | +| Індекс супровідності | | | | +| Кількість методів | | | | +| Середня довжина методу | | | | + +### Після рефакторингу + +| Метрика | Файл 1 | Файл 2 | Загалом | Зміна | +|---------|--------|--------|---------|-------| +| Рядків коду | | | | | +| Цикломатична складність | | | | | +| Індекс супровідності | | | | | +| Кількість методів | | | | | +| Середня довжина методу | | | | | + +--- + +## Контрольний список після рефакторингу + +- [ ] Усі тести проходять +- [ ] Немає нових попереджень або помилок +- [ ] Код успішно компілюється +- [ ] Ручна верифікація завершена +- [ ] Документація оновлена (за потреби) +- [ ] Код переглянутий +- [ ] Метрики покращені +- [ ] Підпис користувача отриманий + +--- + +## Отримані уроки + +### Що пройшло добре +- [Пункт 1] +- [Пункт 2] + +### Що можна покращити +- [Пункт 1] +- [Пункт 2] + +### Рекомендації на майбутнє +- [Пункт 1] +- [Пункт 2] + +--- + +## Затвердження + +| Роль | Імʼя | Дата | Підпис | +|------|------|------|--------| +| Автор плану | | | | +| Технічний лід | | | | +| Власник продукту | | | | + +--- + +## Додатки + +### A. Повʼязана документація +- [Посилання на релевантні документи] + +### B. Довідкові матеріали +- [Посилання на каталог запахів коду] +- [Посилання на каталог рефакторингів] + +### C. Використані інструменти +- [Тестовий фреймворк] +- [Інструменти лінтингу] +- [Інструменти аналізу складності] From b56f1e111abb6c19f68660b0a3a3aa4e8cbc8f32 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 22:57:13 +0300 Subject: [PATCH 10/20] feat(uk): translate P3 examples for skills/refactor, subagents, checkpoints, advanced 03-skills/refactor: SKILL.md + templates/refactoring-plan.md 04-subagents: 8 agent definitions 08-checkpoints: checkpoint-examples.md 09-advanced: planning-mode-examples.md Remaining: refactor references (1692 lines), P4 root docs Ref: luongnv89/claude-howto#63 --- uk/04-subagents/README.md | 1118 +++++++++++++++++ uk/04-subagents/clean-code-reviewer.md | 69 + uk/04-subagents/code-reviewer.md | 64 + uk/04-subagents/data-scientist.md | 100 ++ uk/04-subagents/debugger.md | 83 ++ uk/04-subagents/documentation-writer.md | 101 ++ uk/04-subagents/implementation-agent.md | 81 ++ uk/04-subagents/performance-optimizer.md | 129 ++ uk/04-subagents/secure-reviewer.md | 78 ++ uk/04-subagents/test-engineer.md | 77 ++ uk/08-checkpoints/checkpoint-examples.md | 342 +++++ .../planning-mode-examples.md | 493 ++++++++ 12 files changed, 2735 insertions(+) create mode 100644 uk/04-subagents/README.md create mode 100644 uk/04-subagents/clean-code-reviewer.md create mode 100644 uk/04-subagents/code-reviewer.md create mode 100644 uk/04-subagents/data-scientist.md create mode 100644 uk/04-subagents/debugger.md create mode 100644 uk/04-subagents/documentation-writer.md create mode 100644 uk/04-subagents/implementation-agent.md create mode 100644 uk/04-subagents/performance-optimizer.md create mode 100644 uk/04-subagents/secure-reviewer.md create mode 100644 uk/04-subagents/test-engineer.md create mode 100644 uk/08-checkpoints/checkpoint-examples.md create mode 100644 uk/09-advanced-features/planning-mode-examples.md diff --git a/uk/04-subagents/README.md b/uk/04-subagents/README.md new file mode 100644 index 0000000..6786dc1 --- /dev/null +++ b/uk/04-subagents/README.md @@ -0,0 +1,1118 @@ + + + + + + + Claude How To + + +# Субагенти — повний довідник + +Субагенти — це спеціалізовані AI-асистенти, яким Claude Code може делегувати завдання. Кожен субагент має конкретне призначення, використовує власне контекстне вікно, окреме від основної розмови, і може бути налаштований з конкретними інструментами та власним системним промптом. + +## Зміст + +1. [Огляд](#огляд) +2. [Ключові переваги](#ключові-переваги) +3. [Розташування файлів](#розташування-файлів) +4. [Конфігурація](#конфігурація) +5. [Вбудовані субагенти](#вбудовані-субагенти) +6. [Управління субагентами](#управління-субагентами) +7. [Використання субагентів](#використання-субагентів) +8. [Відновлювані агенти](#відновлювані-агенти) +9. [Ланцюжки субагентів](#ланцюжки-субагентів) +10. [Постійна пам'ять для субагентів](#постійна-памʼять-для-субагентів) +11. [Фонові субагенти](#фонові-субагенти) +12. [Ізоляція через Worktree](#ізоляція-через-worktree) +13. [Обмеження створюваних субагентів](#обмеження-створюваних-субагентів) +14. [CLI-команда `claude agents`](#cli-команда-claude-agents) +15. [Agent Teams (експериментально)](#agent-teams-експериментально) +16. [Безпека субагентів плагінів](#безпека-субагентів-плагінів) +17. [Архітектура](#архітектура) +18. [Управління контекстом](#управління-контекстом) +19. [Коли використовувати субагентів](#коли-використовувати-субагентів) +20. [Найкращі практики](#найкращі-практики) +21. [Приклади субагентів у цій папці](#приклади-субагентів-у-цій-папці) +22. [Інструкції з встановлення](#інструкції-з-встановлення) +23. [Пов'язані концепції](#повʼязані-концепції) + +--- + +## Огляд + +Субагенти забезпечують делеговане виконання завдань у Claude Code шляхом: + +- Створення **ізольованих AI-асистентів** з окремими контекстними вікнами +- Надання **налаштованих системних промптів** для спеціалізованої експертизи +- Застосування **контролю доступу до інструментів** для обмеження можливостей +- Запобігання **забрудненню контексту** від складних завдань +- Забезпечення **паралельного виконання** кількох спеціалізованих завдань + +Кожен субагент працює незалежно з чистого аркуша, отримуючи лише конкретний контекст, необхідний для його завдання, а потім повертає результати головному агенту для синтезу. + +**Швидкий старт**: Використовуйте команду `/agents` для створення, перегляду, редагування та управління субагентами в інтерактивному режимі. + +--- + +## Ключові переваги + +| Перевага | Опис | +|----------|------| +| **Збереження контексту** | Працює в окремому контексті, запобігаючи забрудненню основної розмови | +| **Спеціалізована експертиза** | Точно налаштований для конкретних доменів з вищим рівнем успіху | +| **Повторне використання** | Використання в різних проєктах і поширення між командами | +| **Гнучкі дозволи** | Різні рівні доступу до інструментів для різних типів субагентів | +| **Масштабованість** | Кілька агентів працюють над різними аспектами одночасно | + +--- + +## Розташування файлів + +Файли субагентів можна зберігати в кількох розташуваннях з різними областями дії: + +| Пріоритет | Тип | Розташування | Область дії | +|-----------|-----|-------------|-------------| +| 1 (найвищий) | **CLI-визначені** | Через прапорець `--agents` (JSON) | Лише сесія | +| 2 | **Субагенти проєкту** | `.claude/agents/` | Поточний проєкт | +| 3 | **Субагенти користувача** | `~/.claude/agents/` | Усі проєкти | +| 4 (найнижчий) | **Агенти плагінів** | Каталог `agents/` плагіна | Через плагіни | + +Коли існують дублікати імен, джерела з вищим пріоритетом мають перевагу. + +--- + +## Конфігурація + +### Формат файлу + +Субагенти визначаються у YAML-фронтматері, за яким іде системний промпт у Markdown: + +```yaml +--- +name: your-sub-agent-name +description: Description of when this subagent should be invoked +tools: tool1, tool2, tool3 # Опціонально — успадковує всі інструменти, якщо не вказано +disallowedTools: tool4 # Опціонально — явно заборонені інструменти +model: sonnet # Опціонально — sonnet, opus, haiku або inherit +permissionMode: default # Опціонально — режим дозволів +maxTurns: 20 # Опціонально — ліміт агентних кроків +skills: skill1, skill2 # Опціонально — навички для попереднього завантаження +mcpServers: server1 # Опціонально — доступні MCP-сервери +memory: user # Опціонально — область постійної пам'яті (user, project, local) +background: false # Опціонально — запуск як фонове завдання +effort: high # Опціонально — рівень зусиль (low, medium, high, max) +isolation: worktree # Опціонально — ізоляція через git worktree +initialPrompt: "Start by analyzing the codebase" # Опціонально — автоматичний перший крок +hooks: # Опціонально — хуки, обмежені компонентом + PreToolUse: + - matcher: "Bash" + hooks: + - type: command + command: "./scripts/security-check.sh" +--- + +Your subagent's system prompt goes here. This can be multiple paragraphs +and should clearly define the subagent's role, capabilities, and approach +to solving problems. +``` + +### Поля конфігурації + +| Поле | Обов'язкове | Опис | +|------|-------------|------| +| `name` | Так | Унікальний ідентифікатор (малі літери та дефіси) | +| `description` | Так | Опис призначення природною мовою. Включіть "use PROACTIVELY" для заохочення автоматичного виклику | +| `tools` | Ні | Список інструментів через кому. Пропустіть для успадкування всіх. Підтримує синтаксис `Agent(agent_name)` для обмеження створюваних субагентів | +| `disallowedTools` | Ні | Список заборонених інструментів через кому | +| `model` | Ні | Модель: `sonnet`, `opus`, `haiku`, повний ID моделі або `inherit`. За замовч. — налаштована модель субагента | +| `permissionMode` | Ні | `default`, `acceptEdits`, `dontAsk`, `bypassPermissions`, `plan` | +| `maxTurns` | Ні | Максимальна кількість агентних кроків | +| `skills` | Ні | Список навичок через кому для попереднього завантаження. Вставляє повний вміст навички в контекст при запуску | +| `mcpServers` | Ні | MCP-сервери, доступні субагенту | +| `hooks` | Ні | Хуки, обмежені компонентом (PreToolUse, PostToolUse, Stop) | +| `memory` | Ні | Область постійної пам'яті: `user`, `project` або `local` | +| `background` | Ні | `true` для запуску як фонового завдання | +| `effort` | Ні | Рівень зусиль: `low`, `medium`, `high` або `max` | +| `isolation` | Ні | `worktree` для власного git worktree | +| `initialPrompt` | Ні | Автоматичний перший крок при запуску субагента як головного агента | + +### Варіанти конфігурації інструментів + +**Варіант 1: Успадкування всіх інструментів (пропустити поле)** +```yaml +--- +name: full-access-agent +description: Agent with all available tools +--- +``` + +**Варіант 2: Вказати конкретні інструменти** +```yaml +--- +name: limited-agent +description: Agent with specific tools only +tools: Read, Grep, Glob, Bash +--- +``` + +**Варіант 3: Умовний доступ до інструментів** +```yaml +--- +name: conditional-agent +description: Agent with filtered tool access +tools: Read, Bash(npm:*), Bash(test:*) +--- +``` + +### Конфігурація через CLI + +Визначте субагентів для однієї сесії за допомогою прапорця `--agents` у форматі JSON: + +```bash +claude --agents '{ + "code-reviewer": { + "description": "Expert code reviewer. Use proactively after code changes.", + "prompt": "You are a senior code reviewer. Focus on code quality, security, and best practices.", + "tools": ["Read", "Grep", "Glob", "Bash"], + "model": "sonnet" + } +}' +``` + +**Формат JSON для прапорця `--agents`:** + +```json +{ + "agent-name": { + "description": "Required: when to invoke this agent", + "prompt": "Required: system prompt for the agent", + "tools": ["Optional", "array", "of", "tools"], + "model": "optional: sonnet|opus|haiku" + } +} +``` + +**Пріоритет визначень агентів:** + +Визначення агентів завантажуються з таким пріоритетом (перший збіг виграє): +1. **CLI-визначені** — прапорець `--agents` (лише сесія, JSON) +2. **Рівень проєкту** — `.claude/agents/` (поточний проєкт) +3. **Рівень користувача** — `~/.claude/agents/` (усі проєкти) +4. **Рівень плагіна** — каталог `agents/` плагіна + +Це дозволяє CLI-визначенням перевизначати всі інші джерела для однієї сесії. + +--- + +## Вбудовані субагенти + +Claude Code включає кілька вбудованих субагентів, які завжди доступні: + +| Агент | Модель | Призначення | +|-------|--------|-------------| +| **general-purpose** | Успадковує | Складні, багатокрокові завдання | +| **Plan** | Успадковує | Дослідження для режиму планування | +| **Explore** | Haiku | Дослідження кодової бази лише для читання (швидке/середнє/дуже ретельне) | +| **Bash** | Успадковує | Термінальні команди в окремому контексті | +| **statusline-setup** | Sonnet | Налаштування рядка стану | +| **Claude Code Guide** | Haiku | Відповіді на питання про функції Claude Code | + +### Субагент General-Purpose + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Успадковує від батька | +| **Інструменти** | Усі інструменти | +| **Призначення** | Складні дослідницькі завдання, багатокрокові операції, модифікація коду | + +**Коли використовується**: Завдання, що потребують дослідження та модифікації зі складною логікою. + +### Субагент Plan + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Успадковує від батька | +| **Інструменти** | Read, Glob, Grep, Bash | +| **Призначення** | Автоматичне дослідження кодової бази в режимі планування | + +**Коли використовується**: Коли Claude потрібно зрозуміти кодову базу перед представленням плану. + +### Субагент Explore + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Haiku (швидкий, низька затримка) | +| **Режим** | Строго лише для читання | +| **Інструменти** | Glob, Grep, Read, Bash (лише команди для читання) | +| **Призначення** | Швидкий пошук та аналіз кодової бази | + +**Коли використовується**: Пошук/розуміння коду без внесення змін. + +**Рівні ретельності** — вкажіть глибину дослідження: +- **"quick"** — швидкий пошук з мінімальним дослідженням, добре для пошуку конкретних патернів +- **"medium"** — помірне дослідження, баланс швидкості та ретельності, стандартний підхід +- **"very thorough"** — комплексний аналіз у кількох розташуваннях та конвенціях іменування, може зайняти більше часу + +### Субагент Bash + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Успадковує від батька | +| **Інструменти** | Bash | +| **Призначення** | Виконання термінальних команд в окремому контекстному вікні | + +**Коли використовується**: Виконання команд оболонки, які виграють від ізольованого контексту. + +### Субагент Statusline Setup + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Sonnet | +| **Інструменти** | Read, Write, Bash | +| **Призначення** | Налаштування відображення рядка стану Claude Code | + +**Коли використовується**: Налаштування або кастомізація рядка стану. + +### Субагент Claude Code Guide + +| Властивість | Значення | +|-------------|----------| +| **Модель** | Haiku (швидкий, низька затримка) | +| **Інструменти** | Лише для читання | +| **Призначення** | Відповіді на питання про функції та використання Claude Code | + +**Коли використовується**: Коли користувачі питають про роботу Claude Code або використання конкретних функцій. + +--- + +## Управління субагентами + +### Команда `/agents` (рекомендовано) + +```bash +/agents +``` + +Надає інтерактивне меню для: +- Перегляду всіх доступних субагентів (вбудованих, користувача та проєкту) +- Створення нових субагентів з керованим налаштуванням +- Редагування наявних субагентів та доступу до інструментів +- Видалення субагентів +- Перегляду активних субагентів при наявності дублікатів + +### Пряме управління файлами + +```bash +# Створення субагента проєкту +mkdir -p .claude/agents +cat > .claude/agents/test-runner.md << 'EOF' +--- +name: test-runner +description: Use proactively to run tests and fix failures +--- + +You are a test automation expert. When you see code changes, proactively +run the appropriate tests. If tests fail, analyze the failures and fix +them while preserving the original test intent. +EOF + +# Створення субагента користувача (доступний у всіх проєктах) +mkdir -p ~/.claude/agents +``` + +--- + +## Використання субагентів + +### Автоматичне делегування + +Claude проактивно делегує завдання на основі: +- Опису завдання у вашому запиті +- Поля `description` у конфігурації субагента +- Поточного контексту та доступних інструментів + +Для заохочення проактивного використання додайте "use PROACTIVELY" або "MUST BE USED" у поле `description`: + +```yaml +--- +name: code-reviewer +description: Expert code review specialist. Use PROACTIVELY after writing or modifying code. +--- +``` + +### Явний виклик + +Ви можете явно запросити конкретного субагента: + +``` +> Use the test-runner subagent to fix failing tests +> Have the code-reviewer subagent look at my recent changes +> Ask the debugger subagent to investigate this error +``` + +### Виклик через @-згадку + +Використовуйте префікс `@` для гарантованого виклику конкретного субагента (обходить евристику автоматичного делегування): + +``` +> @"code-reviewer (agent)" review the auth module +``` + +### Агент на всю сесію + +Запуск сесії з конкретним агентом як головним: + +```bash +# Через прапорець CLI +claude --agent code-reviewer + +# Через settings.json +{ + "agent": "code-reviewer" +} +``` + +### Список доступних агентів + +Використовуйте команду `claude agents` для переліку всіх налаштованих агентів з усіх джерел: + +```bash +claude agents +``` + +--- + +## Відновлювані агенти + +Субагенти можуть продовжувати попередні розмови зі збереженим контекстом: + +```bash +# Початковий виклик +> Use the code-analyzer agent to start reviewing the authentication module +# Повертає agentId: "abc123" + +# Відновлення агента пізніше +> Resume agent abc123 and now analyze the authorization logic as well +``` + +**Випадки використання**: +- Тривалі дослідження між кількома сесіями +- Ітеративне вдосконалення без втрати контексту +- Багатокрокові воркфлови зі збереженням контексту + +--- + +## Ланцюжки субагентів + +Послідовне виконання кількох субагентів: + +```bash +> First use the code-analyzer subagent to find performance issues, + then use the optimizer subagent to fix them +``` + +Це дозволяє створювати складні воркфлови, де результат одного субагента є вхідними даними для іншого. + +--- + +## Постійна пам'ять для субагентів + +Поле `memory` надає субагентам постійний каталог, що зберігається між розмовами. Це дозволяє субагентам накопичувати знання з часом, зберігаючи нотатки, висновки та контекст між сесіями. + +### Області пам'яті + +| Область | Каталог | Випадок використання | +|---------|---------|---------------------| +| `user` | `~/.claude/agent-memory//` | Персональні нотатки та налаштування для всіх проєктів | +| `project` | `.claude/agent-memory//` | Знання, специфічні для проєкту, спільні з командою | +| `local` | `.claude/agent-memory-local//` | Локальні знання проєкту, не комітяться у контроль версій | + +### Як це працює + +- Перші 200 рядків `MEMORY.md` у каталозі пам'яті автоматично завантажуються в системний промпт субагента +- Інструменти `Read`, `Write` та `Edit` автоматично ввімкнені для управління файлами пам'яті +- Субагент може створювати додаткові файли у каталозі пам'яті за потребою + +### Приклад конфігурації + +```yaml +--- +name: researcher +memory: user +--- + +You are a research assistant. Use your memory directory to store findings, +track progress across sessions, and build up knowledge over time. + +Check your MEMORY.md file at the start of each session to recall previous context. +``` + +```mermaid +graph LR + A["Subagent
Session 1"] -->|writes| M["MEMORY.md
(persistent)"] + M -->|loads into| B["Subagent
Session 2"] + B -->|updates| M + M -->|loads into| C["Subagent
Session 3"] + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#e1f5fe,stroke:#333,color:#333 + style M fill:#f3e5f5,stroke:#333,color:#333 +``` + +--- + +## Фонові субагенти + +Субагенти можуть працювати у фоні, звільняючи основну розмову для інших завдань. + +### Конфігурація + +Встановіть `background: true` у фронтматері для постійного запуску субагента як фонового завдання: + +```yaml +--- +name: long-runner +background: true +description: Performs long-running analysis tasks in the background +--- +``` + +### Клавіатурні скорочення + +| Скорочення | Дія | +|-----------|-----| +| `Ctrl+B` | Перемістити поточне завдання субагента у фон | +| `Ctrl+F` | Завершити всіх фонових агентів (натисніть двічі для підтвердження) | + +### Вимкнення фонових завдань + +Встановіть змінну оточення для повного вимкнення підтримки фонових завдань: + +```bash +export CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 +``` + +--- + +## Ізоляція через Worktree + +Налаштування `isolation: worktree` надає субагенту власне git worktree, дозволяючи вносити зміни незалежно, не впливаючи на основне робоче дерево. + +### Конфігурація + +```yaml +--- +name: feature-builder +isolation: worktree +description: Implements features in an isolated git worktree +tools: Read, Write, Edit, Bash, Grep, Glob +--- +``` + +### Як це працює + +```mermaid +graph TB + Main["Main Working Tree"] -->|spawns| Sub["Subagent with
Isolated Worktree"] + Sub -->|makes changes in| WT["Separate Git
Worktree + Branch"] + WT -->|no changes| Clean["Auto-cleaned"] + WT -->|has changes| Return["Returns worktree
path and branch"] + + style Main fill:#e1f5fe,stroke:#333,color:#333 + style Sub fill:#f3e5f5,stroke:#333,color:#333 + style WT fill:#e8f5e9,stroke:#333,color:#333 + style Clean fill:#fff3e0,stroke:#333,color:#333 + style Return fill:#fff3e0,stroke:#333,color:#333 +``` + +- Субагент працює у власному git worktree на окремій гілці +- Якщо субагент не вносить змін, worktree автоматично очищується +- Якщо зміни є, шлях до worktree та назва гілки повертаються головному агенту для огляду або мерджу + +--- + +## Обмеження створюваних субагентів + +Ви можете контролювати, яких субагентів може створювати конкретний субагент, використовуючи синтаксис `Agent(agent_type)` у полі `tools`. Це дозволяє створити список дозволених субагентів для делегування. + +> **Примітка**: У v2.1.63 інструмент `Task` було перейменовано на `Agent`. Існуючі посилання `Task(...)` все ще працюють як псевдоніми. + +### Приклад + +```yaml +--- +name: coordinator +description: Coordinates work between specialized agents +tools: Agent(worker, researcher), Read, Bash +--- + +You are a coordinator agent. You can delegate work to the "worker" and +"researcher" subagents only. Use Read and Bash for your own exploration. +``` + +У цьому прикладі субагент `coordinator` може створювати лише субагентів `worker` та `researcher`. Він не може створювати інших субагентів, навіть якщо вони визначені деінде. + +--- + +## CLI-команда `claude agents` + +Команда `claude agents` відображає всіх налаштованих агентів, згрупованих за джерелом (вбудовані, рівень користувача, рівень проєкту): + +```bash +claude agents +``` + +Ця команда: +- Показує всіх доступних агентів з усіх джерел +- Групує агентів за розташуванням джерела +- Вказує **перевизначення**, коли агент вищого пріоритету затіняє агента нижчого рівня (наприклад, агент рівня проєкту з тим самим ім'ям, що й агент рівня користувача) + +--- + +## Agent Teams (експериментально) + +Agent Teams координують кілька екземплярів Claude Code, що працюють разом над складними завданнями. На відміну від субагентів (які є делегованими підзавданнями, що повертають результати), тіммейти працюють незалежно з власними контекстними вікнами і можуть обмінюватися повідомленнями безпосередньо через спільну систему поштових скриньок. + +> **Офіційна документація**: [code.claude.com/docs/en/agent-teams](https://code.claude.com/docs/en/agent-teams) + +> **Примітка**: Agent Teams — експериментальна функція, вимкнена за замовчуванням. Потребує Claude Code v2.1.32+. Увімкніть перед використанням. + +### Субагенти vs Agent Teams + +| Аспект | Субагенти | Agent Teams | +|--------|-----------|-------------| +| **Модель делегування** | Батько делегує підзавдання, чекає результат | Тімлід координує роботу, тіммейти виконують незалежно | +| **Контекст** | Чистий контекст на підзавдання, результати стискаються назад | Кожен тіммейт підтримує власне постійне контекстне вікно | +| **Координація** | Послідовна або паралельна, керована батьком | Спільний список завдань з автоматичним управлінням залежностями | +| **Комунікація** | Результати повертаються лише батьку (без обміну між агентами) | Тіммейти обмінюються повідомленнями безпосередньо через поштову скриньку | +| **Відновлення сесії** | Підтримується | Не підтримується з in-process тіммейтами | +| **Найкраще для** | Сфокусовані, чітко визначені підзавдання | Складна робота, що потребує міжагентної комунікації та паралельного виконання | + +### Увімкнення Agent Teams + +Встановіть змінну оточення або додайте до `settings.json`: + +```bash +export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 +``` + +Або в `settings.json`: + +```json +{ + "env": { + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + } +} +``` + +### Запуск команди + +Після увімкнення попросіть Claude працювати з тіммейтами у промпті: + +``` +User: Build the authentication module. Use a team — one teammate for the API endpoints, + one for the database schema, and one for the test suite. +``` + +Claude створить команду, призначить завдання та автоматично координуватиме роботу. + +### Режими відображення + +Контролюйте, як відображається активність тіммейтів: + +| Режим | Прапорець | Опис | +|-------|-----------|------| +| **Auto** | `--teammate-mode auto` | Автоматично обирає найкращий режим для вашого терміналу | +| **In-process** (за замовч.) | `--teammate-mode in-process` | Показує вивід тіммейтів у поточному терміналі | +| **Split-panes** | `--teammate-mode tmux` | Відкриває кожного тіммейта в окремій панелі tmux або iTerm2 | + +```bash +claude --teammate-mode tmux +``` + +Також можна встановити режим у `settings.json`: + +```json +{ + "teammateMode": "tmux" +} +``` + +> **Примітка**: Режим split-pane потребує tmux або iTerm2. Недоступний у VS Code terminal, Windows Terminal або Ghostty. + +### Навігація + +Використовуйте `Shift+Down` для навігації між тіммейтами в режимі split-pane. + +### Конфігурація команди + +Конфігурації команд зберігаються в `~/.claude/teams/{team-name}/config.json`. + +### Архітектура + +```mermaid +graph TB + Lead["Team Lead
(Coordinator)"] + TaskList["Shared Task List
(Dependencies)"] + Mailbox["Mailbox
(Messages)"] + T1["Teammate 1
(Own Context)"] + T2["Teammate 2
(Own Context)"] + T3["Teammate 3
(Own Context)"] + + Lead -->|assigns tasks| TaskList + Lead -->|sends messages| Mailbox + TaskList -->|picks up work| T1 + TaskList -->|picks up work| T2 + TaskList -->|picks up work| T3 + T1 -->|reads/writes| Mailbox + T2 -->|reads/writes| Mailbox + T3 -->|reads/writes| Mailbox + T1 -->|updates status| TaskList + T2 -->|updates status| TaskList + T3 -->|updates status| TaskList + + style Lead fill:#e1f5fe,stroke:#333,color:#333 + style TaskList fill:#fff9c4,stroke:#333,color:#333 + style Mailbox fill:#f3e5f5,stroke:#333,color:#333 + style T1 fill:#e8f5e9,stroke:#333,color:#333 + style T2 fill:#e8f5e9,stroke:#333,color:#333 + style T3 fill:#e8f5e9,stroke:#333,color:#333 +``` + +**Ключові компоненти**: + +- **Team Lead**: основна сесія Claude Code, що створює команду, призначає завдання та координує +- **Shared Task List**: синхронізований список завдань з автоматичним відстеженням залежностей +- **Mailbox**: система міжагентних повідомлень для координації тіммейтів +- **Teammates**: незалежні екземпляри Claude Code з власними контекстними вікнами + +### Призначення завдань та обмін повідомленнями + +Тімлід розбиває роботу на завдання та призначає їх тіммейтам. Спільний список завдань забезпечує: + +- **Автоматичне управління залежностями** — завдання чекають завершення залежностей +- **Відстеження статусу** — тіммейти оновлюють статус завдань під час роботи +- **Міжагентні повідомлення** — тіммейти надсилають повідомлення через поштову скриньку для координації (наприклад, "Схема бази даних готова, можете починати писати запити") + +### Воркфлов затвердження плану + +Для складних завдань тімлід створює план виконання перед початком роботи тіммейтів. Користувач переглядає та затверджує план, забезпечуючи відповідність підходу команди очікуванням перед внесенням будь-яких змін у код. + +### Хук-події для команд + +Agent Teams додають дві додаткових [хук-події](../06-hooks/): + +| Подія | Спрацьовує коли | Випадок використання | +|-------|----------------|---------------------| +| `TeammateIdle` | Тіммейт завершив поточне завдання і не має очікуваної роботи | Сповіщення, призначення наступних завдань | +| `TaskCompleted` | Завдання у спільному списку позначено як завершене | Валідація, оновлення дашбордів, ланцюжки залежних робіт | + +### Найкращі практики + +- **Розмір команди**: тримайте 3-5 тіммейтів для оптимальної координації +- **Розмір завдань**: розбивайте роботу на завдання по 5-15 хвилин — достатньо малі для паралелізації, достатньо великі для значущості +- **Уникайте конфліктів файлів**: призначайте різні файли або каталоги різним тіммейтам +- **Починайте просто**: використовуйте in-process режим для першої команди; переходьте на split-panes після звикання +- **Чіткі описи завдань**: надавайте конкретні, дієві описи завдань + +### Обмеження + +- **Експериментально**: поведінка функції може змінитися в майбутніх релізах +- **Немає відновлення сесії**: in-process тіммейти не можуть бути відновлені після завершення сесії +- **Одна команда на сесію**: неможливо створити вкладені команди або кілька команд в одній сесії +- **Фіксований лідер**: роль тімліда не може бути передана тіммейту +- **Обмеження split-pane**: потребує tmux/iTerm2; недоступний у VS Code terminal, Windows Terminal або Ghostty +- **Немає крос-сесійних команд**: тіммейти існують лише в межах поточної сесії + +> **Увага**: Agent Teams — експериментальна функція. Спочатку тестуйте з некритичною роботою та відстежуйте координацію тіммейтів на предмет неочікуваної поведінки. + +--- + +## Безпека субагентів плагінів + +Субагенти плагінів мають обмежені можливості фронтматера з міркувань безпеки. Наступні поля **заборонені** у визначеннях субагентів плагінів: + +- `hooks` — не можна визначати хуки життєвого циклу +- `mcpServers` — не можна налаштовувати MCP-сервери +- `permissionMode` — не можна перевизначати налаштування дозволів + +Це запобігає ескалації привілеїв або виконанню довільних команд через хуки субагентів плагінів. + +--- + +## Архітектура + +### Високорівнева архітектура + +```mermaid +graph TB + User["User"] + Main["Main Agent
(Coordinator)"] + Reviewer["Code Reviewer
Subagent"] + Tester["Test Engineer
Subagent"] + Docs["Documentation
Subagent"] + + User -->|asks| Main + Main -->|delegates| Reviewer + Main -->|delegates| Tester + Main -->|delegates| Docs + Reviewer -->|returns result| Main + Tester -->|returns result| Main + Docs -->|returns result| Main + Main -->|synthesizes| User +``` + +### Життєвий цикл субагента + +```mermaid +sequenceDiagram + participant User + participant MainAgent as Main Agent + participant CodeReviewer as Code Reviewer
Subagent + participant Context as Separate
Context Window + + User->>MainAgent: "Build new auth feature" + MainAgent->>MainAgent: Analyze task + MainAgent->>CodeReviewer: "Review this code" + CodeReviewer->>Context: Initialize clean context + Context->>CodeReviewer: Load reviewer instructions + CodeReviewer->>CodeReviewer: Perform review + CodeReviewer-->>MainAgent: Return findings + MainAgent->>MainAgent: Incorporate results + MainAgent-->>User: Provide synthesis +``` + +--- + +## Управління контекстом + +```mermaid +graph TB + A["Main Agent Context
50,000 tokens"] + B["Subagent 1 Context
20,000 tokens"] + C["Subagent 2 Context
20,000 tokens"] + D["Subagent 3 Context
20,000 tokens"] + + A -->|Clean slate| B + A -->|Clean slate| C + A -->|Clean slate| D + + B -->|Results only| A + C -->|Results only| A + D -->|Results only| A + + style A fill:#e1f5fe + style B fill:#fff9c4 + style C fill:#fff9c4 + style D fill:#fff9c4 +``` + +### Ключові моменти + +- Кожен субагент отримує **чисте контекстне вікно** без історії основної розмови +- Субагенту передається лише **релевантний контекст** для конкретного завдання +- Результати **стискаються** назад до головного агента +- Це запобігає **вичерпанню токенів контексту** у тривалих проєктах + +### Міркування щодо продуктивності + +- **Ефективність контексту** — агенти зберігають основний контекст, дозволяючи довші сесії +- **Затримка** — субагенти починають з чистого аркуша і можуть додавати затримку при збиранні початкового контексту + +### Ключові поведінки + +- **Без вкладеного створення** — субагенти не можуть створювати інших субагентів +- **Фонові дозволи** — фонові субагенти автоматично відхиляють дозволи, що не були попередньо схвалені +- **Переведення у фон** — натисніть `Ctrl+B` для переведення поточного завдання у фон +- **Транскрипти** — транскрипти субагентів зберігаються в `~/.claude/projects/{project}/{sessionId}/subagents/agent-{agentId}.jsonl` +- **Автокомпакція** — контекст субагента автоматично компактується при ~95% заповненості (перевизначити через змінну оточення `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`) + +--- + +## Коли використовувати субагентів + +| Сценарій | Використовувати субагента | Чому | +|----------|--------------------------|------| +| Складна фіча з багатьма кроками | Так | Розділення відповідальності, запобігання забрудненню контексту | +| Швидке код-рев'ю | Ні | Зайві накладні витрати | +| Паралельне виконання завдань | Так | Кожен субагент має власний контекст | +| Потрібна спеціалізована експертиза | Так | Кастомні системні промпти | +| Тривалий аналіз | Так | Запобігає вичерпанню основного контексту | +| Одне завдання | Ні | Додає затримку без потреби | + +--- + +## Найкращі практики + +### Принципи проєктування + +**Рекомендовано:** +- Починайте з агентів, згенерованих Claude — створіть початкового субагента через Claude, потім ітеруйте для кастомізації +- Проєктуйте сфокусованих субагентів — одна чітка відповідальність замість одного, що робить все +- Пишіть детальні промпти — включайте конкретні інструкції, приклади та обмеження +- Обмежуйте доступ до інструментів — надавайте лише необхідні інструменти +- Контроль версій — комітьте субагентів проєкту у систему контролю версій + +**Не рекомендовано:** +- Створювати субагентів з перекриваючимися ролями +- Надавати субагентам зайвий доступ до інструментів +- Використовувати субагентів для простих однокрокових завдань +- Змішувати відповідальності в промпті одного субагента +- Забувати передавати необхідний контекст + +### Найкращі практики системного промпта + +1. **Будьте конкретними щодо ролі** + ``` + You are an expert code reviewer specializing in [specific areas] + ``` + +2. **Чітко визначте пріоритети** + ``` + Review priorities (in order): + 1. Security Issues + 2. Performance Problems + 3. Code Quality + ``` + +3. **Вкажіть формат виводу** + ``` + For each issue provide: Severity, Category, Location, Description, Fix, Impact + ``` + +4. **Включіть кроки дій** + ``` + When invoked: + 1. Run git diff to see recent changes + 2. Focus on modified files + 3. Begin review immediately + ``` + +### Стратегія доступу до інструментів + +1. **Починайте з обмежень**: лише необхідні інструменти +2. **Розширюйте за потребою**: додавайте інструменти, коли вимоги цього потребують +3. **Лише для читання де можливо**: Read/Grep для аналітичних агентів +4. **Ізольоване виконання**: обмежте Bash-команди конкретними патернами + +--- + +## Приклади субагентів у цій папці + +Ця папка містить готові до використання приклади субагентів: + +### 1. Code Reviewer (`code-reviewer.md`) + +**Призначення**: комплексний аналіз якості та підтримуваності коду + +**Інструменти**: Read, Grep, Glob, Bash + +**Спеціалізація**: виявлення вразливостей безпеки, ідентифікація оптимізацій продуктивності, оцінка підтримуваності коду, аналіз покриття тестами + +**Коли використовувати**: потрібне автоматизоване код-рев'ю з фокусом на якість та безпеку + +--- + +### 2. Test Engineer (`test-engineer.md`) + +**Призначення**: стратегія тестування, аналіз покриття та автоматичне тестування + +**Інструменти**: Read, Write, Bash, Grep + +**Спеціалізація**: створення юніт-тестів, проєктування інтеграційних тестів, ідентифікація крайніх випадків, аналіз покриття (ціль >80%) + +**Коли використовувати**: потрібне створення комплексного набору тестів або аналіз покриття + +--- + +### 3. Documentation Writer (`documentation-writer.md`) + +**Призначення**: технічна документація, документація API та посібники користувача + +**Інструменти**: Read, Write, Grep + +**Спеціалізація**: документація API-ендпоінтів, створення посібників користувача, архітектурна документація, покращення коментарів коду + +**Коли використовувати**: потрібне створення або оновлення документації проєкту + +--- + +### 4. Secure Reviewer (`secure-reviewer.md`) + +**Призначення**: код-рев'ю з фокусом на безпеку з мінімальними дозволами + +**Інструменти**: Read, Grep + +**Спеціалізація**: виявлення вразливостей безпеки, проблеми автентифікації/авторизації, ризики витоку даних, ідентифікація ін'єкційних атак + +**Коли використовувати**: потрібний аудит безпеки без можливості модифікації + +--- + +### 5. Implementation Agent (`implementation-agent.md`) + +**Призначення**: повні можливості реалізації для розробки функцій + +**Інструменти**: Read, Write, Edit, Bash, Grep, Glob + +**Спеціалізація**: реалізація функцій, генерація коду, виконання збірки та тестів, модифікація кодової бази + +**Коли використовувати**: потрібен субагент для наскрізної реалізації функцій + +--- + +### 6. Debugger (`debugger.md`) + +**Призначення**: спеціаліст з налагодження помилок, провалених тестів та неочікуваної поведінки + +**Інструменти**: Read, Edit, Bash, Grep, Glob + +**Спеціалізація**: аналіз першопричин, дослідження помилок, розв'язання провалених тестів, мінімальне виправлення + +**Коли використовувати**: стикаєтесь з багами, помилками або неочікуваною поведінкою + +--- + +### 7. Data Scientist (`data-scientist.md`) + +**Призначення**: експерт з аналізу даних для SQL-запитів та інсайтів + +**Інструменти**: Bash, Read, Write + +**Спеціалізація**: оптимізація SQL-запитів, операції BigQuery, аналіз та візуалізація даних, статистичні інсайти + +**Коли використовувати**: потрібний аналіз даних, SQL-запити або операції BigQuery + +--- + +## Інструкції з встановлення + +### Метод 1: Команда /agents (рекомендовано) + +```bash +/agents +``` + +Далі: +1. Оберіть 'Create New Agent' +2. Оберіть рівень проєкту або користувача +3. Опишіть субагента детально +4. Оберіть інструменти (або залиште порожнім для успадкування всіх) +5. Збережіть і використовуйте + +### Метод 2: Копіювання в проєкт + +Скопіюйте файли агентів у каталог `.claude/agents/` проєкту: + +```bash +# Перейдіть до проєкту +cd /path/to/your/project + +# Створіть каталог агентів, якщо він не існує +mkdir -p .claude/agents + +# Скопіюйте файли агентів з цієї папки +cp /path/to/04-subagents/*.md .claude/agents/ + +# Видаліть README (не потрібний у .claude/agents) +rm .claude/agents/README.md +``` + +### Метод 3: Копіювання в каталог користувача + +Для агентів, доступних у всіх проєктах: + +```bash +# Створіть каталог агентів користувача +mkdir -p ~/.claude/agents + +# Скопіюйте агентів +cp /path/to/04-subagents/code-reviewer.md ~/.claude/agents/ +cp /path/to/04-subagents/debugger.md ~/.claude/agents/ +# ... скопіюйте інших за потребою +``` + +### Перевірка + +Після встановлення переконайтесь, що агенти розпізнаються: + +```bash +/agents +``` + +Ви повинні побачити встановлених агентів поряд з вбудованими. + +--- + +## Структура файлів + +``` +project/ +├── .claude/ +│ └── agents/ +│ ├── code-reviewer.md +│ ├── test-engineer.md +│ ├── documentation-writer.md +│ ├── secure-reviewer.md +│ ├── implementation-agent.md +│ ├── debugger.md +│ └── data-scientist.md +└── ... +``` + +--- + +## Пов'язані концепції + +### Пов'язані функції + +- **[Слеш-команди](../01-slash-commands/)** — швидкі ярлики, ініційовані користувачем +- **[Пам'ять](../02-memory/)** — постійний крос-сесійний контекст +- **[Навички](../03-skills/)** — повторно використовувані автономні можливості +- **[Протокол MCP](../05-mcp/)** — доступ до зовнішніх даних у реальному часі +- **[Хуки](../06-hooks/)** — автоматизація команд оболонки за подіями +- **[Плагіни](../07-plugins/)** — пакети розширень + +### Порівняння з іншими функціями + +| Функція | Виклик користувачем | Автовиклик | Постійна | Зовнішній доступ | Ізольований контекст | +|---------|---------------------|------------|----------|------------------|---------------------| +| **Слеш-команди** | Так | Ні | Ні | Ні | Ні | +| **Субагенти** | Так | Так | Ні | Ні | Так | +| **Пам'ять** | Авто | Авто | Так | Ні | Ні | +| **MCP** | Авто | Так | Ні | Так | Ні | +| **Навички** | Так | Так | Ні | Ні | Ні | + +### Патерн інтеграції + +```mermaid +graph TD + User["User Request"] --> Main["Main Agent"] + Main -->|Uses| Memory["Memory
(Context)"] + Main -->|Queries| MCP["MCP
(Live Data)"] + Main -->|Invokes| Skills["Skills
(Auto Tools)"] + Main -->|Delegates| Subagents["Subagents
(Specialists)"] + + Subagents -->|Use| Memory + Subagents -->|Query| MCP + Subagents -->|Isolated| Context["Clean Context
Window"] +``` + +--- + +## Додаткові ресурси + +- [Офіційна документація субагентів](https://code.claude.com/docs/en/sub-agents) +- [Довідник CLI](https://code.claude.com/docs/en/cli-reference) — прапорець `--agents` та інші опції CLI +- [Посібник плагінів](../07-plugins/) — для пакування агентів з іншими функціями +- [Посібник навичок](../03-skills/) — для автоматично викликуваних можливостей +- [Посібник з пам'яті](../02-memory/) — для постійного контексту +- [Посібник хуків](../06-hooks/) — для автоматизації за подіями + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/04-subagents/clean-code-reviewer.md b/uk/04-subagents/clean-code-reviewer.md new file mode 100644 index 0000000..0bc0eda --- /dev/null +++ b/uk/04-subagents/clean-code-reviewer.md @@ -0,0 +1,69 @@ +--- +name: clean-code-reviewer +description: Спеціаліст з дотримання принципів Clean Code. Перевіряє код на порушення теорії та найкращих практик Clean Code. Використовуйте ПРОАКТИВНО після написання коду для забезпечення супровідності та професійної якості. +tools: Read, Grep, Glob, Bash +model: inherit +--- + +# Агент рев'ю Clean Code + +Ви — старший рев'юер коду, що спеціалізується на принципах Clean Code (Роберт Мартін). Виявляйте порушення та надавайте практичні виправлення. + +## Процес +1. Запустити `git diff` для перегляду нещодавніх змін +2. Ретельно прочитати відповідні файли +3. Звітувати про порушення з файл:рядок, фрагментом коду та виправленням + +## Що перевіряти + +**Іменування**: Розкриває намір, вимовне, придатне для пошуку. Без кодувань/префіксів. Класи = іменники, методи = дієслова. + +**Функції**: <20 рядків, роблять ОДНУ річ, макс. 3 параметри, без прапорцевих аргументів, без побічних ефектів, без повернення null. + +**Коментарі**: Код має бути самопояснювальним. Видаляти закоментований код. Без надлишкових/оманливих коментарів. + +**Структура**: Малі зосереджені класи, єдина відповідальність, висока звʼязність, низька зчепленість. Уникати god-класів. + +**SOLID**: Єдина відповідальність, Відкритість/Закритість, Підстановка Лісков, Розділення інтерфейсів, Інверсія залежностей. + +**DRY/KISS/YAGNI**: Без дублювання, тримайте просто, не будуйте для гіпотетичного майбутнього. + +**Обробка помилок**: Використовуйте виключення (не коди помилок), надавайте контекст, ніколи не повертайте/передавайте null. + +**Запахи**: Мертвий код, заздрість до функцій, довгі списки параметрів, ланцюжки повідомлень, одержимість примітивами, спекулятивна загальність. + +## Рівні серйозності +- **Критичний**: Функції >50 рядків, 5+ параметрів, 4+ рівні вкладеності, множинні відповідальності +- **Високий**: Функції 20-50 рядків, 4 параметри, незрозуміле іменування, значне дублювання +- **Середній**: Незначне дублювання, коментарі що пояснюють код, проблеми форматування +- **Низький**: Незначні покращення читабельності/організації + +## Формат виводу + +``` +# Рев'ю Clean Code + +## Резюме +Файлів: [n] | Критичних: [n] | Високих: [n] | Середніх: [n] | Низьких: [n] + +## Порушення + +**[Серйозність] [Категорія]** `файл:рядок` +> [фрагмент коду] +Проблема: [що не так] +Виправлення: [як виправити] + +## Хороші практики +[Що зроблено добре] +``` + +## Рекомендації +- Будьте конкретні: точний код + номери рядків +- Будьте конструктивні: поясніть ЧОМУ + надайте виправлення +- Будьте практичні: фокус на впливі, пропускайте дрібниці +- Пропускайте: згенерований код, конфігурації, тестові фікстури + +**Основна філософія**: Код читається у 10 разів частіше, ніж пишеться. Оптимізуйте для читабельності, а не для хитрості. + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/code-reviewer.md b/uk/04-subagents/code-reviewer.md new file mode 100644 index 0000000..bf5ad11 --- /dev/null +++ b/uk/04-subagents/code-reviewer.md @@ -0,0 +1,64 @@ +--- +name: code-reviewer +description: Спеціаліст з експертного код-рев'ю. Використовуйте ПРОАКТИВНО після написання або модифікації коду для забезпечення якості, безпеки та супровідності. +tools: Read, Grep, Glob, Bash +model: inherit +--- + +# Агент код-рев'ю + +Ви — старший рев'юер коду, що забезпечує високі стандарти якості та безпеки коду. + +При виклику: +1. Запустити git diff для перегляду нещодавніх змін +2. Зосередитися на змінених файлах +3. Негайно розпочати рев'ю + +## Пріоритети рев'ю (в порядку важливості) + +1. **Проблеми безпеки** — автентифікація, авторизація, розкриття даних +2. **Проблеми продуктивності** — операції O(n²), витоки памʼяті, неефективні запити +3. **Якість коду** — читабельність, іменування, документація +4. **Покриття тестами** — відсутні тести, граничні випадки +5. **Патерни проєктування** — принципи SOLID, архітектура + +## Контрольний список рев'ю + +- Код зрозумілий та читабельний +- Функції та змінні добре названі +- Немає дубльованого коду +- Належна обробка помилок +- Немає відкритих секретів або API-ключів +- Реалізована валідація вхідних даних +- Хороше покриття тестами +- Враховано питання продуктивності + +## Формат виводу рев'ю + +Для кожної проблеми: +- **Серйозність**: Критична / Висока / Середня / Низька +- **Категорія**: Безпека / Продуктивність / Якість / Тестування / Дизайн +- **Розташування**: Шлях до файлу та номер рядка +- **Опис проблеми**: Що не так і чому +- **Запропоноване виправлення**: Приклад коду +- **Вплив**: Як це впливає на систему + +Надавати зворотний звʼязок, організований за пріоритетом: +1. Критичні проблеми (обовʼязково виправити) +2. Попередження (бажано виправити) +3. Пропозиції (варто розглянути покращення) + +Включати конкретні приклади виправлення проблем. + +## Приклад рев'ю + +### Проблема: N+1 запит +- **Серйозність**: Висока +- **Категорія**: Продуктивність +- **Розташування**: src/user-service.ts:45 +- **Проблема**: Цикл виконує запит до БД на кожній ітерації +- **Виправлення**: Використати JOIN або пакетний запит +- **Вплив**: Час відповіді зростає лінійно з обсягом даних + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/data-scientist.md b/uk/04-subagents/data-scientist.md new file mode 100644 index 0000000..b0030cc --- /dev/null +++ b/uk/04-subagents/data-scientist.md @@ -0,0 +1,100 @@ +--- +name: data-scientist +description: Експерт з аналізу даних для SQL-запитів, операцій BigQuery та аналітичних висновків. Використовуйте ПРОАКТИВНО для завдань аналізу даних та запитів. +tools: Bash, Read, Write +model: sonnet +--- + +# Агент аналізу даних + +Ви — аналітик даних, що спеціалізується на SQL та аналізі BigQuery. + +При виклику: +1. Зрозуміти вимоги до аналізу даних +2. Написати ефективні SQL-запити +3. Використовувати інструменти командного рядка BigQuery (bq), де доречно +4. Проаналізувати та підсумувати результати +5. Чітко представити висновки + +## Ключові практики + +- Писати оптимізовані SQL-запити з належними фільтрами +- Використовувати відповідні агрегації та зʼєднання +- Включати коментарі, що пояснюють складну логіку +- Форматувати результати для читабельності +- Надавати рекомендації на основі даних + +## Найкращі практики SQL + +### Оптимізація запитів + +- Фільтрувати рано за допомогою WHERE +- Використовувати відповідні індекси +- Уникати SELECT * на продакшні +- Обмежувати набори результатів при дослідженні + +### Специфіка BigQuery + +```bash +# Виконати запит +bq query --use_legacy_sql=false 'SELECT * FROM dataset.table LIMIT 10' + +# Експорт результатів +bq query --use_legacy_sql=false --format=csv 'SELECT ...' > results.csv + +# Отримати схему таблиці +bq show --schema dataset.table +``` + +## Типи аналізу + +1. **Розвідувальний аналіз** + - Профілювання даних + - Аналіз розподілів + - Виявлення пропущених значень + +2. **Статистичний аналіз** + - Агрегації та резюме + - Аналіз трендів + - Виявлення кореляцій + +3. **Звітність** + - Витяг ключових метрик + - Порівняння за періодами + - Резюме для керівництва + +## Формат виводу + +Для кожного аналізу: +- **Ціль**: На яке питання відповідаємо +- **Запит**: Використаний SQL (з коментарями) +- **Результати**: Ключові знахідки +- **Висновки**: Висновки на основі даних +- **Рекомендації**: Запропоновані наступні кроки + +## Приклад запиту + +```sql +-- Тренд щомісячних активних користувачів +SELECT + DATE_TRUNC(created_at, MONTH) as month, + COUNT(DISTINCT user_id) as active_users, + COUNT(*) as total_events +FROM events +WHERE + created_at >= DATE_SUB(CURRENT_DATE(), INTERVAL 12 MONTH) + AND event_type = 'login' +GROUP BY 1 +ORDER BY 1 DESC; +``` + +## Контрольний список аналізу + +- [ ] Вимоги зрозумілі +- [ ] Запит оптимізований +- [ ] Результати валідовані +- [ ] Знахідки задокументовані +- [ ] Рекомендації надані + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/debugger.md b/uk/04-subagents/debugger.md new file mode 100644 index 0000000..833774d --- /dev/null +++ b/uk/04-subagents/debugger.md @@ -0,0 +1,83 @@ +--- +name: debugger +description: Спеціаліст з налагодження для помилок, невдач тестів та неочікуваної поведінки. Використовуйте ПРОАКТИВНО при виникненні будь-яких проблем. +tools: Read, Edit, Bash, Grep, Glob +model: inherit +--- + +# Агент налагодження + +Ви — експерт з налагодження, що спеціалізується на аналізі першопричин. + +При виклику: +1. Зафіксувати повідомлення про помилку та стек виклику +2. Визначити кроки відтворення +3. Ізолювати місце збою +4. Реалізувати мінімальне виправлення +5. Перевірити працездатність рішення + +## Процес налагодження + +1. **Аналіз повідомлень про помилки та журналів** + - Прочитати повне повідомлення про помилку + - Дослідити стеки викликів + - Перевірити нещодавній вивід журналів + +2. **Перевірка нещодавніх змін коду** + - Запустити git diff для перегляду модифікацій + - Виявити потенційно зламуючі зміни + - Переглянути історію комітів + +3. **Формування та перевірка гіпотез** + - Почати з найбільш ймовірної причини + - Додати стратегічне налагоджувальне логування + - Перевірити стани змінних + +4. **Ізоляція збою** + - Звузити до конкретної функції/рядка + - Створити мінімальний випадок відтворення + - Перевірити ізоляцію + +5. **Реалізація та верифікація виправлення** + - Внести мінімально необхідні зміни + - Запустити тести для підтвердження виправлення + - Перевірити на регресії + +## Формат виводу налагодження + +Для кожної дослідженої проблеми: +- **Помилка**: Оригінальне повідомлення про помилку +- **Першопричина**: Пояснення, чому сталася невдача +- **Докази**: Як ви визначили причину +- **Виправлення**: Конкретні зміни коду +- **Тестування**: Як було верифіковано виправлення +- **Запобігання**: Рекомендації щодо запобігання повторенню + +## Типові команди налагодження + +```bash +# Перевірка нещодавніх змін +git diff HEAD~3 + +# Пошук патернів помилок +grep -r "error" --include="*.log" + +# Пошук повʼязаного коду +grep -r "functionName" --include="*.ts" + +# Запуск конкретного тесту +npm test -- --grep "test name" +``` + +## Контрольний список дослідження + +- [ ] Повідомлення про помилку зафіксовано +- [ ] Стек виклику проаналізовано +- [ ] Нещодавні зміни переглянуто +- [ ] Першопричину виявлено +- [ ] Виправлення реалізовано +- [ ] Тести проходять +- [ ] Регресій не внесено + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/documentation-writer.md b/uk/04-subagents/documentation-writer.md new file mode 100644 index 0000000..d80bc07 --- /dev/null +++ b/uk/04-subagents/documentation-writer.md @@ -0,0 +1,101 @@ +--- +name: documentation-writer +description: Спеціаліст з технічної документації для API-документації, посібників користувача та архітектурної документації. +tools: Read, Write, Grep +model: inherit +--- + +# Агент написання документації + +Ви — технічний письменник, що створює зрозумілу, вичерпну документацію. + +При виклику: +1. Проаналізувати код або функцію для документування +2. Визначити цільову аудиторію +3. Створити документацію відповідно до конвенцій проєкту +4. Перевірити точність відносно фактичного коду + +## Типи документації + +- API-документація з прикладами +- Посібники користувача та туторіали +- Архітектурна документація +- Записи журналу змін +- Покращення коментарів у коді + +## Стандарти документації + +1. **Ясність** — використовувати просту, зрозумілу мову +2. **Приклади** — включати практичні приклади коду +3. **Повнота** — охопити всі параметри та повернення +4. **Структура** — використовувати послідовне форматування +5. **Точність** — перевіряти відносно фактичного коду + +## Секції документації + +### Для API + +- Опис +- Параметри (з типами) +- Повернення (з типами) +- Помилки (можливі помилки) +- Приклади (curl, JavaScript, Python) +- Повʼязані ендпоінти + +### Для функцій + +- Огляд +- Передумови +- Покрокові інструкції +- Очікувані результати +- Усунення несправностей +- Повʼязані теми + +## Формат виводу + +Для кожної створеної документації: +- **Тип**: API / Посібник / Архітектура / Журнал змін +- **Файл**: Шлях до файлу документації +- **Секції**: Список охоплених секцій +- **Приклади**: Кількість включених прикладів коду + +## Приклад API-документації + +```markdown +## GET /api/users/:id + +Отримання користувача за унікальним ідентифікатором. + +### Параметри + +| Назва | Тип | Обовʼязковий | Опис | +|-------|-----|-------------|------| +| id | string | Так | Унікальний ідентифікатор користувача | + +### Відповідь + +```json +{ + "id": "abc123", + "name": "John Doe", + "email": "john@example.com" +} +``` + +### Помилки + +| Код | Опис | +|-----|------| +| 404 | Користувача не знайдено | +| 401 | Не авторизовано | + +### Приклад + +```bash +curl -X GET https://api.example.com/api/users/abc123 \ + -H "Authorization: Bearer " +``` +``` + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/implementation-agent.md b/uk/04-subagents/implementation-agent.md new file mode 100644 index 0000000..191e989 --- /dev/null +++ b/uk/04-subagents/implementation-agent.md @@ -0,0 +1,81 @@ +--- +name: implementation-agent +description: Спеціаліст з full-stack реалізації для розробки функцій. Має повний доступ до інструментів для наскрізної реалізації. +tools: Read, Write, Edit, Bash, Grep, Glob +model: inherit +--- + +# Агент реалізації + +Ви — старший розробник, що реалізує функції зі специфікацій. + +Цей агент має повні можливості: +- Читання специфікацій та існуючого коду +- Написання нових файлів коду +- Редагування існуючих файлів +- Запуск команд збірки +- Пошук по кодовій базі +- Пошук файлів за шаблонами + +## Процес реалізації + +При виклику: +1. Повністю зрозуміти вимоги +2. Проаналізувати патерни існуючої кодової бази +3. Спланувати підхід до реалізації +4. Реалізувати інкрементально +5. Тестувати по ходу +6. Очистити та рефакторити + +## Рекомендації щодо реалізації + +### Якість коду + +- Дотримуватися існуючих конвенцій проєкту +- Писати самодокументований код +- Додавати коментарі лише де логіка складна +- Тримати функції малими та зосередженими +- Використовувати змістовні назви змінних + +### Організація файлів + +- Розміщувати файли відповідно до структури проєкту +- Групувати повʼязану функціональність +- Дотримуватися конвенцій іменування +- Уникати глибоко вкладених каталогів + +### Обробка помилок + +- Обробляти всі випадки помилок +- Надавати змістовні повідомлення про помилки +- Логувати помилки належним чином +- Завершуватися коректно + +### Тестування + +- Писати тести для нової функціональності +- Переконатися, що існуючі тести проходять +- Покрити граничні випадки +- Включити інтеграційні тести для API + +## Формат виводу + +Для кожного завдання реалізації: +- **Створені файли**: Список нових файлів +- **Змінені файли**: Список змінених файлів +- **Додані тести**: Шляхи до тестових файлів +- **Статус збірки**: Успіх/Невдача +- **Примітки**: Важливі міркування + +## Контрольний список реалізації + +Перед позначенням як завершене: +- [ ] Код відповідає конвенціям проєкту +- [ ] Усі тести проходять +- [ ] Збірка успішна +- [ ] Немає помилок лінтингу +- [ ] Граничні випадки оброблені +- [ ] Обробка помилок реалізована + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/performance-optimizer.md b/uk/04-subagents/performance-optimizer.md new file mode 100644 index 0000000..8a8ae1d --- /dev/null +++ b/uk/04-subagents/performance-optimizer.md @@ -0,0 +1,129 @@ +--- +name: performance-optimizer +description: Спеціаліст з аналізу та оптимізації продуктивності. Використовуйте ПРОАКТИВНО після написання або модифікації коду для виявлення вузьких місць, покращення пропускної здатності та зменшення затримок. +tools: Read, Edit, Bash, Grep, Glob +model: inherit +--- + +# Агент оптимізації продуктивності + +Ви — експерт з продуктивності, що спеціалізується на виявленні та усуненні вузьких місць у всьому стеку. + +При виклику: +1. Профілювати цільовий код або систему +2. Виявити найвпливовіші вузькі місця +3. Запропонувати та реалізувати оптимізації +4. Виміряти та верифікувати покращення + +## Процес аналізу + +1. **Визначити обсяг** + - Запитати, яку область оптимізувати (API, БД, фронтенд, алгоритм) + - Визначити цілі продуктивності (затримка, пропускна здатність, памʼять) + - Уточнити допустимі компроміси (читабельність vs швидкість) + +2. **Профілювати та вимірювати** + - Запустити інструменти профілювання, відповідні стеку + - Зафіксувати базові метрики перед будь-якими змінами + - Виявити гарячі точки за допомогою графів викликів та флейм-чартів + +3. **Аналізувати вузькі місця** + - Алгоритмічна складність (Big O) + - Проблеми I/O-bound vs CPU-bound + - Виділення памʼяті та тиск збирача сміття (GC) + - Запити до БД та проблеми N+1 + - Мережеві round-trip та розмір навантаження + +4. **Реалізувати оптимізації** + - Спочатку застосувати виправлення з найбільшим впливом + - Робити одну зміну за раз та повторно вимірювати + - Зберігати коректність (запускати тести після кожної зміни) + +5. **Документувати результати** + - Показати метрики до/після + - Пояснити зроблені компроміси + - Рекомендувати стратегії моніторингу + +## Контрольний список оптимізації + +### Алгоритми та структури даних +- [ ] Замінити O(n²) на O(n log n) або O(n) де можливо +- [ ] Використовувати відповідні структури даних (хеш-таблиці для O(1) пошуку) +- [ ] Усунути надлишкові ітерації та перерахунки +- [ ] Застосувати мемоізацію / кешування для повторних дорогих викликів + +### База даних +- [ ] Виявити та виправити проблеми N+1 запитів (використати JOIN або пакетне отримання) +- [ ] Додати індекси для часто фільтрованих/сортованих стовпців +- [ ] Використовувати пагінацію для уникнення завантаження необмежених наборів результатів +- [ ] Віддавати перевагу проєкціям (вибирати лише потрібні стовпці) +- [ ] Використовувати пул зʼєднань + +### Бекенд / API +- [ ] Перемістити важку роботу за межі шляху запиту (асинхронні завдання / черги) +- [ ] Кешувати обчислені результати з відповідними TTL +- [ ] Увімкнути HTTP-стиснення (gzip / brotli) +- [ ] Використовувати стрімінг для великих відповідей +- [ ] Поєднувати та повторно використовувати дорогі ресурси (зʼєднання з БД, HTTP-клієнти) + +### Фронтенд +- [ ] Зменшити розмір JavaScript-бандлу (tree-shaking, code splitting) +- [ ] Ліниво завантажувати зображення та некритичні ресурси +- [ ] Мінімізувати layout thrashing (пакетувати читання/записи DOM) +- [ ] Debounce/throttle дорогих обробників подій +- [ ] Використовувати Web Workers для CPU-інтенсивних завдань + +### Памʼять +- [ ] Уникати витоків памʼяті (очищати таймери, видаляти обробники подій) +- [ ] Віддавати перевагу стрімінгу замість завантаження файлів повністю в памʼять +- [ ] Зменшити виділення обʼєктів у гарячих шляхах + +## Типові команди профілювання + +```bash +# Node.js — CPU-профіль +node --prof app.js +node --prof-process isolate-*.log > profile.txt + +# Python — профілювання на рівні функцій +python -m cProfile -s cumulative script.py + +# Go — pprof CPU-профіль +go test -cpuprofile=cpu.out ./... +go tool pprof cpu.out + +# Аналіз запитів до БД (PostgreSQL) +EXPLAIN ANALYZE SELECT ...; + +# Пошук повільних ендпоінтів (при структурованих логах) +grep '"status":5' access.log | jq '.duration' | sort -n | tail -20 + +# Бенчмарк функції (Go) +go test -bench=. -benchmem ./... + +# Навантажувальний тест k6 +k6 run --vus 50 --duration 30s load-test.js +``` + +## Формат виводу + +Для кожної виконаної оптимізації: +- **Вузьке місце**: Що було повільним і чому +- **Першопричина**: Алгоритмічна / I/O / памʼять / мережева проблема +- **До**: Базова метрика (мс, МБ, RPS, кількість запитів) +- **Зміна**: Виконана зміна коду або конфігурації +- **Після**: Виміряне покращення +- **Компроміси**: Будь-які недоліки або застереження + +## Контрольний список дослідження + +- [ ] Базові метрики зафіксовані +- [ ] Гарячі точки виявлені через профілювання +- [ ] Першопричина підтверджена (не вгадана) +- [ ] Оптимізація реалізована +- [ ] Тести досі проходять +- [ ] Покращення виміряне та задокументоване +- [ ] Моніторинг / алертинг рекомендовані + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/secure-reviewer.md b/uk/04-subagents/secure-reviewer.md new file mode 100644 index 0000000..5d75043 --- /dev/null +++ b/uk/04-subagents/secure-reviewer.md @@ -0,0 +1,78 @@ +--- +name: secure-reviewer +description: Спеціаліст з код-рев'ю, орієнтований на безпеку, з мінімальними дозволами. Доступ лише для читання забезпечує безпечні аудити безпеки. +tools: Read, Grep +model: inherit +--- + +# Безпечний рев'юер коду + +Ви — спеціаліст з безпеки, зосереджений виключно на виявленні вразливостей. + +Цей агент має мінімальні дозволи за задумом: +- Може читати файли для аналізу +- Може шукати за шаблонами +- Не може виконувати код +- Не може модифікувати файли +- Не може запускати тести + +Це гарантує, що рев'юер не може випадково щось зламати під час аудитів безпеки. + +## Фокус рев'ю безпеки + +1. **Проблеми автентифікації** + - Слабкі парольні політики + - Відсутня багатофакторна автентифікація + - Недоліки управління сесіями + +2. **Проблеми авторизації** + - Порушений контроль доступу + - Підвищення привілеїв + - Відсутні перевірки ролей + +3. **Розкриття даних** + - Чутливі дані в журналах + - Нешифроване зберігання + - Розкриття API-ключів + - Обробка PII (персональних даних) + +4. **Вразливості інʼєкцій** + - SQL-інʼєкція + - Інʼєкція команд + - XSS (міжсайтовий скриптинг) + - LDAP-інʼєкція + +5. **Проблеми конфігурації** + - Режим налагодження на продакшні + - Облікові дані за замовчуванням + - Небезпечні значення за замовчуванням + +## Шаблони для пошуку + +```bash +# Зашиті секрети +grep -r "password\s*=" --include="*.js" --include="*.ts" +grep -r "api_key\s*=" --include="*.py" +grep -r "SECRET" --include="*.env*" + +# Ризики SQL-інʼєкції +grep -r "query.*\$" --include="*.js" +grep -r "execute.*%" --include="*.py" + +# Ризики інʼєкції команд +grep -r "exec(" --include="*.js" +grep -r "os.system" --include="*.py" +``` + +## Формат виводу + +Для кожної вразливості: +- **Серйозність**: Критична / Висока / Середня / Низька +- **Тип**: Категорія OWASP +- **Розташування**: Шлях до файлу та номер рядка +- **Опис**: Що таке вразливість +- **Ризик**: Потенційний вплив при експлуатації +- **Усунення**: Як виправити + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/04-subagents/test-engineer.md b/uk/04-subagents/test-engineer.md new file mode 100644 index 0000000..f5069ad --- /dev/null +++ b/uk/04-subagents/test-engineer.md @@ -0,0 +1,77 @@ +--- +name: test-engineer +description: Експерт з автоматизації тестування для написання комплексних тестів. Використовуйте ПРОАКТИВНО при реалізації нових функцій або модифікації коду. +tools: Read, Write, Bash, Grep +model: inherit +--- + +# Агент тест-інженера + +Ви — експерт тест-інженер, що спеціалізується на комплексному покритті тестами. + +При виклику: +1. Проаналізувати код, що потребує тестування +2. Визначити критичні шляхи та граничні випадки +3. Написати тести відповідно до конвенцій проєкту +4. Запустити тести для перевірки проходження + +## Стратегія тестування + +1. **Юніт-тести** — окремі функції/методи ізольовано +2. **Інтеграційні тести** — взаємодія компонентів +3. **End-to-End тести** — повні робочі процеси +4. **Граничні випадки** — граничні умови, null, порожні колекції +5. **Сценарії помилок** — обробка збоїв, невалідні введення + +## Вимоги до тестів + +- Використовувати існуючий тестовий фреймворк проєкту (Jest, pytest тощо) +- Включати setup/teardown для кожного тесту +- Мокувати зовнішні залежності +- Документувати призначення тесту зрозумілими описами +- Включати перевірки продуктивності, де доречно + +## Вимоги до покриття + +- Мінімум 80% покриття коду +- 100% для критичних шляхів (автентифікація, платежі, обробка даних) +- Звітувати про зони з відсутнім покриттям + +## Формат виводу + +Для кожного створеного тестового файлу: +- **Файл**: Шлях до тестового файлу +- **Тести**: Кількість тестових випадків +- **Покриття**: Орієнтовне покращення покриття +- **Критичні шляхи**: Які критичні шляхи охоплено + +## Приклад структури тесту + +```javascript +describe('Функція: Автентифікація користувача', () => { + beforeEach(() => { + // Налаштування + }); + + afterEach(() => { + // Очищення + }); + + it('має автентифікувати валідні облікові дані', async () => { + // Arrange + // Act + // Assert + }); + + it('має відхилити невалідні облікові дані', async () => { + // Тест випадку помилки + }); + + it('має обробити граничний випадок: порожній пароль', async () => { + // Тест граничного випадку + }); +}); +``` + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/08-checkpoints/checkpoint-examples.md b/uk/08-checkpoints/checkpoint-examples.md new file mode 100644 index 0000000..5ae7bff --- /dev/null +++ b/uk/08-checkpoints/checkpoint-examples.md @@ -0,0 +1,342 @@ +# Приклади контрольних точок + +Реальні приклади ефективного використання контрольних точок у Claude Code. + +Примітка: Контрольні точки створюються автоматично з кожним промптом користувача. Вам не потрібно зберігати їх вручну. Для відкату натисніть `Esc` двічі (`Esc+Esc`) або використовуйте `/rewind` для відкриття браузера контрольних точок. + +## Приклад 1: Міграція бази даних + +### Сценарій +Потрібно мігрувати з MySQL на PostgreSQL, але хочете дослідити як пряму міграцію, так і поступовий підхід з подвійним записом (dual-write). + +### Робочий процес + +``` +Користувач: Реалізуймо пряму міграцію з MySQL на PostgreSQL + [Контрольна точка A створена автоматично] + +Claude: Реалізую пряму міграцію... +[Змінює драйвер БД, оновлює запити, модифікує схему] + +Користувач: Запусти тести + [Контрольна точка B створена автоматично] + +Claude: Запускаю тести... +❌ 15 тестів не проходять — проблеми з пулом зʼєднань + +Користувач: Цей підхід має проблеми. Спробуймо патерн dual-write. +[Користувач натискає Esc+Esc, обирає контрольну точку A, обирає "Restore code and conversation"] + +Користувач: Тепер реалізуй патерн dual-write, де ми пишемо в обидві БД + +Claude: Реалізую міграцію з dual-write... +[Реалізує рівень dual-write, стратегію поступової міграції] + +Користувач: Запусти тести + +Claude: Запускаю тести... +✅ Усі тести проходять + +Користувач: Підхід dual-write явно безпечніший. Закомітимо це. +``` + +## Приклад 2: Оптимізація продуктивності + +### Сценарій +Кілька стратегій оптимізації продуктивності для випробування. + +### Робочий процес + +``` +Користувач: Оптимізуймо час відповіді API. Поточний: 450мс + [Контрольна точка "Baseline" створена автоматично] + +Claude: Додам кешування запитів до БД... +[Реалізує кешування Redis] + +Користувач: Запусти тести продуктивності + +Claude: Результати: 280мс середній час відповіді (покращення 38%) + +Користувач: Спробую інший підхід. +[Користувач натискає Esc+Esc, обирає контрольну точку "Baseline", обирає "Restore code and conversation"] + +Користувач: Спробуй оптимізацію запитів до БД + +Claude: Оптимізую запити до БД... +[Додає індекси, оптимізує N+1 запити] + +Користувач: Запусти тести продуктивності + +Claude: Результати: 180мс середній час відповіді (покращення 60%) + +Користувач: Спробую ще третій підхід. +[Користувач натискає Esc+Esc, обирає контрольну точку "Baseline", обирає "Restore code and conversation"] + +Користувач: Спробуй стиснення відповідей та CDN + +Claude: Додам стиснення та CDN... +[Реалізує gzip, налаштовує CDN] + +Користувач: Запусти тести продуктивності + +Claude: Результати: 320мс середній час відповіді (покращення 29%) + +Користувач: Оптимізація запитів була найкращою. Повернуся та поєднаю з кешуванням. +[Користувач натискає Esc+Esc, обирає контрольну точку після оптимізації запитів, обирає "Restore code and conversation"] + +Користувач: Тепер додай кешування Redis поверх цих оптимізованих запитів + +Claude: [Додає кешування Redis поверх оптимізованих запитів] + +Користувач: Запусти тести продуктивності + +Claude: Результати: 95мс середній час відповіді (покращення 79%) 🎉 + +Користувач: Ідеально! Це переможець. Закомітимо. +``` + +## Приклад 3: Ітерація UI/UX + +### Сценарій +Випробування різних макетів для дашборду. + +### Робочий процес + +``` +Користувач: Перепроєктуймо дашборд з бічною панеллю + [Контрольна точка "Start" створена автоматично] + +Claude: [Реалізує макет з бічною панеллю] + +Користувач: Покажи скріншот + +Claude: [Показує скріншот] + +Користувач: Бічна панель тісна. Спробуймо верхню навігацію. +[Користувач натискає Esc+Esc, обирає контрольну точку "Start", обирає "Restore code and conversation"] + +Користувач: Спробуй макет з верхньою навігацією + +Claude: [Реалізує верхню навігацію] + +Користувач: Покажи скріншот + +Claude: [Показує скріншот] + +Користувач: Краще, але спробуймо макет у вигляді сітки карток +[Користувач натискає Esc+Esc, обирає контрольну точку "Start", обирає "Restore code and conversation"] + +Користувач: Спробуй макет сітки карток + +Claude: [Реалізує сітку карток] + +Користувач: Покажи скріншот + +Claude: [Показує скріншот] + +Користувач: Чудово! Але чи можемо поєднати верхню навігацію із сіткою карток? +[Користувач натискає Esc+Esc, обирає контрольну точку після сітки карток, обирає "Restore code and conversation"] + +Користувач: Додай верхню навігацію до макету сітки карток + +Claude: [Додає верхню навігацію до сітки карток] + +Користувач: Ідеально! Це фінальний дизайн. +``` + +## Приклад 4: Сесія налагодження + +### Сценарій +Полювання на складну помилку з кількома гіпотезами. + +### Робочий процес + +``` +Користувач: В додатку є витік памʼяті + [Контрольна точка "Before debugging" створена автоматично] + +Claude: Досліджую... +[Аналізує код] + +Користувач: Думаю, це в обробниках подій. Виправимо їх. + +Claude: [Виправляє очищення обробників подій] + +Користувач: Запусти профілювальник памʼяті + +Claude: Памʼять все ще тече — обробники подій не були причиною + +Користувач: Повернуся та спробую іншу гіпотезу. +[Користувач натискає Esc+Esc, обирає контрольну точку "Before debugging", обирає "Restore code and conversation"] + +Користувач: Може це зʼєднання з БД? + +Claude: [Реалізує виправлення пулу зʼєднань] + +Користувач: Запусти профілювальник памʼяті + +Claude: Все ще тече — не зʼєднання + +Користувач: Повернуся та спробую інший ракурс. +[Користувач натискає Esc+Esc, обирає контрольну точку "Before debugging", обирає "Restore code and conversation"] + +Користувач: Перевіримо циклічні посилання + +Claude: [Знаходить та виправляє циклічні посилання в кеші] + +Користувач: Запусти профілювальник памʼяті + +Claude: ✅ Витік памʼяті виправлено! Циклічні посилання в рівні кешування були причиною. + +Користувач: Відмінно! Закомітимо це виправлення. +``` + +## Приклад 5: Еволюція дизайну API + +### Сценарій +Проєктування REST API з кількома ітераціями. + +### Робочий процес + +``` +Користувач: Створи REST API для нашої блог-платформи + [Контрольна точка "Before API design" створена автоматично] + +Claude: [Створює базовий CRUD API] + +Користувач: Це занадто просто. Додаймо пагінацію та фільтрацію + +Claude: [Додає пагінацію та фільтрацію] + +Користувач: Потрібні кращі звʼязки між ресурсами + +Claude: [Реалізує HATEOAS-посилання] + +Користувач: Власне, спробуймо GraphQL замість REST +[Користувач натискає Esc+Esc, обирає контрольну точку "Before API design", обирає "Restore code and conversation"] + +Користувач: Реалізуй GraphQL API для нашої блог-платформи + +Claude: [Реалізує GraphQL API] + +Користувач: Думаю, REST краще для нашого випадку. +[Користувач натискає Esc+Esc, обирає контрольну точку після HATEOAS, обирає "Restore code and conversation"] + +Користувач: Фіналізуємо REST-підхід. +``` + +## Приклад 6: Управління конфігурацією + +### Сценарій +Тестування різних підходів до конфігурації. + +### Робочий процес + +``` +Користувач: Перемісти конфігурацію у змінні оточення + [Контрольна точка "Original config" створена автоматично] + +Claude: [Реалізує конфігурацію через змінні оточення] + +Користувач: Тест у середовищі розробки + +Claude: Працює локально, але проблеми з деплоєм на продакшні + +Користувач: Спробую інший підхід. +[Користувач натискає Esc+Esc, обирає контрольну точку "Original config", обирає "Restore code and conversation"] + +Користувач: Спробуй підхід з файлом конфігурації та валідацією + +Claude: [Реалізує YAML-конфігурацію з валідацією JSON Schema] + +Користувач: Тест у середовищі розробки + +Claude: ✅ Працює добре, хороші повідомлення про помилки валідації + +Користувач: Чи можемо також підтримувати змінні оточення для чутливих значень? + +Claude: [Додає перевизначення через змінні оточення для секретів] + +Користувач: Тест деплою + +Claude: ✅ Усі середовища працюють коректно + +Користувач: Ідеально! Це готове для продакшну. +``` + +## Приклад 7: Стратегія тестування + +### Сценарій +Реалізація комплексного тестування. + +### Робочий процес + +``` +Користувач: Додай юніт-тести для модуля автентифікації + [Контрольна точка створена автоматично] + +Claude: [Додає юніт-тести Jest] + +Користувач: Запусти тести + +Claude: 45 тестів проходять, 78% покриття + +Користувач: Додай також інтеграційні тести + +Claude: [Додає інтеграційні тести] + +Користувач: Запусти тести + +Claude: 89 тестів проходять, 92% покриття, але тести повільні (3 хвилини) + +Користувач: Тести занадто повільні. Оптимізуймо. + +Claude: [Оптимізує налаштування тестів, додає паралельне виконання] + +Користувач: Запусти тести + +Claude: 89 тестів проходять, 92% покриття, 35 секунд ✅ + +Користувач: Чудово! Тепер додай E2E тести для критичних шляхів + +Claude: [Додає E2E тести Playwright] + +Користувач: Запусти всі тести + +Claude: 112 тестів проходять, 94% покриття, 2 хвилини + +Користувач: Ідеальний баланс покриття та швидкості! +``` + +## Приклад 8: Використання підсумку від контрольної точки + +### Сценарій +Після довгої сесії налагодження хочете стиснути розмову, зберігаючи контекст. + +### Робочий процес + +``` +Користувач: [Після 20+ повідомлень налагодження та дослідження] + +[Користувач натискає Esc+Esc, обирає ранню контрольну точку, обирає "Summarize from here"] +[Необовʼязково надає інструкції: "Зосередься на тому, що ми спробували і що спрацювало"] + +Claude: [Генерує підсумок розмови від цієї точки далі] +[Оригінальні повідомлення зберігаються в транскрипті] +[Підсумок замінює видиму розмову, зменшуючи використання контекстного вікна] + +Користувач: Тепер продовжимо з підходом, що спрацював. +``` + +## Ключові висновки + +1. **Контрольні точки автоматичні**: Кожен промпт користувача створює контрольну точку — ручне збереження не потрібне +2. **Використовуйте Esc+Esc або /rewind**: Два способи доступу до браузера контрольних точок +3. **Обирайте правильний варіант відновлення**: Відновити код, розмову, обидва або підсумувати — залежно від потреб +4. **Не бійтеся експериментувати**: Контрольні точки роблять безпечним випробування радикальних змін +5. **Поєднуйте з git**: Контрольні точки для дослідження, git для фіналізованої роботи +6. **Підсумовуйте довгі сесії**: Використовуйте "Summarize from here" для підтримки керованості розмов + +--- +**Останнє оновлення**: 9 квітня 2026 diff --git a/uk/09-advanced-features/planning-mode-examples.md b/uk/09-advanced-features/planning-mode-examples.md new file mode 100644 index 0000000..aa1ebf2 --- /dev/null +++ b/uk/09-advanced-features/planning-mode-examples.md @@ -0,0 +1,493 @@ +# Приклади режиму планування + +Реальні приклади ефективного використання режиму планування в Claude Code. + +## Приклад 1: Створення REST API + +### Без режиму планування + +``` +Користувач: Створи REST API для блогу + +Claude: Створю API... +[Одразу починає кодувати, може пропустити вимоги] +``` + +### З режимом планування + +``` +Користувач: /plan Створи REST API для блогу + +Claude: Створю комплексний план для API блогу. + +## План реалізації REST API блогу + +### Фаза 1: Налаштування проєкту (15 хв) +1. Ініціалізувати проєкт Node.js з Express +2. Налаштувати конфігурацію TypeScript +3. Встановити залежності (express, pg, jwt, joi) +4. Налаштувати змінні оточення +5. Встановити структуру проєкту + +### Фаза 2: Рівень бази даних (30 хв) +6. Спроєктувати схему БД + - таблиця users (id, email, password_hash, created_at) + - таблиця posts (id, user_id, title, content, published, created_at, updated_at) + - таблиця comments (id, post_id, user_id, content, created_at) +7. Створити файли міграцій +8. Налаштувати пул зʼєднань з БД +9. Реалізувати моделі БД + +### Фаза 3: Автентифікація (45 хв) +10. Реалізувати ендпоінт реєстрації +11. Реалізувати ендпоінт входу з JWT +12. Створити middleware автентифікації +13. Додати хешування паролів з bcrypt +14. Реалізувати логіку оновлення токенів + +### Фаза 4: API постів (40 хв) +15. GET /api/posts — список усіх опублікованих постів (з пагінацією) +16. GET /api/posts/:id — отримати окремий пост +17. POST /api/posts — створити новий пост (потрібна автентифікація) +18. PUT /api/posts/:id — оновити пост (автентифікація, перевірка власності) +19. DELETE /api/posts/:id — видалити пост (автентифікація, перевірка власності) +20. GET /api/users/:id/posts — отримати пости користувача + +### Фаза 5: API коментарів (30 хв) +21. GET /api/posts/:id/comments — отримати коментарі посту +22. POST /api/posts/:id/comments — додати коментар (потрібна автентифікація) +23. DELETE /api/comments/:id — видалити коментар (автентифікація, перевірка власності) + +### Фаза 6: Валідація та обробка помилок (30 хв) +24. Додати валідацію запитів з Joi +25. Реалізувати глобальний обробник помилок +26. Додати санітизацію вхідних даних +27. Реалізувати обмеження частоти запитів + +### Фаза 7: Тестування (60 хв) +28. Написати юніт-тести для моделей +29. Написати інтеграційні тести для ендпоінтів автентифікації +30. Написати інтеграційні тести для ендпоінтів постів +31. Написати інтеграційні тести для ендпоінтів коментарів +32. Досягти 80%+ покриття коду + +### Фаза 8: Документація та деплой (30 хв) +33. Згенерувати API-документацію зі Swagger +34. Створити README з інструкціями налаштування +35. Додати конфігурацію Docker +36. Налаштувати CI/CD пайплайн + +**Орієнтовний час**: 4.5 години +**Файлів для створення**: ~25 +**Ключові технології**: Express, PostgreSQL, JWT, TypeScript + +**Резюме API-ендпоінтів**: +- Автентифікація: 2 ендпоінти +- Пости: 6 ендпоінтів +- Коментарі: 3 ендпоінти +- Загалом: 11 ендпоінтів + +Готові продовжити? (yes/no/modify) + +Користувач: yes + +Claude: Починаю Фазу 1: Налаштування проєкту... +[Реалізує кожну фазу систематично] +``` + +## Приклад 2: Міграція бази даних + +### З режимом планування + +``` +Користувач: /plan Мігрувати з MongoDB на PostgreSQL + +Claude: Це складна міграція. Створю детальний план. + +## План міграції MongoDB → PostgreSQL + +### Фаза 1: Аналіз та підготовка (День 1) +1. Проаналізувати поточну схему MongoDB +2. Визначити звʼязки та обмеження даних +3. Задокументувати поточний обсяг та темп зростання даних +4. Спроєктувати еквівалентну схему PostgreSQL +5. Спланувати відповідності типів даних +6. Визначити потенційні складнощі міграції + +### Фаза 2: Налаштування PostgreSQL (День 1) +7. Налаштувати БД PostgreSQL +8. Створити схему з таблицями, індексами, обмеженнями +9. Налаштувати пул зʼєднань +10. Налаштувати стратегію резервного копіювання + +### Фаза 3: Реалізація dual-write (Дні 2-3) +11. Створити рівень абстракції БД +12. Реалізувати dual-write в обидві БД +13. Додати перевірки консистентності даних +14. Деплой dual-write на staging +15. Моніторинг на предмет проблем + +### Фаза 4: Міграція даних (День 4) +16. Створити скрипти експорту даних з MongoDB +17. Створити скрипти імпорту даних у PostgreSQL +18. Реалізувати логіку трансформації даних +19. Запустити початкову міграцію на копії продакшн-даних +20. Валідувати цілісність мігрованих даних + +### Фаза 5: Поступове переключення (Дні 5-7) +21. Увімкнути dual-write на продакшні +22. Мігрувати історичні дані пакетами +23. Безперервно валідувати консистентність даних +24. Моніторити обидві БД +25. Виправляти проблеми синхронізації даних + +### Фаза 6: PostgreSQL як основна (День 8) +26. Переключити операції читання на PostgreSQL +27. Моніторити продуктивність запитів +28. Оптимізувати повільні запити +29. Продовжити dual-write для безпеки + +### Фаза 7: Виведення MongoDB (Дні 9-10) +30. Припинити запис у MongoDB +31. Залишити MongoDB як бекап на 2 тижні +32. Видалити залежності від MongoDB з коду +33. Архівувати дані MongoDB +34. Вивести з експлуатації інстанс MongoDB + +**Орієнтовний час**: 10 днів +**Рівень ризику**: Високий +**Стратегія відкату**: Залишити MongoDB запущеною з dual-write +**Критерії успіху**: +- Нуль втрат даних +- <5% регресії продуктивності +- Усі тести проходять + +Продовжити з цим планом? (yes/no/modify) + +Користувач: Modify — додаймо план відкату для кожної фази + +Claude: Оновлений план з процедурами відкату для кожної фази... +``` + +## Приклад 3: Рефакторинг фронтенду + +``` +Користувач: /plan Рефакторити React-додаток з класових компонентів на хуки + +Claude: Створю систематичний план рефакторингу. + +## План міграції React Class → Hooks + +### Фаза 1: Підготовка та аналіз (2 години) +1. Аудит усіх класових компонентів +2. Категоризація за складністю: + - Прості (лише стан): ~15 компонентів + - Середні (методи життєвого циклу): ~23 компоненти + - Складні (кілька lifecycle, refs): ~8 компонентів +3. Визначити бібліотеки, що потребують оновлення +4. Створити граф залежностей компонентів +5. Спланувати порядок міграції (листові вузли першими) + +### Фаза 2: Налаштування та інструменти (1 година) +6. Оновити React до v18+ +7. Налаштувати правила ESLint для хуків +8. Створити шаблони конверсії +9. Налаштувати автоматичні тести +10. Створити контрольну точку перед початком + +### Фаза 3: Міграція простих компонентів (4 години) +11. Конвертувати прості stateful компоненти (15 компонентів) +12. Замінити this.state на useState +13. Замінити this.setState на сетери стану +14. Тестувати кожен компонент після конверсії +15. Оновити тести + +### Фаза 4: Міграція середніх компонентів (8 годин) +16. Конвертувати компоненти з методами lifecycle (23 компоненти) +17. Замінити componentDidMount на useEffect +18. Замінити componentDidUpdate на useEffect +19. Замінити componentWillUnmount на очищення useEffect +20. Ретельно тестувати + +### Фаза 5: Міграція складних компонентів (12 годин) +21. Конвертувати складні компоненти (8 компонентів) +22. Замінити refs на useRef +23. Витягти кастомні хуки для спільної логіки +24. Обробити крайні випадки (кілька useEffect) +25. Розширене тестування + +### Фаза 6: Витяг спільної логіки (6 годин) +26. Виявити дубльовану логіку між компонентами +27. Створити кастомні хуки: + - useAuth + - useFetch + - useLocalStorage + - useDebounce +28. Рефакторити компоненти для використання кастомних хуків +29. Тестувати кастомні хуки незалежно + +### Фаза 7: Оптимізація продуктивності (4 години) +30. Додати React.memo де потрібно +31. Оптимізувати з useCallback +32. Оптимізувати з useMemo +33. Профілювати та виправити регресії продуктивності + +### Фаза 8: Очищення та документація (2 години) +34. Видалити невикористані утиліти класових компонентів +35. Оновити документацію +36. Оновити рекомендації з кодування +37. Створити посібник міграції для команди + +**Орієнтовний час**: 5 днів (39 годин) +**Файлів для зміни**: 46 компонентів +**Рівень ризику**: Середній + +**Порядок міграції**: +1. Листові компоненти (без залежностей) +2. Компоненти середнього рівня +3. Контейнерні компоненти верхнього рівня +4. App.jsx (останній) + +Продовжити? (yes/no/modify) +``` + +## Приклад 4: Реалізація безпеки + +``` +Користувач: /plan Реалізувати комплексну безпеку для нашого веб-додатку + +Claude: Створю ретельний план реалізації безпеки. + +## План реалізації безпеки веб-додатку + +### Фаза 1: Аудит безпеки (День 1) +1. Запустити автоматичні сканери безпеки (npm audit, Snyk) +2. Перевірити залежності на вразливості +3. Перевірити відповідність OWASP Top 10 +4. Аудит потоків автентифікації +5. Перевірити практики обробки даних +6. Задокументувати поточні прогалини безпеки + +### Фаза 2: Посилення автентифікації (Дні 2-3) +7. Реалізувати вимоги до складності паролів +8. Додати індикатор надійності пароля +9. Реалізувати обмеження частоти спроб входу +10. Додати блокування облікового запису після невдалих спроб +11. Реалізувати 2FA (TOTP) +12. Покращити управління сесіями +13. Реалізувати безпечний потік скидання пароля + +### Фаза 3: Авторизація та контроль доступу (Дні 3-4) +14. Реалізувати RBAC (контроль доступу на основі ролей) +15. Додати перевірки дозволів на всіх ендпоінтах +16. Реалізувати принцип мінімальних привілеїв +17. Додати журнал аудиту для чутливих операцій +18. Реалізувати дозволи на рівні ресурсів + +### Фаза 4: Захист даних (Дні 4-5) +19. Реалізувати шифрування в стані спокою (чутливі поля) +20. Забезпечити TLS/SSL для всіх комунікацій +21. Реалізувати безпечне зберігання сесій +22. Додати маскування PII у журналах +23. Реалізувати політики збереження даних +24. Додати безпечну обробку завантаження файлів + +### Фаза 5: Валідація та санітизація введення (Дні 5-6) +25. Реалізувати валідацію введення на всіх ендпоінтах +26. Додати захист від XSS (Content Security Policy) +27. Реалізувати захист від SQL-інʼєкцій (параметризовані запити) +28. Додати захист від CSRF +29. Реалізувати ліміти розміру запитів +30. Додати валідацію типів файлів при завантаженні + +### Фаза 6: Заголовки безпеки та конфігурація (День 6) +31. Додати заголовки безпеки: + - Strict-Transport-Security + - X-Content-Type-Options + - X-Frame-Options + - X-XSS-Protection + - Content-Security-Policy +32. Правильно налаштувати CORS +33. Вимкнути непотрібні HTTP-методи +34. Видалити заголовки версії сервера + +### Фаза 7: Моніторинг та логування (День 7) +35. Реалізувати логування подій безпеки +36. Додати виявлення аномалій +37. Налаштувати виявлення вторгнень +38. Реалізувати алертинг у реальному часі +39. Створити дашборд безпеки + +### Фаза 8: Тестування та документація (Дні 8-9) +40. Провести тестування на проникнення +41. Запустити сканери безпеки +42. Протестувати всі функції безпеки +43. Створити документацію безпеки +44. Навчити команду практикам безпеки +45. Створити план реагування на інциденти + +### Фаза 9: Відповідність та політики (День 10) +46. Перевірка відповідності GDPR +47. Створити політику конфіденційності +48. Реалізувати права субʼєктів даних +49. Додати згоду на cookies +50. Створити документацію політик безпеки + +**Орієнтовний час**: 10 днів +**Рівень ризику**: Критичний +**Пріоритет**: Високий + +**Відповідність**: OWASP Top 10, GDPR + +Продовжити? (yes/no/modify) +``` + +## Приклад 5: Оптимізація продуктивності + +``` +Користувач: /plan Оптимізувати наш повільний сайт електронної комерції + +Claude: Створю комплексний план оптимізації продуктивності. + +## План оптимізації продуктивності електронної комерції + +### Фаза 1: Аудит продуктивності (4 години) +1. Запустити аудит Lighthouse +2. Проаналізувати профіль продуктивності Chrome DevTools +3. Виміряти Core Web Vitals: + - LCP (Largest Contentful Paint) + - FID (First Input Delay) + - CLS (Cumulative Layout Shift) +4. Визначити вузькі місця продуктивності +5. Створити базові метрики продуктивності + +**Поточні метрики**: +- LCP: 4.2с (ціль: <2.5с) +- FID: 280мс (ціль: <100мс) +- CLS: 0.25 (ціль: <0.1) +- Завантаження сторінки: 8.3с (ціль: <3с) + +### Фаза 2: Оптимізація зображень (6 годин) +6. Конвертувати зображення у формат WebP +7. Реалізувати адаптивні зображення +8. Додати ліниве завантаження зображень +9. Оптимізувати розміри зображень (стиснення) +10. Реалізувати CDN для зображень +11. Додати плейсхолдери зображень + +**Очікуваний вплив**: -40% час завантаження + +### Фаза 3: Розділення коду та ліниве завантаження (8 годин) +12. Реалізувати розділення коду за маршрутами +13. Ліниво завантажувати некритичні компоненти +14. Розділити vendor-бандли +15. Оптимізувати розміри чанків +16. Реалізувати динамічні імпорти +17. Додати попереднє завантаження критичних ресурсів + +**Очікуваний вплив**: -30% початковий розмір бандлу + +### Фаза 4: Стратегія кешування (6 годин) +18. Реалізувати кешування браузером (Cache-Control) +19. Додати service worker для офлайн-підтримки +20. Реалізувати кешування відповідей API +21. Додати кеш Redis для запитів до БД +22. Реалізувати stale-while-revalidate +23. Налаштувати кешування CDN + +**Очікуваний вплив**: -50% час відповіді API + +### Фаза 5: Оптимізація БД (8 годин) +24. Додати індекси в БД +25. Оптимізувати повільні запити (>100мс) +26. Реалізувати кешування результатів запитів +27. Додати пул зʼєднань +28. Денормалізувати де доречно +29. Реалізувати репліки БД для читання + +**Очікуваний вплив**: -60% час запитів до БД + +### Фаза 6: Оптимізація фронтенду (10 годин) +30. Мінімізувати та стиснути JavaScript +31. Мінімізувати та стиснути CSS +32. Видалити невикористаний CSS (PurgeCSS) +33. Реалізувати критичний CSS +34. Відкласти некритичний JavaScript +35. Зменшити розмір DOM +36. Оптимізувати рендеринг React (memo, useMemo) +37. Реалізувати віртуальний скролінг для довгих списків + +**Очікуваний вплив**: -35% час виконання JavaScript + +### Фаза 7: Оптимізація мережі (4 години) +38. Увімкнути HTTP/2 +39. Реалізувати підказки ресурсів (preconnect, prefetch) +40. Зменшити кількість HTTP-запитів +41. Увімкнути стиснення Brotli +42. Оптимізувати сторонні скрипти + +**Очікуваний вплив**: -25% мережевий час + +### Фаза 8: Моніторинг та тестування (4 години) +43. Налаштувати моніторинг продуктивності (Datadog/New Relic) +44. Додати Real User Monitoring (RUM) +45. Створити бюджети продуктивності +46. Налаштувати автоматичний Lighthouse CI +47. Тестувати на реальних пристроях + +**Орієнтовний час**: 50 годин (2 тижні) + +**Цільові метрики** (90-й перцентиль): +- LCP: <2.0с (з 4.2с) ✅ +- FID: <50мс (з 280мс) ✅ +- CLS: <0.05 (з 0.25) ✅ +- Завантаження: <2.5с (з 8.3с) ✅ + +**Порядок пріоритету**: +1. Оптимізація зображень (швидкі перемоги) +2. Розділення коду (високий вплив) +3. Кешування (високий вплив) +4. Оптимізація БД (критично) +5. Оптимізація фронтенду (полірування) + +Продовжити з цим планом? (yes/no/modify) +``` + +## Ключові висновки + +### Переваги режиму планування + +1. **Ясність**: Чіткий план дій перед початком +2. **Оцінка**: Оцінки часу та зусиль +3. **Оцінка ризиків**: Раннє виявлення потенційних проблем +4. **Пріоритезація**: Логічний порядок завдань +5. **Затвердження**: Перегляд та затвердження перед виконанням +6. **Модифікація**: Коригування плану на основі зворотного звʼязку + +### Коли використовувати режим планування + +✅ **Завжди використовуйте для**: +- Багатоденних проєктів +- Командних співпраць +- Критичних змін системи +- Вивчення нових концепцій +- Складного рефакторингу + +❌ **Не використовуйте для**: +- Виправлення помилок +- Дрібних правок +- Простих запитань +- Швидких експериментів + +### Найкращі практики + +1. **Ретельно переглядайте плани** перед затвердженням +2. **Модифікуйте плани**, коли помічаєте проблеми +3. **Розбивайте** складні завдання +4. **Оцінюйте реалістичні** часові рамки +5. **Включайте стратегії відкату** +6. **Додавайте критерії успіху** +7. **Плануйте тестування** на кожній фазі + +--- +**Останнє оновлення**: 9 квітня 2026 From c0d400b21b901ca1ff41bf4bdb9ffce3ae78f2c6 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 23:08:46 +0300 Subject: [PATCH 11/20] feat(uk): translate refactor references (code-smells + catalog) 03-skills/refactor/references/code-smells.md (669 lines) 03-skills/refactor/references/refactoring-catalog.md (1023 lines) P3 complete. Remaining: P4 root docs (5 files). Ref: luongnv89/claude-howto#63 --- .../refactor/references/code-smells.md | 669 +++++++++++ .../references/refactoring-catalog.md | 1019 +++++++++++++++++ 2 files changed, 1688 insertions(+) create mode 100644 uk/03-skills/refactor/references/code-smells.md create mode 100644 uk/03-skills/refactor/references/refactoring-catalog.md diff --git a/uk/03-skills/refactor/references/code-smells.md b/uk/03-skills/refactor/references/code-smells.md new file mode 100644 index 0000000..3480bbe --- /dev/null +++ b/uk/03-skills/refactor/references/code-smells.md @@ -0,0 +1,669 @@ +# Каталог запахів коду + +Комплексний довідник запахів коду на основі книги Мартіна Фаулера *Refactoring* (2-ге видання). Запахи коду — це симптоми глибших проблем; вони вказують на те, що щось може бути не так з дизайном вашого коду. + +> «Запах коду — це поверхнева ознака, яка зазвичай відповідає глибшій проблемі в системі.» — Мартін Фаулер + +--- + +## Роздуті елементи (Bloaters) + +Запахи коду, що представляють щось, що розрослося занадто великим для ефективної роботи. + +### Long Method (Довгий метод) + +**Ознаки:** +- Метод перевищує 30-50 рядків +- Потрібно прокручувати, щоб побачити весь метод +- Кілька рівнів вкладеності +- Коментарі пояснюють, що роблять секції + +**Чому це погано:** +- Важко зрозуміти +- Складно тестувати ізольовано +- Зміни мають непередбачувані наслідки +- Дубльована логіка ховається всередині + +**Рефакторинги:** +- Extract Method +- Replace Temp with Query +- Introduce Parameter Object +- Replace Method with Method Object +- Decompose Conditional + +**Приклад (до):** +```javascript +function processOrder(order) { + // Валідація замовлення (20 рядків) + if (!order.items) throw new Error('No items'); + if (order.items.length === 0) throw new Error('Empty order'); + // ... ще валідація + + // Обчислення підсумків (30 рядків) + let subtotal = 0; + for (const item of order.items) { + subtotal += item.price * item.quantity; + } + // ... податок, доставка, знижки + + // Надсилання сповіщень (20 рядків) + // ... логіка email +} +``` + +**Приклад (після):** +```javascript +function processOrder(order) { + validateOrder(order); + const totals = calculateOrderTotals(order); + sendOrderNotifications(order, totals); + return { order, totals }; +} +``` + +--- + +### Large Class (Великий клас) + +**Ознаки:** +- Клас має багато полів екземпляра (>7-10) +- Клас має багато методів (>15-20) +- Назва класу розмита (Manager, Handler, Processor) +- Методи не використовують усі поля екземпляра + +**Чому це погано:** +- Порушує принцип єдиної відповідальності +- Важко тестувати +- Зміни поширюються на неповʼязані функції +- Складно повторно використовувати частини + +**Рефакторинги:** +- Extract Class +- Extract Subclass +- Extract Interface + +**Виявлення:** +``` +Рядків коду > 300 +Кількість методів > 15 +Кількість полів > 10 +``` + +--- + +### Primitive Obsession (Одержимість примітивами) + +**Ознаки:** +- Використання примітивів для доменних концепцій (string для email, int для грошей) +- Масиви примітивів замість обʼєктів +- Рядкові константи для кодів типів +- Магічні числа/рядки + +**Чому це погано:** +- Немає валідації на рівні типу +- Логіка розкидана по кодовій базі +- Легко передати неправильні значення +- Відсутні доменні концепції + +**Рефакторинги:** +- Replace Primitive with Object +- Replace Type Code with Class +- Replace Type Code with Subclasses +- Replace Type Code with State/Strategy + +**Приклад (до):** +```javascript +const user = { + email: 'john@example.com', // Просто рядок + phone: '1234567890', // Просто рядок + status: 'active', // Магічний рядок + balance: 10050 // Копійки як ціле число +}; +``` + +**Приклад (після):** +```javascript +const user = { + email: new Email('john@example.com'), + phone: new PhoneNumber('1234567890'), + status: UserStatus.ACTIVE, + balance: Money.cents(10050) +}; +``` + +--- + +### Long Parameter List (Довгий список параметрів) + +**Ознаки:** +- Методи з 4+ параметрами +- Параметри, що завжди зʼявляються разом +- Булеві прапорці, що змінюють поведінку методу +- Часте передавання null/undefined + +**Чому це погано:** +- Важко викликати правильно +- Плутанина з порядком параметрів +- Вказує, що метод робить занадто багато +- Важко додавати нові параметри + +**Рефакторинги:** +- Introduce Parameter Object +- Preserve Whole Object +- Replace Parameter with Method Call +- Remove Flag Argument + +**Приклад (до):** +```javascript +function createUser(firstName, lastName, email, phone, + street, city, state, zip, + isAdmin, isActive, createdBy) { + // ... +} +``` + +**Приклад (після):** +```javascript +function createUser(personalInfo, address, options) { + // personalInfo: { firstName, lastName, email, phone } + // address: { street, city, state, zip } + // options: { isAdmin, isActive, createdBy } +} +``` + +--- + +### Data Clumps (Групи даних) + +**Ознаки:** +- Ті самі 3+ поля зʼявляються разом повторно +- Параметри, що завжди подорожують разом +- Класи з підмножинами полів, що належать один одному + +**Чому це погано:** +- Дубльована логіка обробки +- Відсутня абстракція +- Важче розширювати +- Вказує на прихований клас + +**Рефакторинги:** +- Extract Class +- Introduce Parameter Object +- Preserve Whole Object + +**Приклад:** +```javascript +// Група даних: координати (x, y, z) +function movePoint(x, y, z, dx, dy, dz) { } +function scalePoint(x, y, z, factor) { } +function distanceBetween(x1, y1, z1, x2, y2, z2) { } + +// Витяг класу Point3D +class Point3D { + constructor(x, y, z) { } + move(delta) { } + scale(factor) { } + distanceTo(other) { } +} +``` + +--- + +## Зловживання обʼєктною орієнтацією (OO Abusers) + +Запахи, що вказують на неповне або некоректне використання принципів ООП. + +### Switch Statements (Оператори Switch) + +**Ознаки:** +- Довгі ланцюжки switch/case або if/else +- Той самий switch у кількох місцях +- Switch за кодами типів +- Додавання нових випадків вимагає змін всюди + +**Чому це погано:** +- Порушує принцип відкритості/закритості +- Зміни поширюються на всі місця з switch +- Важко розширювати +- Часто вказує на відсутній поліморфізм + +**Рефакторинги:** +- Replace Conditional with Polymorphism +- Replace Type Code with Subclasses +- Replace Type Code with State/Strategy + +**Приклад (до):** +```javascript +function calculatePay(employee) { + switch (employee.type) { + case 'hourly': + return employee.hours * employee.rate; + case 'salaried': + return employee.salary / 12; + case 'commissioned': + return employee.sales * employee.commission; + } +} +``` + +**Приклад (після):** +```javascript +class HourlyEmployee { + calculatePay() { + return this.hours * this.rate; + } +} + +class SalariedEmployee { + calculatePay() { + return this.salary / 12; + } +} +``` + +--- + +### Temporary Field (Тимчасове поле) + +**Ознаки:** +- Поля екземпляра, що використовуються лише в деяких методах +- Поля, що встановлюються умовно +- Складна ініціалізація для певних випадків + +**Чому це погано:** +- Плутанина — поле існує, але може бути null +- Важко зрозуміти стан обʼєкта +- Вказує на приховану умовну логіку + +**Рефакторинги:** +- Extract Class +- Introduce Null Object +- Replace Temp Field with Local + +--- + +### Refused Bequest (Відхилена спадщина) + +**Ознаки:** +- Підклас не використовує успадковані методи/дані +- Підклас перевизначає, щоб нічого не робити +- Успадкування використовується для повторного використання коду, а не для відношення IS-A + +**Чому це погано:** +- Неправильна абстракція +- Порушує принцип підстановки Лісков +- Оманлива ієрархія + +**Рефакторинги:** +- Push Down Method/Field +- Replace Subclass with Delegate +- Replace Inheritance with Delegation + +--- + +### Alternative Classes with Different Interfaces (Альтернативні класи з різними інтерфейсами) + +**Ознаки:** +- Два класи, що роблять схожі речі +- Різні назви методів для тієї самої концепції +- Можуть використовуватися взаємозамінно + +**Чому це погано:** +- Дубльовані реалізації +- Немає спільного інтерфейсу +- Важко перемикатися між ними + +**Рефакторинги:** +- Rename Method +- Move Method +- Extract Superclass +- Extract Interface + +--- + +## Перешкоди для змін (Change Preventers) + +Запахи, що ускладнюють зміни — зміна однієї речі вимагає зміни багатьох інших. + +### Divergent Change (Дивергентна зміна) + +**Ознаки:** +- Один клас змінюється з кількох різних причин +- Зміни в різних областях запускають редагування того самого класу +- Клас є «God-класом» + +**Чому це погано:** +- Порушує принцип єдиної відповідальності +- Висока частота змін +- Конфлікти злиття + +**Рефакторинги:** +- Extract Class +- Extract Superclass +- Extract Subclass + +**Приклад:** +Клас `User` змінюється через: +- Зміни автентифікації +- Зміни профілю +- Зміни білінгу +- Зміни сповіщень + +→ Витягти: `AuthService`, `ProfileService`, `BillingService`, `NotificationService` + +--- + +### Shotgun Surgery (Хірургія дробовиком) + +**Ознаки:** +- Одна зміна вимагає редагування в багатьох класах +- Мала функція потребує правок у 10+ файлах +- Зміни розкидані, важко знайти всі + +**Чому це погано:** +- Легко пропустити місце +- Високий звʼязок (coupling) +- Зміни схильні до помилок + +**Рефакторинги:** +- Move Method +- Move Field +- Inline Class + +**Виявлення:** +Шукайте: додавання одного поля вимагає змін у >5 файлах. + +--- + +### Parallel Inheritance Hierarchies (Паралельні ієрархії успадкування) + +**Ознаки:** +- Створення підкласу в одній ієрархії вимагає підкласу в іншій +- Префікси класів збігаються (напр., `DatabaseOrder`, `DatabaseProduct`) + +**Чому це погано:** +- Подвійне обслуговування +- Звʼязок між ієрархіями +- Легко забути одну сторону + +**Рефакторинги:** +- Move Method +- Move Field +- Усунути одну ієрархію + +--- + +## Непотрібне (Dispensables) + +Щось непотрібне, що слід видалити. + +### Comments (Надмірні коментарі) + +**Ознаки:** +- Коментарі, що пояснюють, що робить код +- Закоментований код +- TODO/FIXME, що залишаються назавжди +- Вибачення в коментарях + +**Чому це погано:** +- Коментарі брешуть (розсинхронізуються) +- Код має бути самодокументованим +- Мертвий код створює плутанину + +**Рефакторинги:** +- Extract Method (назва пояснює що) +- Rename (ясність без коментарів) +- Видалити закоментований код +- Introduce Assertion + +**Хороші vs погані коментарі:** +```javascript +// ПОГАНО: Пояснює що +// Цикл по користувачах і перевірка чи активні +for (const user of users) { + if (user.status === 'active') { } +} + +// ДОБРЕ: Пояснює чому +// Лише активні — неактивні обробляються задачею очищення +const activeUsers = users.filter(u => u.isActive); +``` + +--- + +### Duplicate Code (Дубльований код) + +**Ознаки:** +- Той самий код у кількох місцях +- Схожий код з малими варіаціями +- Патерни копі-пасту + +**Чому це погано:** +- Виправлення помилок потрібне в кількох місцях +- Ризик неконсистентності +- Роздута кодова база + +**Рефакторинги:** +- Extract Method +- Extract Class +- Pull Up Method (в ієрархіях) +- Form Template Method + +**Правило виявлення:** +Будь-який код, дубльований 3+ разів, слід витягти. + +--- + +### Lazy Class (Ледачий клас) + +**Ознаки:** +- Клас не робить достатньо для виправдання свого існування +- Обгортка без доданої цінності +- Результат надмірної інженерії + +**Чому це погано:** +- Накладні витрати обслуговування +- Непотрібна непрямість +- Складність без користі + +**Рефакторинги:** +- Inline Class +- Collapse Hierarchy + +--- + +### Dead Code (Мертвий код) + +**Ознаки:** +- Недосяжний код +- Невикористані змінні/методи/класи +- Закоментований код +- Код за неможливими умовами + +**Чому це погано:** +- Плутанина +- Тягар обслуговування +- Уповільнює розуміння + +**Рефакторинги:** +- Remove Dead Code +- Safe Delete + +**Виявлення:** +```bash +# Шукати невикористані експорти +# Шукати невикористані функції +# Попередження IDE "unused" +``` + +--- + +### Speculative Generality (Спекулятивна загальність) + +**Ознаки:** +- Абстрактні класи з одним підкласом +- Невикористані параметри «на майбутнє» +- Методи, що лише делегують +- «Фреймворк» для одного випадку + +**Чому це погано:** +- Складність без користі +- YAGNI (You Ain't Gonna Need It — Вам це не знадобиться) +- Важче зрозуміти + +**Рефакторинги:** +- Collapse Hierarchy +- Inline Class +- Remove Parameter +- Rename Method + +--- + +## Звʼязувачі (Couplers) + +Запахи, що представляють надмірний звʼязок між класами. + +### Feature Envy (Заздрість до функцій) + +**Ознаки:** +- Метод використовує більше даних іншого класу, ніж свого +- Багато викликів геттерів іншого обʼєкта +- Дані та поведінка розділені + +**Чому це погано:** +- Неправильне розташування поведінки +- Погана інкапсуляція +- Важко супроводжувати + +**Рефакторинги:** +- Move Method +- Move Field +- Extract Method (потім перемістити) + +**Приклад (до):** +```javascript +class Order { + getDiscountedPrice(customer) { + // Інтенсивно використовує дані customer + if (customer.loyaltyYears > 5) { + return this.price * customer.discountRate; + } + return this.price; + } +} +``` + +**Приклад (після):** +```javascript +class Customer { + getDiscountedPriceFor(price) { + if (this.loyaltyYears > 5) { + return price * this.discountRate; + } + return price; + } +} +``` + +--- + +### Inappropriate Intimacy (Недоречна інтимність) + +**Ознаки:** +- Класи отримують доступ до приватних частин один одного +- Двосторонні посилання +- Підкласи знають занадто багато про батьків + +**Чому це погано:** +- Високий звʼязок +- Зміни каскадуються +- Важко модифікувати один без іншого + +**Рефакторинги:** +- Move Method +- Move Field +- Change Bidirectional to Unidirectional +- Extract Class +- Hide Delegate + +--- + +### Message Chains (Ланцюжки повідомлень) + +**Ознаки:** +- Довгі ланцюжки викликів: `a.getB().getC().getD().getValue()` +- Клієнт залежить від структури навігації +- Код типу «потяг-катастрофа» (train wreck) + +**Чому це погано:** +- Крихкий — будь-яка зміна ламає ланцюжок +- Порушує Закон Деметри +- Звʼязок зі структурою + +**Рефакторинги:** +- Hide Delegate +- Extract Method +- Move Method + +**Приклад:** +```javascript +// Погано: Ланцюжок повідомлень +const managerName = employee.getDepartment().getManager().getName(); + +// Краще: Приховати делегування +const managerName = employee.getManagerName(); +``` + +--- + +### Middle Man (Посередник) + +**Ознаки:** +- Клас, що лише делегує іншому +- Половина методів — делегування +- Немає доданої цінності + +**Чому це погано:** +- Непотрібна непрямість +- Накладні витрати обслуговування +- Заплутана архітектура + +**Рефакторинги:** +- Remove Middle Man +- Inline Method + +--- + +## Посібник серйозності запахів + +| Серйозність | Опис | Дія | +|-------------|------|-----| +| **Критичний** | Блокує розробку, спричиняє помилки | Виправити негайно | +| **Високий** | Значний тягар обслуговування | Виправити в поточному спринті | +| **Середній** | Помітний, але керований | Запланувати на найближче майбутнє | +| **Низький** | Незначна незручність | Виправляти при нагоді | + +--- + +## Контрольний список швидкого виявлення + +Використовуйте цей список при скануванні коду: + +- [ ] Є методи > 30 рядків? +- [ ] Є класи > 300 рядків? +- [ ] Є методи з > 4 параметрами? +- [ ] Є дубльовані блоки коду? +- [ ] Є switch/case за кодами типів? +- [ ] Є невикористаний код? +- [ ] Є методи, що інтенсивно використовують дані іншого класу? +- [ ] Є довгі ланцюжки викликів? +- [ ] Є коментарі, що пояснюють «що», а не «чому»? +- [ ] Є примітиви, що мають бути обʼєктами? + +--- + +## Додаткове читання + +- Fowler, M. (2018). *Refactoring: Improving the Design of Existing Code* (2nd ed.) +- Kerievsky, J. (2004). *Refactoring to Patterns* +- Feathers, M. (2004). *Working Effectively with Legacy Code* diff --git a/uk/03-skills/refactor/references/refactoring-catalog.md b/uk/03-skills/refactor/references/refactoring-catalog.md new file mode 100644 index 0000000..fb29009 --- /dev/null +++ b/uk/03-skills/refactor/references/refactoring-catalog.md @@ -0,0 +1,1019 @@ +# Каталог рефакторингів + +Курований каталог технік рефакторингу з книги Мартіна Фаулера *Refactoring* (2-ге видання). Кожен рефакторинг включає мотивацію, покрокову механіку та приклади. + +> «Рефакторинг визначається своєю механікою — точною послідовністю кроків, яких ви дотримуєтесь для здійснення зміни.» — Мартін Фаулер + +--- + +## Як використовувати цей каталог + +1. **Виявити запах** за допомогою довідника запахів коду +2. **Знайти відповідний рефакторинг** у цьому каталозі +3. **Дотримуватися механіки** крок за кроком +4. **Тестувати після кожного кроку** для збереження поведінки + +**Золоте правило**: Якщо будь-який крок займає більше 10 хвилин, розбийте його на менші кроки. + +--- + +## Найпоширеніші рефакторинги + +### Extract Method + +**Коли використовувати**: Довгий метод, дубльований код, потрібно назвати концепцію + +**Мотивація**: Перетворити фрагмент коду на метод, назва якого пояснює призначення. + +**Механіка**: +1. Створити новий метод, названий за тим, що він робить (не як) +2. Скопіювати фрагмент коду в новий метод +3. Просканувати локальні змінні, використані у фрагменті +4. Передати локальні змінні як параметри (або оголосити в методі) +5. Обробити повернені значення належним чином +6. Замінити оригінальний фрагмент викликом нового методу +7. Тестувати + +**До**: +```javascript +function printOwing(invoice) { + let outstanding = 0; + + console.log("***********************"); + console.log("**** Customer Owes ****"); + console.log("***********************"); + + // Обчислення заборгованості + for (const order of invoice.orders) { + outstanding += order.amount; + } + + // Друк деталей + console.log(`name: ${invoice.customer}`); + console.log(`amount: ${outstanding}`); +} +``` + +**Після**: +```javascript +function printOwing(invoice) { + printBanner(); + const outstanding = calculateOutstanding(invoice); + printDetails(invoice, outstanding); +} + +function printBanner() { + console.log("***********************"); + console.log("**** Customer Owes ****"); + console.log("***********************"); +} + +function calculateOutstanding(invoice) { + return invoice.orders.reduce((sum, order) => sum + order.amount, 0); +} + +function printDetails(invoice, outstanding) { + console.log(`name: ${invoice.customer}`); + console.log(`amount: ${outstanding}`); +} +``` + +--- + +### Inline Method + +**Коли використовувати**: Тіло методу таке ж зрозуміле, як його назва; надмірне делегування + +**Мотивація**: Видалити непотрібну непрямість, коли метод не додає цінності. + +**Механіка**: +1. Перевірити, що метод не є поліморфним +2. Знайти всі виклики методу +3. Замінити кожен виклик тілом методу +4. Тестувати після кожної заміни +5. Видалити визначення методу + +**До**: +```javascript +function getRating(driver) { + return moreThanFiveLateDeliveries(driver) ? 2 : 1; +} + +function moreThanFiveLateDeliveries(driver) { + return driver.numberOfLateDeliveries > 5; +} +``` + +**Після**: +```javascript +function getRating(driver) { + return driver.numberOfLateDeliveries > 5 ? 2 : 1; +} +``` + +--- + +### Extract Variable + +**Коли використовувати**: Складний вираз, важкий для розуміння + +**Мотивація**: Дати назву частині складного виразу. + +**Механіка**: +1. Переконатися, що вираз не має побічних ефектів +2. Оголосити незмінну змінну +3. Встановити її як результат виразу (або частини) +4. Замінити оригінальний вираз змінною +5. Тестувати + +**До**: +```javascript +return order.quantity * order.itemPrice - + Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + + Math.min(order.quantity * order.itemPrice * 0.1, 100); +``` + +**Після**: +```javascript +const basePrice = order.quantity * order.itemPrice; +const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05; +const shipping = Math.min(basePrice * 0.1, 100); +return basePrice - quantityDiscount + shipping; +``` + +--- + +### Inline Variable + +**Коли використовувати**: Назва змінної не передає більше, ніж вираз + +**Мотивація**: Видалити непотрібну непрямість. + +**Механіка**: +1. Перевірити, що права частина не має побічних ефектів +2. Якщо змінна не незмінна, зробити її такою і тестувати +3. Знайти перше посилання та замінити виразом +4. Тестувати +5. Повторити для всіх посилань +6. Видалити оголошення та присвоєння +7. Тестувати + +--- + +### Rename Variable + +**Коли використовувати**: Назва не чітко передає призначення + +**Мотивація**: Хороші назви критичні для чистого коду. + +**Механіка**: +1. Якщо змінна широко використовується, розглянути інкапсуляцію +2. Знайти всі посилання +3. Змінити кожне посилання +4. Тестувати + +**Поради**: +- Використовуйте назви, що розкривають намір +- Уникайте абревіатур +- Використовуйте доменну термінологію + +```javascript +// Погано +const d = 30; +const x = users.filter(u => u.a); + +// Добре +const daysSinceLastLogin = 30; +const activeUsers = users.filter(user => user.isActive); +``` + +--- + +### Change Function Declaration + +**Коли використовувати**: Назва функції не пояснює призначення, параметри потребують зміни + +**Мотивація**: Хороші назви функцій роблять код самодокументованим. + +**Механіка (проста)**: +1. Видалити непотрібні параметри +2. Змінити назву +3. Додати потрібні параметри +4. Тестувати + +**Механіка (міграція — для складних змін)**: +1. Якщо видаляєте параметр, переконайтеся, що він не використовується +2. Створити нову функцію з бажаним оголошенням +3. Зробити так, щоб стара функція викликала нову +4. Тестувати +5. Змінити виклики на нову функцію +6. Тестувати після кожного +7. Видалити стару функцію + +**До**: +```javascript +function circum(radius) { + return 2 * Math.PI * radius; +} +``` + +**Після**: +```javascript +function circumference(radius) { + return 2 * Math.PI * radius; +} +``` + +--- + +### Encapsulate Variable + +**Коли використовувати**: Прямий доступ до даних з кількох місць + +**Мотивація**: Забезпечити чітку точку доступу для маніпуляції даними. + +**Механіка**: +1. Створити функції getter та setter +2. Знайти всі посилання +3. Замінити читання на getter +4. Замінити записи на setter +5. Тестувати після кожної зміни +6. Обмежити видимість змінної + +**До**: +```javascript +let defaultOwner = { firstName: "Martin", lastName: "Fowler" }; + +// Використовується в багатьох місцях +spaceship.owner = defaultOwner; +``` + +**Після**: +```javascript +let defaultOwnerData = { firstName: "Martin", lastName: "Fowler" }; + +function defaultOwner() { return defaultOwnerData; } +function setDefaultOwner(arg) { defaultOwnerData = arg; } + +spaceship.owner = defaultOwner(); +``` + +--- + +### Introduce Parameter Object + +**Коли використовувати**: Кілька параметрів, що часто зʼявляються разом + +**Мотивація**: Згрупувати дані, що природно належать разом. + +**Механіка**: +1. Створити новий клас/структуру для згрупованих параметрів +2. Тестувати +3. Використати Change Function Declaration для додавання нового обʼєкта +4. Тестувати +5. Для кожного параметра в групі видалити його з функції та використати новий обʼєкт +6. Тестувати після кожного + +**До**: +```javascript +function amountInvoiced(startDate, endDate) { ... } +function amountReceived(startDate, endDate) { ... } +function amountOverdue(startDate, endDate) { ... } +``` + +**Після**: +```javascript +class DateRange { + constructor(start, end) { + this.start = start; + this.end = end; + } +} + +function amountInvoiced(dateRange) { ... } +function amountReceived(dateRange) { ... } +function amountOverdue(dateRange) { ... } +``` + +--- + +### Combine Functions into Class + +**Коли використовувати**: Кілька функцій оперують тими самими даними + +**Мотивація**: Згрупувати функції з даними, над якими вони працюють. + +**Механіка**: +1. Застосувати Encapsulate Record до спільних даних +2. Перемістити кожну функцію в клас +3. Тестувати після кожного переміщення +4. Замінити аргументи даних використанням полів класу + +**До**: +```javascript +function base(reading) { ... } +function taxableCharge(reading) { ... } +function calculateBaseCharge(reading) { ... } +``` + +**Після**: +```javascript +class Reading { + constructor(data) { this._data = data; } + + get base() { ... } + get taxableCharge() { ... } + get calculateBaseCharge() { ... } +} +``` + +--- + +### Split Phase + +**Коли використовувати**: Код працює з двома різними речами + +**Мотивація**: Розділити код на окремі фази з чіткими межами. + +**Механіка**: +1. Створити другу функцію для другої фази +2. Тестувати +3. Ввести проміжну структуру даних між фазами +4. Тестувати +5. Витягти першу фазу в окрему функцію +6. Тестувати + +**До**: +```javascript +function priceOrder(product, quantity, shippingMethod) { + const basePrice = product.basePrice * quantity; + const discount = Math.max(quantity - product.discountThreshold, 0) + * product.basePrice * product.discountRate; + const shippingPerCase = (basePrice > shippingMethod.discountThreshold) + ? shippingMethod.discountedFee : shippingMethod.feePerCase; + const shippingCost = quantity * shippingPerCase; + return basePrice - discount + shippingCost; +} +``` + +**Після**: +```javascript +function priceOrder(product, quantity, shippingMethod) { + const priceData = calculatePricingData(product, quantity); + return applyShipping(priceData, shippingMethod); +} + +function calculatePricingData(product, quantity) { + const basePrice = product.basePrice * quantity; + const discount = Math.max(quantity - product.discountThreshold, 0) + * product.basePrice * product.discountRate; + return { basePrice, quantity, discount }; +} + +function applyShipping(priceData, shippingMethod) { + const shippingPerCase = (priceData.basePrice > shippingMethod.discountThreshold) + ? shippingMethod.discountedFee : shippingMethod.feePerCase; + const shippingCost = priceData.quantity * shippingPerCase; + return priceData.basePrice - priceData.discount + shippingCost; +} +``` + +--- + +## Переміщення функцій (Moving Features) + +### Move Method + +**Коли використовувати**: Метод використовує більше можливостей іншого класу, ніж свого + +**Мотивація**: Розміщувати функції разом з даними, які вони використовують найбільше. + +**Механіка**: +1. Дослідити всі елементи програми, використані методом у своєму класі +2. Перевірити, чи метод є поліморфним +3. Скопіювати метод у цільовий клас +4. Адаптувати до нового контексту +5. Зробити оригінальний метод делегуючим до цільового +6. Тестувати +7. Розглянути видалення оригінального методу + +--- + +### Move Field + +**Коли використовувати**: Поле використовується більше іншим класом + +**Мотивація**: Тримати дані разом з функціями, що їх використовують. + +**Механіка**: +1. Інкапсулювати поле, якщо ще не зроблено +2. Тестувати +3. Створити поле в цільовому класі +4. Оновити посилання на використання цільового поля +5. Тестувати +6. Видалити оригінальне поле + +--- + +### Move Statements into Function + +**Коли використовувати**: Той самий код завжди зʼявляється разом з викликом функції + +**Мотивація**: Видалити дублювання, перемістивши повторюваний код у функцію. + +**Механіка**: +1. Витягти повторюваний код у функцію, якщо ще не зроблено +2. Перемістити оператори в цю функцію +3. Тестувати +4. Якщо виклики більше не потребують окремих операторів, видалити їх + +--- + +### Move Statements to Callers + +**Коли використовувати**: Загальна поведінка різниться між викликачами + +**Мотивація**: Коли поведінка має відрізнятися, перемістити її з функції. + +**Механіка**: +1. Використати Extract Method на коді для переміщення +2. Використати Inline Method на оригінальній функції +3. Видалити тепер вбудований виклик +4. Перемістити витягнутий код до кожного виклику +5. Тестувати + +--- + +## Організація даних (Organizing Data) + +### Replace Primitive with Object + +**Коли використовувати**: Елемент даних потребує більше поведінки, ніж просте значення + +**Мотивація**: Інкапсулювати дані разом з їхньою поведінкою. + +**Механіка**: +1. Застосувати Encapsulate Variable +2. Створити простий клас значення +3. Змінити setter для створення нового екземпляра +4. Змінити getter для повернення значення +5. Тестувати +6. Додати багатшу поведінку до нового класу + +**До**: +```javascript +class Order { + constructor(data) { + this.priority = data.priority; // рядок: "high", "rush" тощо + } +} + +// Використання +if (order.priority === "high" || order.priority === "rush") { ... } +``` + +**Після**: +```javascript +class Priority { + constructor(value) { + if (!Priority.legalValues().includes(value)) + throw new Error(`Invalid priority: ${value}`); + this._value = value; + } + + static legalValues() { return ['low', 'normal', 'high', 'rush']; } + get value() { return this._value; } + + higherThan(other) { + return Priority.legalValues().indexOf(this._value) > + Priority.legalValues().indexOf(other._value); + } +} + +// Використання +if (order.priority.higherThan(new Priority("normal"))) { ... } +``` + +--- + +### Replace Temp with Query + +**Коли використовувати**: Тимчасова змінна зберігає результат виразу + +**Мотивація**: Зробити код зрозумілішим, витягнувши вираз у функцію. + +**Механіка**: +1. Перевірити, що змінна присвоюється лише один раз +2. Витягти праву частину присвоєння в метод +3. Замінити посилання на тимчасову змінну викликом методу +4. Тестувати +5. Видалити оголошення та присвоєння тимчасової змінної + +**До**: +```javascript +const basePrice = this._quantity * this._itemPrice; +if (basePrice > 1000) { + return basePrice * 0.95; +} else { + return basePrice * 0.98; +} +``` + +**Після**: +```javascript +get basePrice() { + return this._quantity * this._itemPrice; +} + +// В методі +if (this.basePrice > 1000) { + return this.basePrice * 0.95; +} else { + return this.basePrice * 0.98; +} +``` + +--- + +## Спрощення умовної логіки (Simplifying Conditional Logic) + +### Decompose Conditional + +**Коли використовувати**: Складний умовний оператор (if-then-else) + +**Мотивація**: Зробити намір зрозумілим, витягнувши умови та дії. + +**Механіка**: +1. Застосувати Extract Method на умові +2. Застосувати Extract Method на then-гілці +3. Застосувати Extract Method на else-гілці (якщо є) + +**До**: +```javascript +if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)) { + charge = quantity * plan.summerRate; +} else { + charge = quantity * plan.regularRate + plan.regularServiceCharge; +} +``` + +**Після**: +```javascript +if (isSummer(aDate, plan)) { + charge = summerCharge(quantity, plan); +} else { + charge = regularCharge(quantity, plan); +} + +function isSummer(date, plan) { + return !date.isBefore(plan.summerStart) && !date.isAfter(plan.summerEnd); +} + +function summerCharge(quantity, plan) { + return quantity * plan.summerRate; +} + +function regularCharge(quantity, plan) { + return quantity * plan.regularRate + plan.regularServiceCharge; +} +``` + +--- + +### Consolidate Conditional Expression + +**Коли використовувати**: Кілька умов з однаковим результатом + +**Мотивація**: Зробити зрозумілим, що умови є однією перевіркою. + +**Механіка**: +1. Перевірити відсутність побічних ефектів в умовах +2. Обʼєднати умови за допомогою `and` або `or` +3. Розглянути Extract Method на обʼєднаній умові + +**До**: +```javascript +if (employee.seniority < 2) return 0; +if (employee.monthsDisabled > 12) return 0; +if (employee.isPartTime) return 0; +``` + +**Після**: +```javascript +if (isNotEligibleForDisability(employee)) return 0; + +function isNotEligibleForDisability(employee) { + return employee.seniority < 2 || + employee.monthsDisabled > 12 || + employee.isPartTime; +} +``` + +--- + +### Replace Nested Conditional with Guard Clauses + +**Коли використовувати**: Глибоко вкладені умови ускладнюють відстеження потоку + +**Мотивація**: Використовувати захисні вирази (guard clauses) для спеціальних випадків, зберігаючи нормальний потік зрозумілим. + +**Механіка**: +1. Знайти умови спеціальних випадків +2. Замінити їх захисними виразами з раннім поверненням +3. Тестувати після кожної зміни + +**До**: +```javascript +function payAmount(employee) { + let result; + if (employee.isSeparated) { + result = { amount: 0, reasonCode: "SEP" }; + } else { + if (employee.isRetired) { + result = { amount: 0, reasonCode: "RET" }; + } else { + result = calculateNormalPay(employee); + } + } + return result; +} +``` + +**Після**: +```javascript +function payAmount(employee) { + if (employee.isSeparated) return { amount: 0, reasonCode: "SEP" }; + if (employee.isRetired) return { amount: 0, reasonCode: "RET" }; + return calculateNormalPay(employee); +} +``` + +--- + +### Replace Conditional with Polymorphism + +**Коли використовувати**: Switch/case за типом, умовна логіка що варіюється за типом + +**Мотивація**: Дозволити обʼєктам обробляти свою поведінку самостійно. + +**Механіка**: +1. Створити ієрархію класів (якщо не існує) +2. Використати фабричну функцію для створення обʼєктів +3. Перемістити умовну логіку в метод суперкласу +4. Створити метод підкласу для кожного випадку +5. Видалити оригінальну умову + +**До**: +```javascript +function plumage(bird) { + switch (bird.type) { + case 'EuropeanSwallow': + return "average"; + case 'AfricanSwallow': + return (bird.numberOfCoconuts > 2) ? "tired" : "average"; + case 'NorwegianBlueParrot': + return (bird.voltage > 100) ? "scorched" : "beautiful"; + default: + return "unknown"; + } +} +``` + +**Після**: +```javascript +class Bird { + get plumage() { return "unknown"; } +} + +class EuropeanSwallow extends Bird { + get plumage() { return "average"; } +} + +class AfricanSwallow extends Bird { + get plumage() { + return (this.numberOfCoconuts > 2) ? "tired" : "average"; + } +} + +class NorwegianBlueParrot extends Bird { + get plumage() { + return (this.voltage > 100) ? "scorched" : "beautiful"; + } +} + +function createBird(data) { + switch (data.type) { + case 'EuropeanSwallow': return new EuropeanSwallow(data); + case 'AfricanSwallow': return new AfricanSwallow(data); + case 'NorwegianBlueParrot': return new NorwegianBlueParrot(data); + default: return new Bird(data); + } +} +``` + +--- + +### Introduce Special Case (Null Object) + +**Коли використовувати**: Повторні перевірки на null для спеціальних випадків + +**Мотивація**: Повертати спеціальний обʼєкт, що обробляє спеціальний випадок. + +**Механіка**: +1. Створити клас спеціального випадку з очікуваним інтерфейсом +2. Додати перевірку isSpecialCase +3. Ввести фабричний метод +4. Замінити перевірки на null використанням обʼєкта спеціального випадку +5. Тестувати + +**До**: +```javascript +const customer = site.customer; +// ... багато місць з перевіркою +if (customer === "unknown") { + customerName = "occupant"; +} else { + customerName = customer.name; +} +``` + +**Після**: +```javascript +class UnknownCustomer { + get name() { return "occupant"; } + get billingPlan() { return registry.defaultPlan; } +} + +// Фабричний метод +function customer(site) { + return site.customer === "unknown" + ? new UnknownCustomer() + : site.customer; +} + +// Використання — перевірки на null не потрібні +const customerName = customer.name; +``` + +--- + +## Рефакторинг API (Refactoring APIs) + +### Separate Query from Modifier + +**Коли використовувати**: Функція і повертає значення, і має побічні ефекти + +**Мотивація**: Зробити зрозумілим, які операції мають побічні ефекти. + +**Механіка**: +1. Створити нову функцію-запит +2. Скопіювати логіку повернення оригінальної функції +3. Змінити оригінал, щоб повертав void +4. Замінити виклики, що використовують повернене значення +5. Тестувати + +**До**: +```javascript +function alertForMiscreant(people) { + for (const p of people) { + if (p === "Don") { + setOffAlarms(); + return "Don"; + } + if (p === "John") { + setOffAlarms(); + return "John"; + } + } + return ""; +} +``` + +**Після**: +```javascript +function findMiscreant(people) { + for (const p of people) { + if (p === "Don") return "Don"; + if (p === "John") return "John"; + } + return ""; +} + +function alertForMiscreant(people) { + if (findMiscreant(people) !== "") setOffAlarms(); +} +``` + +--- + +### Parameterize Function + +**Коли використовувати**: Кілька функцій роблять схожі речі з різними значеннями + +**Мотивація**: Видалити дублювання додаванням параметра. + +**Механіка**: +1. Обрати одну функцію +2. Додати параметр для варійованого літерала +3. Змінити тіло для використання параметра +4. Тестувати +5. Змінити виклики на параметризовану версію +6. Видалити тепер невикористані функції + +**До**: +```javascript +function tenPercentRaise(person) { + person.salary = person.salary * 1.10; +} + +function fivePercentRaise(person) { + person.salary = person.salary * 1.05; +} +``` + +**Після**: +```javascript +function raise(person, factor) { + person.salary = person.salary * (1 + factor); +} + +// Використання +raise(person, 0.10); +raise(person, 0.05); +``` + +--- + +### Remove Flag Argument + +**Коли використовувати**: Булевий параметр, що змінює поведінку функції + +**Мотивація**: Зробити поведінку явною через окремі функції. + +**Механіка**: +1. Створити явну функцію для кожного значення прапорця +2. Замінити кожен виклик відповідною новою функцією +3. Тестувати після кожної зміни +4. Видалити оригінальну функцію + +**До**: +```javascript +function bookConcert(customer, isPremium) { + if (isPremium) { + // логіка преміум-бронювання + } else { + // логіка звичайного бронювання + } +} + +bookConcert(customer, true); +bookConcert(customer, false); +``` + +**Після**: +```javascript +function bookPremiumConcert(customer) { + // логіка преміум-бронювання +} + +function bookRegularConcert(customer) { + // логіка звичайного бронювання +} + +bookPremiumConcert(customer); +bookRegularConcert(customer); +``` + +--- + +## Робота з успадкуванням (Dealing with Inheritance) + +### Pull Up Method + +**Коли використовувати**: Той самий метод у кількох підкласах + +**Мотивація**: Видалити дублювання в ієрархії класів. + +**Механіка**: +1. Перевірити, що методи ідентичні +2. Перевірити, що сигнатури однакові +3. Створити новий метод у суперкласі +4. Скопіювати тіло з одного підкласу +5. Видалити один метод підкласу, тестувати +6. Видалити інші методи підкласів, тестувати кожен + +--- + +### Push Down Method + +**Коли використовувати**: Поведінка релевантна лише для підмножини підкласів + +**Мотивація**: Розмістити метод там, де він використовується. + +**Механіка**: +1. Скопіювати метод у кожен підклас, що його потребує +2. Видалити метод із суперкласу +3. Тестувати +4. Видалити з підкласів, що його не потребують +5. Тестувати + +--- + +### Replace Subclass with Delegate + +**Коли використовувати**: Успадкування використовується некоректно, потрібна більша гнучкість + +**Мотивація**: Віддавати перевагу композиції над успадкуванням, коли доречно. + +**Механіка**: +1. Створити порожній клас для делегата +2. Додати поле в клас-хост для утримання делегата +3. Створити конструктор для делегата, що викликається з хоста +4. Перемістити функціональність до делегата +5. Тестувати після кожного переміщення +6. Замінити успадкування делегуванням + +--- + +## Extract Class + +**Коли використовувати**: Великий клас з кількома відповідальностями + +**Мотивація**: Розділити клас для збереження єдиної відповідальності. + +**Механіка**: +1. Вирішити, як розділити відповідальності +2. Створити новий клас +3. Перемістити поле з оригіналу до нового класу +4. Тестувати +5. Перемістити методи з оригіналу до нового класу +6. Тестувати після кожного переміщення +7. Переглянути та перейменувати обидва класи +8. Вирішити, як відкрити новий клас + +**До**: +```javascript +class Person { + get name() { return this._name; } + set name(arg) { this._name = arg; } + get officeAreaCode() { return this._officeAreaCode; } + set officeAreaCode(arg) { this._officeAreaCode = arg; } + get officeNumber() { return this._officeNumber; } + set officeNumber(arg) { this._officeNumber = arg; } + + get telephoneNumber() { + return `(${this._officeAreaCode}) ${this._officeNumber}`; + } +} +``` + +**Після**: +```javascript +class Person { + constructor() { + this._telephoneNumber = new TelephoneNumber(); + } + get name() { return this._name; } + set name(arg) { this._name = arg; } + get telephoneNumber() { return this._telephoneNumber.toString(); } + get officeAreaCode() { return this._telephoneNumber.areaCode; } + set officeAreaCode(arg) { this._telephoneNumber.areaCode = arg; } +} + +class TelephoneNumber { + get areaCode() { return this._areaCode; } + set areaCode(arg) { this._areaCode = arg; } + get number() { return this._number; } + set number(arg) { this._number = arg; } + toString() { return `(${this._areaCode}) ${this._number}`; } +} +``` + +--- + +## Короткий довідник: Запах → Рефакторинг + +| Запах коду | Основний рефакторинг | Альтернатива | +|------------|---------------------|--------------| +| Long Method | Extract Method | Replace Temp with Query | +| Duplicate Code | Extract Method | Pull Up Method | +| Large Class | Extract Class | Extract Subclass | +| Long Parameter List | Introduce Parameter Object | Preserve Whole Object | +| Feature Envy | Move Method | Extract Method + Move | +| Data Clumps | Extract Class | Introduce Parameter Object | +| Primitive Obsession | Replace Primitive with Object | Replace Type Code | +| Switch Statements | Replace Conditional with Polymorphism | Replace Type Code | +| Temporary Field | Extract Class | Introduce Null Object | +| Message Chains | Hide Delegate | Extract Method | +| Middle Man | Remove Middle Man | Inline Method | +| Divergent Change | Extract Class | Split Phase | +| Shotgun Surgery | Move Method | Inline Class | +| Dead Code | Remove Dead Code | - | +| Speculative Generality | Collapse Hierarchy | Inline Class | + +--- + +## Додаткове читання + +- Fowler, M. (2018). *Refactoring: Improving the Design of Existing Code* (2nd ed.) +- Онлайн-каталог: https://refactoring.com/catalog/ From 1a567be79355f47b855b754dbc9ce87037b1b557 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Thu, 9 Apr 2026 23:59:59 +0300 Subject: [PATCH 12/20] i18n(uk): add missing files, translate P4 root docs - Copy code/image/config files across all modules - Translate brand-voice and code-review templates - Translate CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, STYLE_GUIDE - Copy CHANGELOG as-is (technical log) Ref: luongnv89/claude-howto#63 --- uk/01-slash-commands/pr-slash-command.png | Bin 0 -> 34051 bytes uk/02-memory/memory-ask-claude.png | Bin 0 -> 97611 bytes uk/02-memory/memory-saved.png | Bin 0 -> 303476 bytes uk/03-skills/.gitignore | 5 + .../brand-voice/templates/email-template.txt | 14 + .../templates/social-post-template.txt | 4 + uk/03-skills/brand-voice/tone-examples.md | 13 + .../code-review/scripts/analyze-metrics.py | 35 + .../code-review/scripts/compare-complexity.py | 174 +++ .../code-review/templates/finding-template.md | 112 ++ .../code-review/templates/review-checklist.md | 47 + uk/03-skills/doc-generator/generate-docs.py | 55 + .../refactor/scripts/analyze-complexity.py | 545 +++++++++ .../refactor/scripts/detect-smells.py | 711 +++++++++++ uk/05-mcp/README.md | 1086 +++++++++++++++++ uk/05-mcp/database-mcp.json | 11 + uk/05-mcp/filesystem-mcp.json | 8 + uk/05-mcp/github-mcp.json | 11 + uk/05-mcp/multi-mcp.json | 29 + uk/06-hooks/context-tracker-tiktoken.py | 149 +++ uk/06-hooks/context-tracker.py | 126 ++ uk/06-hooks/dependency-check.sh | 156 +++ uk/06-hooks/format-code.sh | 49 + uk/06-hooks/log-bash.sh | 31 + uk/06-hooks/notify-team.sh | 68 ++ uk/06-hooks/pre-commit.sh | 50 + uk/06-hooks/pre-tool-check.sh | 96 ++ uk/06-hooks/security-scan.sh | 78 ++ uk/06-hooks/validate-prompt.sh | 54 + .../.claude-plugin/plugin.json | 9 + uk/07-plugins/devops-automation/README.md | 107 ++ .../agents/alert-analyzer.md | 14 + .../agents/deployment-specialist.md | 14 + .../agents/incident-commander.md | 14 + .../devops-automation/commands/deploy.md | 15 + .../devops-automation/commands/incident.md | 16 + .../devops-automation/commands/rollback.md | 14 + .../devops-automation/commands/status.md | 15 + .../devops-automation/hooks/post-deploy.js | 34 + .../devops-automation/hooks/pre-deploy.js | 35 + .../mcp/kubernetes-config.json | 11 + .../devops-automation/scripts/deploy.sh | 28 + .../devops-automation/scripts/health-check.sh | 30 + .../devops-automation/scripts/rollback.sh | 25 + .../documentation/.claude-plugin/plugin.json | 9 + uk/07-plugins/documentation/README.md | 119 ++ .../documentation/agents/api-documenter.md | 14 + .../documentation/agents/code-commentator.md | 14 + .../documentation/agents/example-generator.md | 14 + .../commands/generate-api-docs.md | 15 + .../documentation/commands/generate-readme.md | 15 + .../documentation/commands/sync-docs.md | 14 + .../documentation/commands/validate-docs.md | 14 + .../documentation/mcp/github-docs-config.json | 11 + .../documentation/templates/adr-template.md | 39 + .../documentation/templates/api-endpoint.md | 101 ++ .../documentation/templates/function-docs.md | 50 + .../pr-review/.claude-plugin/plugin.json | 9 + uk/07-plugins/pr-review/README.md | 91 ++ .../pr-review/agents/performance-analyzer.md | 13 + .../pr-review/agents/security-reviewer.md | 13 + .../pr-review/agents/test-checker.md | 13 + .../pr-review/commands/check-security.md | 14 + .../pr-review/commands/check-tests.md | 14 + uk/07-plugins/pr-review/commands/review-pr.md | 14 + uk/07-plugins/pr-review/hooks/pre-review.js | 37 + .../pr-review/mcp/github-config.json | 11 + uk/09-advanced-features/config-examples.json | 267 ++++ .../setup-auto-mode-permissions.py | 265 ++++ uk/CHANGELOG.md | 154 +++ uk/CODE_OF_CONDUCT.md | 224 ++++ uk/CONTRIBUTING.md | 385 ++++++ uk/SECURITY.md | 338 +++++ uk/STYLE_GUIDE.md | 637 ++++++++++ uk/TRANSLATION_QUEUE.md | 26 +- 75 files changed, 7039 insertions(+), 13 deletions(-) create mode 100644 uk/01-slash-commands/pr-slash-command.png create mode 100644 uk/02-memory/memory-ask-claude.png create mode 100644 uk/02-memory/memory-saved.png create mode 100644 uk/03-skills/.gitignore create mode 100644 uk/03-skills/brand-voice/templates/email-template.txt create mode 100644 uk/03-skills/brand-voice/templates/social-post-template.txt create mode 100644 uk/03-skills/brand-voice/tone-examples.md create mode 100644 uk/03-skills/code-review/scripts/analyze-metrics.py create mode 100644 uk/03-skills/code-review/scripts/compare-complexity.py create mode 100644 uk/03-skills/code-review/templates/finding-template.md create mode 100644 uk/03-skills/code-review/templates/review-checklist.md create mode 100644 uk/03-skills/doc-generator/generate-docs.py create mode 100644 uk/03-skills/refactor/scripts/analyze-complexity.py create mode 100644 uk/03-skills/refactor/scripts/detect-smells.py create mode 100644 uk/05-mcp/README.md create mode 100644 uk/05-mcp/database-mcp.json create mode 100644 uk/05-mcp/filesystem-mcp.json create mode 100644 uk/05-mcp/github-mcp.json create mode 100644 uk/05-mcp/multi-mcp.json create mode 100644 uk/06-hooks/context-tracker-tiktoken.py create mode 100644 uk/06-hooks/context-tracker.py create mode 100644 uk/06-hooks/dependency-check.sh create mode 100644 uk/06-hooks/format-code.sh create mode 100644 uk/06-hooks/log-bash.sh create mode 100644 uk/06-hooks/notify-team.sh create mode 100644 uk/06-hooks/pre-commit.sh create mode 100644 uk/06-hooks/pre-tool-check.sh create mode 100644 uk/06-hooks/security-scan.sh create mode 100644 uk/06-hooks/validate-prompt.sh create mode 100644 uk/07-plugins/devops-automation/.claude-plugin/plugin.json create mode 100644 uk/07-plugins/devops-automation/README.md create mode 100644 uk/07-plugins/devops-automation/agents/alert-analyzer.md create mode 100644 uk/07-plugins/devops-automation/agents/deployment-specialist.md create mode 100644 uk/07-plugins/devops-automation/agents/incident-commander.md create mode 100644 uk/07-plugins/devops-automation/commands/deploy.md create mode 100644 uk/07-plugins/devops-automation/commands/incident.md create mode 100644 uk/07-plugins/devops-automation/commands/rollback.md create mode 100644 uk/07-plugins/devops-automation/commands/status.md create mode 100644 uk/07-plugins/devops-automation/hooks/post-deploy.js create mode 100644 uk/07-plugins/devops-automation/hooks/pre-deploy.js create mode 100644 uk/07-plugins/devops-automation/mcp/kubernetes-config.json create mode 100644 uk/07-plugins/devops-automation/scripts/deploy.sh create mode 100644 uk/07-plugins/devops-automation/scripts/health-check.sh create mode 100644 uk/07-plugins/devops-automation/scripts/rollback.sh create mode 100644 uk/07-plugins/documentation/.claude-plugin/plugin.json create mode 100644 uk/07-plugins/documentation/README.md create mode 100644 uk/07-plugins/documentation/agents/api-documenter.md create mode 100644 uk/07-plugins/documentation/agents/code-commentator.md create mode 100644 uk/07-plugins/documentation/agents/example-generator.md create mode 100644 uk/07-plugins/documentation/commands/generate-api-docs.md create mode 100644 uk/07-plugins/documentation/commands/generate-readme.md create mode 100644 uk/07-plugins/documentation/commands/sync-docs.md create mode 100644 uk/07-plugins/documentation/commands/validate-docs.md create mode 100644 uk/07-plugins/documentation/mcp/github-docs-config.json create mode 100644 uk/07-plugins/documentation/templates/adr-template.md create mode 100644 uk/07-plugins/documentation/templates/api-endpoint.md create mode 100644 uk/07-plugins/documentation/templates/function-docs.md create mode 100644 uk/07-plugins/pr-review/.claude-plugin/plugin.json create mode 100644 uk/07-plugins/pr-review/README.md create mode 100644 uk/07-plugins/pr-review/agents/performance-analyzer.md create mode 100644 uk/07-plugins/pr-review/agents/security-reviewer.md create mode 100644 uk/07-plugins/pr-review/agents/test-checker.md create mode 100644 uk/07-plugins/pr-review/commands/check-security.md create mode 100644 uk/07-plugins/pr-review/commands/check-tests.md create mode 100644 uk/07-plugins/pr-review/commands/review-pr.md create mode 100644 uk/07-plugins/pr-review/hooks/pre-review.js create mode 100644 uk/07-plugins/pr-review/mcp/github-config.json create mode 100644 uk/09-advanced-features/config-examples.json create mode 100644 uk/09-advanced-features/setup-auto-mode-permissions.py create mode 100644 uk/CHANGELOG.md create mode 100644 uk/CODE_OF_CONDUCT.md create mode 100644 uk/CONTRIBUTING.md create mode 100644 uk/SECURITY.md create mode 100644 uk/STYLE_GUIDE.md diff --git a/uk/01-slash-commands/pr-slash-command.png b/uk/01-slash-commands/pr-slash-command.png new file mode 100644 index 0000000000000000000000000000000000000000..789e5c278312699a754382612f99ce03fa89c0c4 GIT binary patch literal 34051 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Ê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 CDQ+hK literal 0 HcmV?d00001 diff --git a/uk/02-memory/memory-ask-claude.png b/uk/02-memory/memory-ask-claude.png new file mode 100644 index 0000000000000000000000000000000000000000..b2022276cda42ae75e0bdd69f000167f5449274f GIT binary patch literal 97611 zcmeGDcT^Ky`#y?eMMXeGM3AC@A~jT{1{DR7Cek}d?>)2tA_6K+L8_1_O7Fb~0qG^u zOMr-!03k#O1d6|;Y$^@Su@7fX1D{mLjycoNoY!!_)cd(=X+>%ta;-J#?$iWz`8> z?}#w2es-C*F8Ty>_7!JO!Nar1sT^o;S-@sm$quwLzB>CVo`%k!Xd-P`vInmrc$+06H;6SeZNB|Z5mFAL3! zhxapXeW3HYad45Q$>@60(y@CV9?U@@Fx@v3N<}>3#~zp#e`gh#Df;dx01f!TClX1w z$wSk<21N*+pos-{S8knReHz73c}nxrXT#&=T;IX<^%4;mK#`ND$=_sFp9Dju4P;qE zN7SzkEfOS@%LG#H^U%It8fHJ3Ijm$qM0t5%Zud59&w=sNz0qDik0ss?vP->GsI;%2 zaOL9J@;fxQMXoTA1;r$EE?z3#QgJ=$B~rv{`9NM3#?*K1m-Vat7oxA}Z)m10K77SU zx||ao{sCMT;!rOg&q7!h$)p4GL?@40B#AWthCU8goPHO6}yP#KGrgHqia$l6CNQ-y=J0te>qE1_s_rvt>!4$B{29W$KKOlOi>jHg6$(zQPyoCBjaK~Kv4`KRUbAw(m!9Ma z>oR;w6B70Ks(uK7N%+Rpx$7 z6MvoOK;)}aGrbm*XcUOjfklB zFI+Bz(${vc4lYD1&WnA{{Qbfs^T(q)870%(*O-@Vew^9~k6cS6`UZOl=B>V^EX+OS z5Li&3p^^S6;=#$VL1zz%5c0e2W~*oTrRp%b)xgi8JO0=)LuUk;gB`r$jyDeOlMAZ=lH69f@by zyUH^%Gt7=X4GGmPtu+`5M>D^gB1f2zuhGo$oj!d!gxnSZqxtzs4tkTF+BQ`-pZkdZ z1wrN1IU~f|_9WWlQ12h}Be{$*VKQZ5BUD#*mUmJa zlV3c4dQLx_{?l=n6LR;YCTSVMPX9Qs83u2C0wyEN-}qLxAE8GQ*oo$Y2Sb8=3hKM95?fD zgGZqo-W_yVX-u1A^i1`Gt}iYh!XrO>u1HFr$c(u1>CwuQD)!1-ZxskJj{uA-V+lv z-<7;;P<8KdvSF%_ka?YdlBX8=2ovg8vc`^qB-_B-WfirYr6K)cCx=|eT?comt88&>^7NlOxnrNi2F41q zfmSXz+{{#hYl1$d3^9&?hJvK{)AiF$H4w`W2A&LjNzY8D8lNvdYy950-dM1T=wS9E zus~zDW|(30iW7??{s*|2`YueYpVc(-Mfr#FM9<`*Vx`gY@%dGo)emdyBaS1hBV*&f zLmEFaznJ6)sntNpJ=u@mktdzcJjm`S!^4jy-N^g2`d2=vq}urn(I2FKAuMuZBq>8@@G+ljG`qIWJA(V>SgH>{@>#RRphc85LURg-&DrF6I z+qdU4$YsyX)U4%m&^nX(RQj`H8+;HlcpUQtaaL|hcKtT-95I0LWmHQScf4J^AIuFF0E?18{O$F- zmpHw!iL{Fp@CqsV!iRk;q}S)P2Ill z{k{}^v3o?ltPvCUwj?HmUE+paNPoSd@_NjqLV4-J{(^qTY+UUdgYUJxKbW3fa=J9f zdz!aIV?A9wr1vF1OXB&2@2asqUl(63n)Oh1PUO0!PG|l~f0i*UHV`jBBdgp>svBA zv*ZoGe3E%zlo8ICIw6ksIY=PwvUpr^v3M<{ZZcWX4b>jX+URJFE=+lvVgn*o|H$`n zowrb9O1Z<#$}B7rxTo>^ZgmG+N5!u}Tl2n};OJ1ngBn-T_oa`?p&}QP_n)ol8taoi zBP=^WXpOy+{l>7QRY8<~eerZddYy4agLN!EeXZKqnQk0xdN;s~8aPf)*a>w_EuVjo zrZ!a*I~w~o)@*5hDfXk#o#MIea_-7sf!U!;2Lq8GQ`|!;AJr}O>bDg8qGD>2+=339 z_bAs;;k6S6MtVuO>l@wZO@I5gL2t#f(7Y+zvO=GU+}VU#voWzTd#4#^C*su&BfaQx z0jD5h&U$kb$kM_(Q)!k+?Wbnbemm9?W>2fb2w^`bH|mudT(_ap$90#>ik&}SWeqdF zD`j)XN9vYT4Hvz_^zh=C&mvzJ9CG*L9Rto0g_I!3 zt8JvPfr3okoZzD&`)~0{ItC|74xq7qxL-T3u{e%Rj=QotvW;$M+~u3oya`Li`zBm& zAcRt#j+X(!ZAzg%NUvq;pr)m-7&}RQK`CZ@&NUNq+kbEW{r*tbMpjoF|f z^E&I;1G!Yc;8a`Q25qz6)-(IILTI7My&itL z)5WqK2r%B-8mii9XwV1%$7g6x9%G|91soj%Ht?})|8uN->^9AbKc63`p^0*&Ir;ZF zn!x_(=N+&ewfSp*A|aB77WnHDu=#&F{?FNGQ$L;f=lIwM;5(Z8I!dalz+T7N%huM- z+riz37ftgJ_~5L^Vm$i0x6|u5$e{L({@9J@M z9U6ImS>Vvs*2n6)zpIOzx2(Sc_n$Llf#ai(LEP8>oZ{oGz-_4U^tzI}m+kdCBBCOq z+~9N9uV0tKMn(oCDh?7C7Y5D{ z_6~6KvGNyo^XB>MBL7_Hp{=*Im!pS|qr2Pnqw88dclY&C;O0KM(f|DX)lXZ0$N${P z&HL}i0v-@_^bJT%L=^Nt*9Mx(AAKtO)Y0G8#pt1=f9i&*H{1drh4ACUP|t+z&(Ay|Cz798~^v0e>ao|9Xy6LZJdH>93+*{2JSIz+Nm*QKJod22mjx&oMqJohT(*JrgfQ~Bj{O3ad%MOP{rtS9{it&^8fLb`_CP}KKb-0 z`btGl=f`fpK15=Qc_9B-1y;#wCqLwxOIg@@^~Bt8gRe7*Tv)nTiCpe8@t#YthXpi% zKRt*#cdKm2y*9a>QPGq$VDVzW`ev6v-K{)x_!&vpY2BJ>ufnI<_VAz@aDI&`_CctY z-GP2_&Aa7+bUi_vgO?<6_qisg&4(W%@7;_APww5%5K&;b-7UssTMj|~?QV1|pq zF3d`644M9*tc) zUWN71IEM5I$kAg%np|Y>A9m6Z>zxXr;A{`6M9^c>h?Zi{aJHJQ>d$qFAmaK@i+1la zfjp1*(S$)c3&>PJ%I`r>*LdNCtcovdO4KS`rr!o>I8XbFlW5ESmYPg6!Ex-@n-?$W z!muUH=4^M}gk*CZgN&Q}%he#m$zk`9oC-Hn`j&1M;pptu0?#Ldj+9&AA6@1U6R=TuNI`L!c>anWaK>{ zWvl(uay;7^GwG|&W0i1V&V_*|+3ZTLV@#AUHBx$cEdoypbc7^j*#{=SF}P$}AT4H* z)%>03o&d{n)lQaWUy-j^gK1t!sfCnk4n6)@&t8(iU7Unj#qSuTclSFr+vuN+_d@sP zX&pnMjeD#*>OFNIxYgel+&w9fZ$=0%nv?waR_7H)n87aX&a{pej+gde^P91)h*8Bu zk-D;4A;Ypy<39AOcEKLs1a2a|CfpZd?x* zTwt)vb~%=$1Ig9Q?NPqwcDd*ip+vnAlAic$#69)BpXGX>G7D*+fXv)Vlr}kzEvk%* z;qtRBeh|99sluulk|BTaeW5zXyLokZP+&FUdy>-4Tx3N{V^zu%t3Xn!pv|oB#6V$V z+d08kR_y&-kHydG4(~nFq?JG)z?Sw$Y%}tB8|{ZLI$ikXyvz2MN7nkd(KIsq@R68J zzP&Ca7%`Zjc8QXdeuI$h|Ekgjv?*zP@N5hda=ALvJ;=(O<))F*1Oig}%D7=$aqh$u zdu+Ss zxdizpAoUX%-mR~NHpSKB=L!Q*uAzw^-4OYsdO7>&ZhGwK={!s^)x(JTUh@(GePY-7tT~ zu<`$IW5{3!9+f9dGT0fIDHv_E93DVbO5s)%I?ep3)n2=^ei;1S#e4M} zWlsibW_B7K#|NyK(ScauRmD#h`GsmEX7x`9aGt#96qcVr8C+*qnkiY1$9*N=U4DORi$>PFc4%dycPwej-?!Q1>IXM zntvWO?5N$4kZ-X%nOteZ-ruXrH5GX;I|d{YsNYLS##`qwdzIi%nvyM&eOp_Fl%}g? zQuEnN4k6C0qL!9OfdAyEl18&Uj)t zvP(pk3`E1oaFUbRZ0PtmwLE7`O@f_ace88r149Gc3`)a#{F<-TrH zlJr6?D8KqsAT*INXGu&Gc;_cATPE-Pjjfbi`|Hfd-GH9KO?ti#zPxvHDxUQ0ituq( zFz`a*B8|oeWC8?f^XOal;U?!(*}}TX&pyT*qV8W_Pv9cG1wKnB^8!o;GyP`@mKYA8+qcSpFw7Q4IJm1>V=G& z9?k*pdrMTi(biIm#qx-IS?lSF!w^beg5|ZrmP6{DDQM+Dwsn`zVi#BFWitgFKz!#% zAXrF^OZAez*WroXsMW1ghGEb81eae_Z+2emJKF`n4zQ?IUD8UTmI8k*`oK@EaIIB3 zFx|9wiy+aoKu>`V~%zdP{^y@V=RP@1=ChpgLX^nKk?E z*&uxIV!y=Tc~DpEHNp5(D3(r{8gxj|ly|&>(v{e2ch64u(QZv+OD7z{CH)&FL7E(E zPnZnmRQX_+uk0+uEB0)&-n}eL{29*pzB+WL@b}!#T~iB54by<3e%T??2%I57*uPp`sX_5 zI&M(7LiX;1N!ug)R}#QGD94hz>9W^vd+3fEMkva!yD(@3%?1eMP zi$ZI#PC3&o;DbG$0KYl;0Mb%Qd&7jT&5Y**0wrbwK{ZoUUcVr(m3*r3=Rih)bsj<- z5`X~sBz@0@naeNZ^%@fvmnRIF{)aMgsLXe@<-Ah zHGI>kt1IX*xD>k8!$Sw*4mN=6>;LGZ6XT~W!5(&Hk7e=)L_=qs843(Y~K)iA;#Vq;{`_Rg_u%E2)_>_ zAtF?y0kUe{pm&#+ihC3qPTI`8I>U7x)lEK$un)eFgAC9rj1-W-bs-G@Q9S zm(?KTuk&@(@!Vj2ry%~FAiePxYo}|QoZJ4slKNOBnM+S zmUkigeOJ@qyF6Jw4!`OTbqi{r7xxStC!5&`4SQ1iH?!3a`^XB{V>g#l(i@_n@LErF zu4}C6`p*$?qWoP~1*!G+j_eTafTSPj#8Hqjx^BV~_fB6?fXG=ka0m6OQFYawf{S-& zG1!qEssC*{*O^^MZQX5_cFL&R$|C)W3wLbds;^4PgCTaJlbJBnkB~(uUv_GAwzgb6 zpbGp28`|Sl-6taO)^2EbdZiTa1d{zsNFjNz9}~O`66o8vLtki#7p`Tnn{9*(L~(^Y z{3$AK#u>7AquRSCzJa};I9nU*gBz9_RSNyE-=%n{t&!_EQbL~z&$^o|Y;w!GGbR~h z;SX-|efab)btTW_BYm?=-ZmBm+H2-!nWGR2%G-Qe19 zkD-neOVnL7=(Sew$XLj!HU$yWMKhU@mqpFQ>CYbm!oH~B=>|dX{C~I7_Vw`jo>>^x zE=Nt-GtW%Wu>?St+Yi0!s$5Z;`i54gQ`oSkO#U3`Nw!5I7+b ztub7Yo8Dm6oih`gLM2Vp)49TmZvNXVVxJ|RYOJ!*GQ{R)&gHMTrg%P}`^{P!Oliau zkhRU1Pkqq-+9!QckAIL>Cs8@G?=*dbw9tdlca1*X*;ad*esk~XD5mc~)AD}GG3+;x zr!-TSUl-c5Ej&wrxNiF@G;T-LQJZr%ANfjTdEDcda0-ekW`{q>+?|oLM>p#^s zAC#qJ1S}hoWQt^G=AK25xZYppW&z$g(NDw=g|eO$Ya{*!{dCfiKu9yFj8ibkLC)5hu+`o0y`1XL;8k-0$1WEWm)dx zg#hFW!8bc5LJ;_m1-UY&Z+wV#FE92rg0$i-{J{%yyKSI3|IGm>DQI zH6VAz&az0q4#CGew^U(3s>^T@sy-?l37xY)$f{u5+AUuiZ!Iz?9sGPEnaxmf#%|t0 zKP7ys$~h;(oUnEo0_Zip>X+8PUa5Yz&sG*OEW5tnR|5dN*Y2b1m7GdK8kgO+O5Y*X z-O;e5#N3Wu6&65bopPO+eZY5$DYwvfXB80tcKTcE3^{^B>ug28vZBWASBJAnTqcs5 z1~=czBI;K1ZC9)quM-R8d$A*yQdxEb=@FXt%PQys(~v`ZGetAs#g}s}ljV1c@d%1Y zy~v)Rs<)~5UcygMLG5`^Qj08;uu+9{jLxk<2RT_nk;EbasmNHm)50qsyq?0ce$gW- zR}clL19LVhr^`<&(^iRLDfApyLPp2pduAIlZ$={wbw4E)$|sUyO6((b}4Opo4`; zorl#*zkTOd3cf|r)Kg6THz9Nuxp5d*v3X7%IQv z`+J!^S3n2i?`rLC>x_&oS}s3Rq-5XAygX(k7Fg6WNA@Bu8N3<-A@-jCls8>6yrjW` zksUlq-V!r-g;VdlCKdQWo~h{FVqvbkTqR$X?AnD)NceAjtdW8U8Zc99KJkn0|5V5B--y}T=9N(omBjgJErSm-1D zlJpY8(@J#xjB`f_gSL(?Q5z_9V!vW_TuBsOTAQJf64MwNHoUbc2zrUt|!JYf&rtcK$$ zIr%NlEmEX@nL%jJR}C)+t`>}|Oqh9<OQ5I3 zf%>rphl6e|KP5KOn@Sdc(DvfVitehC*~qLMVRfDF?7l3Ou?=5(7sdO(u37 zE#&s9ki1BZ5wL0f-Z-+m5KmQbq^c{JAxj{Sr{gR98K0g;$eXPh^eiMehyD%*-N6m% z!Fn*Ve}nW(t~*uzpw8Yxq0()_6U(I0wOjrRO)*&-k4P*|R=H@Np3f}MBuKtonz45d*e{?W6N@OT-^HKPpz_!$WFx|*iu~l?fEFrTX;6h6Gche(9g985j-?%scU6ybJ7;L|6F?=H~YU(}tLL^_?CX z`!)K0h~3@~D-yI(Z|~1)CO(>yTS|@5EU~u;XxRCBQ2jwBlD>X50cWt zm%{H38Kq6dHPcT{o5>qSU+{HelX0?XJtsLI`%`fz9RWOCyBhjz@xfDf2D9dV_O%&S z1y~4~KTXv0fuwBHox#U;ru^x*Usv(nz7^Z-l!B{bp<>xlYNk6nw1NZ9aW`6@fK5&c zlD`hQSNDr#Ha`A%hZ50&C44@75pv38KqFmR#z(ohr?r2DIX8ruO6@Hy?f%&su1?%1 z&3GgGdP=q3k>&o_&A zqapn4qGh2&uG-rjvTIFi5}J9I=*?+;S+~&L;De+0cvn#yc;TV$-Qv=?mTKx!{OTcD zNOAuALOXX1hk8H?0|$45c)r_>PoWo`c#@3JlFJG6c%W=a|W9Y}8{8`)!@ZR!bn>x6Nng@%XL7ixJ~wYG_}KEAy?M-`x=}}9 zNRuISiq0J%{pnQrE~P6g%4?-d%BZ_-pcMP_cshGHG|%DD($+aeb-&(PO%^@=g0cq; z2T1E%UAk;6tDcFE9Y1Kg)eae=8fhxaJ36#)ukSbFOaYNicO;h{(Oy8+tB+j$8;Vm# zqsVUAl~0OlT?`!UeSMMiNr(Fw#by0!LS6YnHehvIHF-MNRsTkVQiV7pubxw!`K<~QyppKPy+7maJhBVzCtB;d|ameNo&2)`CA&a64d)U z39Why?-U}Jlg=LZWbZd!%T0v%iVxX`l|0X3lBA@HQ9FNFjY3Y>;2U2#f4s-#x9;gR zsvSxntz&k}LWHuQvQ0^3xzOFRu}s`!GKN~b;Y47 z&#to?SUGcNbMNmsyeceIIaw`8ETBS`633)XRfiW0w5n6S5;YY1xiszeFz7RPqx0wy5_Fo*P7YC}g#O95PC3bH61 z;AgQG?by$SY{_H~R*M*sek|hMpqb`f>836-_~uQJq}8{M4WmKqC4IsEjp0L6au6Fn zRAg&7HS|`%9JxsgMf5HY&(v!7MCIbWCC;*ZDRia^WVcYpk&E6kl<6C)ioIJ3-|Xgx z%}v(~-Yg_|sRGJ$E;@LL6cdiXs~~VU`L#?+oa?}~&Jzu(+fXjL8n?p$0|ndXh~35* zHAjHvYVi9bx#)tXuPt93SpPv7-ZF>&K4a!r$QgFeC#w#2a;bW%!uyBrp^bWOh^6JW z?w?Lb1>%QFO+j1t6}1i%@;C|eZ_SQlP_n31;U zJ~wND=tKr@nOrU37@ijYd5FAv&b{Ser?lOnvMo9umSY-3^G0(}a=@=@_qs*}?b%h+wOzzzS%ADwWyTlvn zgU@k?**Dzx$}U#)-1>O=amgy}2JcqP$ct6vspHOdx4T}A>)+fsF$ViIDtT-u$!|0O zX)ezkTA(Ttq%G$Y~1bmOizzCoQU+9}~_YSgOrny|`m@54r3aB8dQ z&Z;y8QwsE=*O^7zzjGc=F**2t9n+&TFb}XbvQ5(4GAYgeK)Hp z(Rlx56j(w19r9AZ@4fEUs9g zJ-G`^G8l9IF-cQ>e|(Cz%~lqSD2!WUw;RfOG!Ln<2;ND`m|p#`UvtZD=R0p8ndpax zaM&{KPUkAtZTkg5d&s1c^DeX!W<8UT5cW6 zgrY@NYTfMnxQP2o{zfC`>;p$SLI6G*QbCFk3Bl-XTx|`EEl$GX?XqV*5eG1mj&I>B zV#3lNU#EaRVN#2Loga=b@cMucP1)>l=xN$WVg8!*23d!dLtMSatI#;9&=+7f9OxJV zbYd7i;(zGrTcz-t;)BC=EX^Sk(eL9JWok|6+QB> zWw&t>6ibSpZu2`>9dXx#A))4kDU}(L8lVy*!_#KDU;Y*e`;sO*^r3C2e}k9YdH^_X ziNU*526s>{l~3uY-$Hxy$2fwrf+AFOOCb4zCV&_mz5mIKQbUql?)ofu=$YG}Dy9$< zFPmyBjNGs^Yk-^ue>m9UDbhBr>xX|C$ErGnb9IZ z*u?F+wX%ULqlwE-VII48=FY3}ZYfM1qi)bkap<0Cz(E8?<06S*s}vQnkVXAvlQAf% zt$|X?S+%^gw3c7d$>#h@Hf`+X*0}@ryuQ}{?2sH631#eC$%d@2tci_o6$YJVax~rOP9qgdshePAJGS)I_QJi47O_B9>yq8 zTeBONXZ|M-M_OBTZYe@@RfVW<1;?;6?T;+<@WJ2pmDb4v!re~lx$k-WaJ4rW%;r%J zNA5lE^DaM%o7`KfcSg%r8GQ#*0Nc=sE|DV5wzpmFjV9vp*4!P4UCK1F)-?@ULeN5o6mCJ6 z3CddDag-+4ZgiK2s6_D%uW?t2L!Y1UbI-Yg*R_ZAjzbwyt^MXfx`V&RH^&Vt73e{x(Ig^gI#Bu8qdKT}BD_Dg|qEM3~2-mM2ho5~P`Ank%>4uQ<9Z+K%r zcXM}!5GszFc4QNpx>(zSI`=&@bUGm6m09PTB3#MN7OP({%IH!Y#GI?qeh3}hC1KHs zQa5dLoC0kGsQ_^i4l{fR-Px{&rxg~?2+eV+Q)772s3tM8nX4+=3QooxQ;U9oFtWHZ z^|#s@AJ=L3#HbBHJpmK6*qtI7IEEo6{FMp-C}Ucy&tp|39gz`r1P&W>zO0tYkL`bf zqyMWt&=0XvHDk~K9=I{35eRseNM4)4b7X`TDzIU)buiazg1Aba*| zy98OvuP|N16n-q_fKs&U=T4XgkjIfgkk(76ZUk@<;E6sGS#d`q3v#3*-Kj1C2rCu^ z;Ni!27AUEY%kfkIhpr|NFd#_XTl50Jga8vQ`mW%)JBxU0>C{KYkIIY1fm63Ft4md0 zGX7SLOK0z2Pw_RYUS8jreLyR~gMB&2(ivQ(lO#*%3^R>wli`7sxTm=@tN=jV7~S7#Dgy-10Zm)gKx@ScA~QUp%EeNH=Q>dGoHN)?s}6a z;;EP#cTLXRXPxx>3uE>YS-71zl&xlOwB5m-1{shv@*Nv{2)~xD+!a_U;KFvKsdOf! zanoOY6(~enpe|#FU>0zdRw5W|0i@}NzXT!WbJ8m9dU3Uf3Za>h>u#a7OAY;sI4ELX z2quVtOvsXA8dVobUR4CrsF>Dtt@&hd3-6DQk{>-U0tj z8LOfHN6KLCW3fM2Mg0*}-~#&@jO!mgHH9pG4rGg1qz5xh%cSg#<7{*00dqEISHpVr zH!WAl_2$6LFRj0&*YaB4Zd@zr0v0SQpt6>rmy}0;TO@GVRU{i2(2fXy8k8+GF&sHO z*lqEeBVi(~xD@D1Bu`(^(Ko|*jUrbTx0K$I)MzN6Vhx#P7k51;_rAp=$rJ+?!F=6X z--m~g^MQQwy_y5u_~&zLzrCkdGtZ5dk96T`b7(64s?7cHo)9UFRN^4mZ*}I;bk!6n zMqt^}uEucmq!f@am6Vdvo7&2g}!l zMVD<#vyw|6UJy-mid93k7CEPsRNxV=4?F?qIm@MX7BcT71yp4vfrCNk7ZMLrI!{jj zHx5*B+Crg6N&I+Dg{6s>17CkiyQP~)oYY+)u&BBYfS|zQ{~@lJVay2@S!dd}9b))g z=_r!IG^<=~-Nj(#i8(E3vBssE$5Svjl7#QSvg&wbbA9nGE;Lga>1qaiE(BEpi)j=u zk)qJjG+XqJ`7aRt#@g8d5tYc-Gi94`J8Cw#bCwq;bXF~KqHE(;sZ2^%3nk7T z0lDkzslZna&r}=)NTKC_NWo$p&zKW3@bNCoQdShgKqD>CcTQ{%a2OK{b4_g%t^n#E zX%8)rXaG`6!6UWk=|Csx4Jdy)Xrp=-Z#st#M&%9_B5G5F(0>v|u7KHR9I2)_yuBoE z+R5^Tk07g*wYDy?L5>4OBv4DC>zqmYZv)J9BazkrQBLjm3A}#=-~UYy>TMk>Yk%m$ z=B7g9mTmxmg)!s=1A>}o3e@?@2V*g)L4aDOXAQJ?kb_*9=1EPwINadx*diYeGb39h zkf+3h+e8A%HI+r!u3fSB&(V}%9A>0stygE_PZ+KaCqZ>5>X4|&{a}}RKT(~oiZ~A0 zSE%!8rxR+d)A(!e&{pnDm{@ei)XTRR_vjgDBvZKR&^F8qOQms4ET)qtqeBHXJUxsO z#%{@5PFTx^wc*qu>n)Q@aqKb=V8I(x&@rRy)*V4ImW2&#hv)C#D_%-P#5w&69&}Xyq*oFT6T$V@Htzw;YzyjQ zx#iNZngi5&%6l8(T=eN*mk2r3w&xLysvi`c0c>9ZZX)B0BaaGp22lAVC%>AAHW2TY=J~BK4 z*fKTFUs|wJxr)52cq1@6>CtGb`ocN}A$uk6s+cJ(bUvUtY3<@J$&Jo8Ep(a$ZU3uw zLT-axBViE-0kbsPPXUstk{422U-t@F7?e3HY;yKLKGokr#yXk4d0TvF%wgxpZWl0; z5t={kq#$yxlI$tb%LE`IP-me`Av0HkR9%m}s__+vK|np-YDP}wqRBN{CN1O{^9pEb zFWFDM`aT=cdsU@oR?2j3Hz`jZV2DLqbNk1-nZZZ?RQA(~!=&ihk<sgk4Rd$3{M z!n*}6%3KV<5`frZ<)7H12fH-`Af(&77_Jp0R*?V;_HP(Rs;B_z8sZl(1Z~~#?PB=! zx7^H|?=jYX779{ud{8+f%ikt&zPxu`70bYai6RejcRkBK0g`M>-2)T*Y85C!p_eG6 z8W5V4tJR{%5sV=~sK3DOebiue-*LR^HTSCW{su?8q7Ik!!0{{QZXEqY#h-q|jk~9Y zld=kG4j0H3i8AXrw8JA1HN?z1}V!7LHf*nY=#y4xaN z)_C01TSI2^D--W3ql8g!rQGDV=+oUtb!ls94H#I^6I2bZjmx@vt|J3xx-;sv{n(l& zUm$CHe#kDbJm02c9XAVX;dit`=DeaX{VU=q59+@By_xkwD@;t>XSqNjolpfTjdTn}Gbx zXNkg|TA*CA`yh-dg*fy)D&W&v4X7EklBu<&U6%AQcu(```k1kgEvMPpdmOG>vYR$j zUVR0wY6HCr#8=(PxJ%$KSk?+8m=bB^BhM*eSG5nyGs)GF>mg%HxjGBmOWl<0<0k+g ze=P?E#{n;Fl0#5Z71ZYCJ!2*ZF2FN3x +7y(Yp@+9D{XS>4@;-Lr7dZ2*2SBX)< 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 literal 0 HcmV?d00001 diff --git a/uk/02-memory/memory-saved.png b/uk/02-memory/memory-saved.png new file mode 100644 index 0000000000000000000000000000000000000000..1c16eb743c8b090d2ad8e44c3720f21f4bc4f0eb GIT binary patch literal 303476 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

*}h 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

C<+sXT!>R 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±jj9 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 me~Z#zmFM4l_ int: + """ + Calculate cyclomatic complexity using McCabe's method. + Count decision points: if, elif, else, for, while, except, and, or + """ + complexity = 1 # Base complexity + + # Count decision points + decision_patterns = [ + r"\bif\b", + r"\belif\b", + r"\bfor\b", + r"\bwhile\b", + r"\bexcept\b", + r"\band\b(?!$)", + r"\bor\b(?!$)", + ] + + for pattern in decision_patterns: + matches = re.findall(pattern, self.code) + complexity += len(matches) + + return complexity + + def calculate_cognitive_complexity(self) -> int: + """ + Calculate cognitive complexity - how hard is it to understand? + Based on nesting depth and control flow. + """ + cognitive = 0 + nesting_depth = 0 + + for line in self.lines: + # Track nesting depth + if re.search(r"^\s*(if|for|while|def|class|try)\b", line): + nesting_depth += 1 + cognitive += nesting_depth + elif re.search(r"^\s*(elif|else|except|finally)\b", line): + cognitive += nesting_depth + + # Reduce nesting when unindenting + if line and not line[0].isspace(): + nesting_depth = 0 + + return cognitive + + def calculate_maintainability_index(self) -> float: + """ + Maintainability Index ranges from 0-100. + > 85: Excellent + > 65: Good + > 50: Fair + < 50: Poor + """ + lines = len(self.lines) + cyclomatic = self.calculate_cyclomatic_complexity() + cognitive = self.calculate_cognitive_complexity() + + # Simplified MI calculation + mi = ( + 171 + - 5.2 * (cyclomatic / lines) + - 0.23 * (cognitive) + - 16.2 * (lines / 1000) + ) + + return max(0, min(100, mi)) + + def get_complexity_report(self) -> dict: + """Generate comprehensive complexity report.""" + return { + "cyclomatic_complexity": self.calculate_cyclomatic_complexity(), + "cognitive_complexity": self.calculate_cognitive_complexity(), + "maintainability_index": round(self.calculate_maintainability_index(), 2), + "lines_of_code": len(self.lines), + "avg_line_length": round( + sum(len(l) for l in self.lines) / len(self.lines), 2 + ) + if self.lines + else 0, + } + + +def compare_files(before_file: str, after_file: str) -> None: + """Compare complexity metrics between two code versions.""" + + with open(before_file) as f: + before_code = f.read() + + with open(after_file) as f: + after_code = f.read() + + before_analyzer = ComplexityAnalyzer(before_code) + after_analyzer = ComplexityAnalyzer(after_code) + + before_metrics = before_analyzer.get_complexity_report() + after_metrics = after_analyzer.get_complexity_report() + + print("=" * 60) + print("CODE COMPLEXITY COMPARISON") + print("=" * 60) + + print("\nBEFORE:") + print(f" Cyclomatic Complexity: {before_metrics['cyclomatic_complexity']}") + print(f" Cognitive Complexity: {before_metrics['cognitive_complexity']}") + print(f" Maintainability Index: {before_metrics['maintainability_index']}") + print(f" Lines of Code: {before_metrics['lines_of_code']}") + print(f" Avg Line Length: {before_metrics['avg_line_length']}") + + print("\nAFTER:") + print(f" Cyclomatic Complexity: {after_metrics['cyclomatic_complexity']}") + print(f" Cognitive Complexity: {after_metrics['cognitive_complexity']}") + print(f" Maintainability Index: {after_metrics['maintainability_index']}") + print(f" Lines of Code: {after_metrics['lines_of_code']}") + print(f" Avg Line Length: {after_metrics['avg_line_length']}") + + print("\nCHANGES:") + cyclomatic_change = ( + after_metrics["cyclomatic_complexity"] - before_metrics["cyclomatic_complexity"] + ) + cognitive_change = ( + after_metrics["cognitive_complexity"] - before_metrics["cognitive_complexity"] + ) + mi_change = ( + after_metrics["maintainability_index"] - before_metrics["maintainability_index"] + ) + loc_change = after_metrics["lines_of_code"] - before_metrics["lines_of_code"] + + print(f" Cyclomatic Complexity: {cyclomatic_change:+d}") + print(f" Cognitive Complexity: {cognitive_change:+d}") + print(f" Maintainability Index: {mi_change:+.2f}") + print(f" Lines of Code: {loc_change:+d}") + + print("\nASSESSMENT:") + if mi_change > 0: + print(" ✅ Code is MORE maintainable") + elif mi_change < 0: + print(" ⚠️ Code is LESS maintainable") + else: + print(" ➡️ Maintainability unchanged") + + if cyclomatic_change < 0: + print(" ✅ Complexity DECREASED") + elif cyclomatic_change > 0: + print(" ⚠️ Complexity INCREASED") + else: + print(" ➡️ Complexity unchanged") + + print("=" * 60) + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: python compare-complexity.py ") + sys.exit(1) + + compare_files(sys.argv[1], sys.argv[2]) diff --git a/uk/03-skills/code-review/templates/finding-template.md b/uk/03-skills/code-review/templates/finding-template.md new file mode 100644 index 0000000..d1b99ea --- /dev/null +++ b/uk/03-skills/code-review/templates/finding-template.md @@ -0,0 +1,112 @@ +# Шаблон знахідки код-рев'ю + +Використовуйте цей шаблон для документування кожної знайденої проблеми під час код-рев'ю. + +--- + +## Проблема: [НАЗВА] + +### Серйозність +- [ ] Критична (блокує деплой) +- [ ] Висока (потрібно виправити перед мерджем) +- [ ] Середня (потрібно виправити незабаром) +- [ ] Низька (бажано виправити) + +### Категорія +- [ ] Безпека +- [ ] Продуктивність +- [ ] Якість коду +- [ ] Підтримуваність +- [ ] Тестування +- [ ] Патерн проєктування +- [ ] Документація + +### Розташування +**Файл:** `src/components/UserCard.tsx` + +**Рядки:** 45-52 + +**Функція/Метод:** `renderUserDetails()` + +### Опис проблеми + +**Що:** Опишіть суть проблеми. + +**Чому це важливо:** Поясніть вплив та чому це потрібно виправити. + +**Поточна поведінка:** Покажіть проблемний код або поведінку. + +**Очікувана поведінка:** Опишіть, що повинно відбуватися замість цього. + +### Приклад коду + +#### Поточний (проблемний) + +```typescript +// Shows the N+1 query problem +const users = fetchUsers(); +users.forEach(user => { + const posts = fetchUserPosts(user.id); // Query per user! + renderUserPosts(posts); +}); +``` + +#### Запропоноване виправлення + +```typescript +// Optimized with JOIN query +const usersWithPosts = fetchUsersWithPosts(); +usersWithPosts.forEach(({ user, posts }) => { + renderUserPosts(posts); +}); +``` + +### Аналіз впливу + +| Аспект | Вплив | Серйозність | +|--------|-------|-------------| +| Продуктивність | 100+ запитів для 20 користувачів | Висока | +| Досвід користувача | Повільне завантаження сторінки | Висока | +| Масштабованість | Ламається при масштабуванні | Критична | +| Підтримуваність | Складно дебажити | Середня | + +### Пов'язані проблеми + +- Аналогічна проблема в `AdminUserList.tsx` рядок 120 +- Пов'язаний PR: #456 +- Пов'язана issue: #789 + +### Додаткові ресурси + +- [N+1 Query Problem](https://en.wikipedia.org/wiki/N%2B1_problem) +- [Database Join Documentation](https://docs.example.com/joins) + +### Нотатки рецензента + +- Це поширений патерн у цій кодовій базі +- Варто додати це до гайду зі стилю коду +- Можливо, варто створити допоміжну функцію + +### Відповідь автора (для зворотного зв'язку) + +*Заповнюється автором коду:* + +- [ ] Виправлення реалізовано в коміті: `abc123` +- [ ] Статус виправлення: Завершено / В процесі / Потребує обговорення +- [ ] Питання або зауваження: (опишіть) + +--- + +## Статистика знахідок (для рецензента) + +При рев'ю кількох знахідок, відстежуйте: + +- **Всього знайдено проблем:** X +- **Критичних:** X +- **Високих:** X +- **Середніх:** X +- **Низьких:** X + +**Рекомендація:** ✅ Затвердити / ⚠️ Запросити зміни / 🔄 Потребує обговорення + +**Загальна якість коду:** 1-5 зірок diff --git a/uk/03-skills/code-review/templates/review-checklist.md b/uk/03-skills/code-review/templates/review-checklist.md new file mode 100644 index 0000000..774cfc0 --- /dev/null +++ b/uk/03-skills/code-review/templates/review-checklist.md @@ -0,0 +1,47 @@ +# Чеклист код-рев'ю + +## Чеклист безпеки +- [ ] Немає захардкоджених облікових даних або секретів +- [ ] Валідація введення для всіх даних від користувача +- [ ] Захист від SQL-ін'єкцій (параметризовані запити) +- [ ] CSRF-захист для операцій зі зміною стану +- [ ] Захист від XSS з правильним екрануванням +- [ ] Перевірка автентифікації на захищених ендпоінтах +- [ ] Перевірка авторизації для ресурсів +- [ ] Безпечне хешування паролів (bcrypt, argon2) +- [ ] Немає чутливих даних у логах +- [ ] HTTPS обов'язковий + +## Чеклист продуктивності +- [ ] Немає N+1 запитів +- [ ] Правильне використання індексів +- [ ] Кешування реалізовано де доцільно +- [ ] Немає блокуючих операцій в основному потоці +- [ ] Async/await використовується коректно +- [ ] Великі набори даних пагіновані +- [ ] Пул з'єднань до бази даних +- [ ] Регулярні вирази оптимізовані +- [ ] Немає зайвого створення об'єктів +- [ ] Витоки пам'яті запобігаються + +## Чеклист якості +- [ ] Функції < 50 рядків +- [ ] Зрозумілі назви змінних +- [ ] Немає дублювання коду +- [ ] Правильна обробка помилок +- [ ] Коментарі пояснюють ЧОМУ, а не ЩО +- [ ] Немає console.log у продакшені +- [ ] Перевірка типів (TypeScript/JSDoc) +- [ ] Принципи SOLID дотримані +- [ ] Патерни проєктування застосовані коректно +- [ ] Самодокументований код + +## Чеклист тестування +- [ ] Юніт-тести написані +- [ ] Граничні випадки покриті +- [ ] Сценарії помилок протестовані +- [ ] Інтеграційні тести є +- [ ] Покриття > 80% +- [ ] Немає нестабільних тестів +- [ ] Зовнішні залежності замоковані +- [ ] Зрозумілі назви тестів diff --git a/uk/03-skills/doc-generator/generate-docs.py b/uk/03-skills/doc-generator/generate-docs.py new file mode 100644 index 0000000..3a0f588 --- /dev/null +++ b/uk/03-skills/doc-generator/generate-docs.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +import ast + + +class APIDocExtractor(ast.NodeVisitor): + """Extract API documentation from Python source code.""" + + def __init__(self): + self.endpoints = [] + + def visit_FunctionDef(self, node): + """Extract function documentation.""" + if node.name.startswith("get_") or node.name.startswith("post_"): + doc = ast.get_docstring(node) + endpoint = { + "name": node.name, + "docstring": doc, + "params": [arg.arg for arg in node.args.args], + "returns": self._extract_return_type(node), + } + self.endpoints.append(endpoint) + self.generic_visit(node) + + def _extract_return_type(self, node): + """Extract return type from function annotation.""" + if node.returns: + return ast.unparse(node.returns) + return "Any" + + +def generate_markdown_docs(endpoints: list[dict]) -> str: + """Generate markdown documentation from endpoints.""" + docs = "# API Documentation\n\n" + + for endpoint in endpoints: + docs += f"## {endpoint['name']}\n\n" + docs += f"{endpoint['docstring']}\n\n" + docs += f"**Parameters**: {', '.join(endpoint['params'])}\n\n" + docs += f"**Returns**: {endpoint['returns']}\n\n" + docs += "---\n\n" + + return docs + + +if __name__ == "__main__": + import sys + + with open(sys.argv[1]) as f: + tree = ast.parse(f.read()) + + extractor = APIDocExtractor() + extractor.visit(tree) + + markdown = generate_markdown_docs(extractor.endpoints) + print(markdown) diff --git a/uk/03-skills/refactor/scripts/analyze-complexity.py b/uk/03-skills/refactor/scripts/analyze-complexity.py new file mode 100644 index 0000000..b8ca92c --- /dev/null +++ b/uk/03-skills/refactor/scripts/analyze-complexity.py @@ -0,0 +1,545 @@ +#!/usr/bin/env python3 +""" +Code Complexity Analyzer + +Analyzes code complexity metrics for Python, JavaScript, and TypeScript files. +Helps measure the impact of refactoring by comparing before/after metrics. + +Usage: + python analyze-complexity.py + python analyze-complexity.py # Compare mode + python analyze-complexity.py --dir # Analyze directory + +Metrics: + - Cyclomatic Complexity: Decision points in code + - Cognitive Complexity: How hard is it to understand + - Maintainability Index: Overall maintainability score (0-100) + - Lines of Code: Total lines + - Function Count: Number of functions/methods + - Average Function Length: Lines per function +""" + +import argparse +import os +import re +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, List, Optional + + +@dataclass +class FunctionMetrics: + """Metrics for a single function.""" + name: str + start_line: int + end_line: int + lines: int + cyclomatic_complexity: int + cognitive_complexity: int + parameter_count: int + + +@dataclass +class FileMetrics: + """Metrics for a file.""" + filename: str + lines_of_code: int + blank_lines: int + comment_lines: int + function_count: int + class_count: int + cyclomatic_complexity: int + cognitive_complexity: int + maintainability_index: float + avg_function_length: float + max_function_length: int + functions: List[FunctionMetrics] + + +class ComplexityAnalyzer: + """Analyze code complexity for multiple languages.""" + + # Patterns for different languages + PATTERNS = { + 'python': { + 'function': r'^\s*def\s+(\w+)\s*\(', + 'class': r'^\s*class\s+(\w+)', + 'decision': [r'\bif\b', r'\belif\b', r'\bfor\b', r'\bwhile\b', + r'\bexcept\b', r'\band\b(?!$)', r'\bor\b(?!$)', + r'\bcase\b', r'\btry\b'], + 'comment': r'^\s*#', + 'multiline_comment_start': r'^\s*["\'][\"\'][\"\']', + 'multiline_comment_end': r'["\'][\"\'][\"\']', + }, + 'javascript': { + 'function': r'(?:function\s+(\w+)|(\w+)\s*[=:]\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))', + 'class': r'class\s+(\w+)', + 'decision': [r'\bif\b', r'\belse\s+if\b', r'\bfor\b', r'\bwhile\b', + r'\bcatch\b', r'\b\?\b', r'\b&&\b', r'\b\|\|\b', + r'\bcase\b', r'\btry\b'], + 'comment': r'^\s*//', + 'multiline_comment_start': r'/\*', + 'multiline_comment_end': r'\*/', + }, + 'typescript': { + 'function': r'(?:function\s+(\w+)|(\w+)\s*[=:]\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))', + 'class': r'class\s+(\w+)', + 'decision': [r'\bif\b', r'\belse\s+if\b', r'\bfor\b', r'\bwhile\b', + r'\bcatch\b', r'\b\?\b', r'\b&&\b', r'\b\|\|\b', + r'\bcase\b', r'\btry\b'], + 'comment': r'^\s*//', + 'multiline_comment_start': r'/\*', + 'multiline_comment_end': r'\*/', + } + } + + def __init__(self, filepath: str): + self.filepath = filepath + self.filename = os.path.basename(filepath) + self.language = self._detect_language() + self.patterns = self.PATTERNS.get(self.language, self.PATTERNS['python']) + + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + self.code = f.read() + self.lines = self.code.split('\n') + + def _detect_language(self) -> str: + """Detect programming language from file extension.""" + ext = os.path.splitext(self.filepath)[1].lower() + ext_map = { + '.py': 'python', + '.js': 'javascript', + '.jsx': 'javascript', + '.ts': 'typescript', + '.tsx': 'typescript', + } + return ext_map.get(ext, 'python') + + def calculate_cyclomatic_complexity(self, code: Optional[str] = None) -> int: + """ + Calculate cyclomatic complexity using McCabe's method. + CC = E - N + 2P where E=edges, N=nodes, P=connected components + Simplified: Count decision points + 1 + """ + if code is None: + code = self.code + + complexity = 1 # Base complexity + + for pattern in self.patterns['decision']: + matches = re.findall(pattern, code) + complexity += len(matches) + + return complexity + + def calculate_cognitive_complexity(self, code: Optional[str] = None) -> int: + """ + Calculate cognitive complexity. + Measures how hard it is to understand the code. + Accounts for nesting depth and control flow breaks. + """ + if code is None: + code = self.code + + lines = code.split('\n') + cognitive = 0 + nesting_depth = 0 + in_function = False + + for line in lines: + stripped = line.strip() + + # Track function boundaries + if re.search(self.patterns['function'], line): + in_function = True + nesting_depth = 0 + + # Increment for control flow structures + if re.search(r'\b(if|for|while|switch)\b', stripped): + nesting_depth += 1 + cognitive += nesting_depth # Nested structures cost more + + elif re.search(r'\b(elif|else if|else|catch|finally)\b', stripped): + cognitive += nesting_depth # Same level as parent + + # Track nesting through braces/indentation + if self.language in ['javascript', 'typescript']: + nesting_depth += stripped.count('{') - stripped.count('}') + nesting_depth = max(0, nesting_depth) + + # Bonus for breaks in linear flow + if re.search(r'\b(break|continue|return|throw)\b', stripped): + if nesting_depth > 1: + cognitive += 1 + + # Bonus for recursion + # (simplified: just look for function calling itself) + + return cognitive + + def calculate_maintainability_index(self) -> float: + """ + Calculate Maintainability Index (0-100). + Based on Halstead Volume, Cyclomatic Complexity, and Lines of Code. + + MI = max(0, (171 - 5.2*ln(V) - 0.23*CC - 16.2*ln(LOC)) * 100/171) + + Interpretation: + - 85-100: Highly maintainable + - 65-84: Moderately maintainable + - 50-64: Difficult to maintain + - 0-49: Very difficult to maintain + """ + import math + + loc = len([l for l in self.lines if l.strip()]) + cc = self.calculate_cyclomatic_complexity() + + # Simplified Halstead Volume approximation + # Count unique operators and operands + operators = len(re.findall(r'[+\-*/%=<>!&|^~]', self.code)) + operands = len(re.findall(r'\b\w+\b', self.code)) + volume = (operators + operands) * math.log2(max(1, operators + operands)) + + # Calculate MI + mi = 171 - 5.2 * math.log(max(1, volume)) - 0.23 * cc - 16.2 * math.log(max(1, loc)) + mi = max(0, min(100, mi * 100 / 171)) + + return round(mi, 2) + + def count_lines(self) -> Dict[str, int]: + """Count different types of lines.""" + total = len(self.lines) + blank = 0 + comment = 0 + in_multiline_comment = False + + for line in self.lines: + stripped = line.strip() + + # Check for multiline comments + if re.search(self.patterns['multiline_comment_start'], stripped): + in_multiline_comment = True + if re.search(self.patterns['multiline_comment_end'], stripped): + in_multiline_comment = False + comment += 1 + continue + + if in_multiline_comment: + comment += 1 + elif not stripped: + blank += 1 + elif re.match(self.patterns['comment'], stripped): + comment += 1 + + return { + 'total': total, + 'blank': blank, + 'comment': comment, + 'code': total - blank - comment + } + + def find_functions(self) -> List[FunctionMetrics]: + """Find all functions and calculate their individual metrics.""" + functions = [] + current_function = None + function_start = 0 + brace_depth = 0 + + for i, line in enumerate(self.lines): + # Check for function definition + match = re.search(self.patterns['function'], line) + if match: + # Save previous function if exists + if current_function: + func_code = '\n'.join(self.lines[function_start:i]) + functions.append(self._create_function_metrics( + current_function, function_start, i - 1, func_code + )) + + current_function = match.group(1) or match.group(2) if match.lastindex and match.lastindex > 1 else match.group(1) + function_start = i + brace_depth = 0 + + # Track braces for JS/TS + if self.language in ['javascript', 'typescript']: + brace_depth += line.count('{') - line.count('}') + + # Don't forget the last function + if current_function: + func_code = '\n'.join(self.lines[function_start:]) + functions.append(self._create_function_metrics( + current_function, function_start, len(self.lines) - 1, func_code + )) + + return functions + + def _create_function_metrics(self, name: str, start: int, end: int, code: str) -> FunctionMetrics: + """Create metrics for a single function.""" + lines = end - start + 1 + + # Count parameters (simplified) + param_match = re.search(r'\(([^)]*)\)', code.split('\n')[0]) + param_count = 0 + if param_match and param_match.group(1).strip(): + param_count = len([p for p in param_match.group(1).split(',') if p.strip()]) + + return FunctionMetrics( + name=name, + start_line=start + 1, + end_line=end + 1, + lines=lines, + cyclomatic_complexity=self.calculate_cyclomatic_complexity(code), + cognitive_complexity=self.calculate_cognitive_complexity(code), + parameter_count=param_count + ) + + def analyze(self) -> FileMetrics: + """Perform complete analysis of the file.""" + line_counts = self.count_lines() + functions = self.find_functions() + + # Count classes + class_count = len(re.findall(self.patterns['class'], self.code)) + + # Calculate averages + func_lengths = [f.lines for f in functions] if functions else [0] + avg_func_length = sum(func_lengths) / len(func_lengths) + max_func_length = max(func_lengths) + + return FileMetrics( + filename=self.filename, + lines_of_code=line_counts['code'], + blank_lines=line_counts['blank'], + comment_lines=line_counts['comment'], + function_count=len(functions), + class_count=class_count, + cyclomatic_complexity=self.calculate_cyclomatic_complexity(), + cognitive_complexity=self.calculate_cognitive_complexity(), + maintainability_index=self.calculate_maintainability_index(), + avg_function_length=round(avg_func_length, 1), + max_function_length=max_func_length, + functions=functions + ) + + +def print_metrics(metrics: FileMetrics, verbose: bool = False) -> None: + """Print metrics in a readable format.""" + print("=" * 60) + print(f"CODE COMPLEXITY ANALYSIS: {metrics.filename}") + print("=" * 60) + + print("\n📊 OVERVIEW") + print("-" * 40) + print(f" Lines of Code: {metrics.lines_of_code}") + print(f" Blank Lines: {metrics.blank_lines}") + print(f" Comment Lines: {metrics.comment_lines}") + print(f" Functions/Methods: {metrics.function_count}") + print(f" Classes: {metrics.class_count}") + + print("\n📈 COMPLEXITY METRICS") + print("-" * 40) + print(f" Cyclomatic Complexity: {metrics.cyclomatic_complexity}") + print(f" Cognitive Complexity: {metrics.cognitive_complexity}") + print(f" Maintainability Index: {metrics.maintainability_index}") + + # Interpret maintainability + mi = metrics.maintainability_index + if mi >= 85: + mi_label = "Highly maintainable ✅" + elif mi >= 65: + mi_label = "Moderately maintainable 🔶" + elif mi >= 50: + mi_label = "Difficult to maintain ⚠️" + else: + mi_label = "Very difficult to maintain ❌" + print(f" → {mi_label}") + + print("\n📐 FUNCTION METRICS") + print("-" * 40) + print(f" Avg Function Length: {metrics.avg_function_length} lines") + print(f" Max Function Length: {metrics.max_function_length} lines") + + if verbose and metrics.functions: + print("\n📋 FUNCTION DETAILS") + print("-" * 40) + for f in sorted(metrics.functions, key=lambda x: x.cyclomatic_complexity, reverse=True): + flag = " ⚠️" if f.cyclomatic_complexity > 10 or f.lines > 50 else "" + print(f" {f.name}() [lines {f.start_line}-{f.end_line}]{flag}") + print(f" - Lines: {f.lines}, CC: {f.cyclomatic_complexity}, " + f"Cognitive: {f.cognitive_complexity}, Params: {f.parameter_count}") + + print("\n" + "=" * 60) + + +def print_comparison(before: FileMetrics, after: FileMetrics) -> None: + """Print comparison between two analyses.""" + print("=" * 70) + print("CODE COMPLEXITY COMPARISON") + print("=" * 70) + + print(f"\n{'Metric':<30} {'Before':<15} {'After':<15} {'Change':<10}") + print("-" * 70) + + def fmt_change(before_val, after_val, lower_is_better=True): + diff = after_val - before_val + if lower_is_better: + symbol = "✅" if diff < 0 else ("⚠️" if diff > 0 else "➖") + else: + symbol = "✅" if diff > 0 else ("⚠️" if diff < 0 else "➖") + return f"{diff:+.1f} {symbol}" if isinstance(diff, float) else f"{diff:+d} {symbol}" + + metrics = [ + ("Lines of Code", before.lines_of_code, after.lines_of_code, True), + ("Function Count", before.function_count, after.function_count, False), + ("Class Count", before.class_count, after.class_count, False), + ("Cyclomatic Complexity", before.cyclomatic_complexity, after.cyclomatic_complexity, True), + ("Cognitive Complexity", before.cognitive_complexity, after.cognitive_complexity, True), + ("Maintainability Index", before.maintainability_index, after.maintainability_index, False), + ("Avg Function Length", before.avg_function_length, after.avg_function_length, True), + ("Max Function Length", before.max_function_length, after.max_function_length, True), + ] + + for name, b_val, a_val, lower_better in metrics: + change = fmt_change(b_val, a_val, lower_better) + print(f"{name:<30} {b_val:<15} {a_val:<15} {change:<10}") + + print("\n" + "=" * 70) + + # Overall assessment + print("\n🎯 ASSESSMENT") + print("-" * 40) + + improvements = 0 + regressions = 0 + + if after.maintainability_index > before.maintainability_index: + print(" ✅ Maintainability improved") + improvements += 1 + elif after.maintainability_index < before.maintainability_index: + print(" ⚠️ Maintainability decreased") + regressions += 1 + + if after.cyclomatic_complexity < before.cyclomatic_complexity: + print(" ✅ Complexity reduced") + improvements += 1 + elif after.cyclomatic_complexity > before.cyclomatic_complexity: + print(" ⚠️ Complexity increased") + regressions += 1 + + if after.avg_function_length < before.avg_function_length: + print(" ✅ Functions are smaller on average") + improvements += 1 + elif after.avg_function_length > before.avg_function_length: + print(" ⚠️ Functions grew larger on average") + regressions += 1 + + print(f"\n Summary: {improvements} improvements, {regressions} regressions") + print("=" * 70) + + +def analyze_directory(directory: str, verbose: bool = False) -> None: + """Analyze all supported files in a directory.""" + supported_extensions = ['.py', '.js', '.jsx', '.ts', '.tsx'] + files = [] + + for root, _, filenames in os.walk(directory): + for filename in filenames: + if any(filename.endswith(ext) for ext in supported_extensions): + files.append(os.path.join(root, filename)) + + if not files: + print(f"No supported files found in {directory}") + return + + print(f"Analyzing {len(files)} files in {directory}...\n") + + total_loc = 0 + total_cc = 0 + total_functions = 0 + all_metrics = [] + + for filepath in sorted(files): + try: + analyzer = ComplexityAnalyzer(filepath) + metrics = analyzer.analyze() + all_metrics.append(metrics) + + total_loc += metrics.lines_of_code + total_cc += metrics.cyclomatic_complexity + total_functions += metrics.function_count + + if verbose: + print_metrics(metrics, verbose=True) + else: + flag = " ⚠️" if metrics.maintainability_index < 65 else "" + print(f" {metrics.filename}: LOC={metrics.lines_of_code}, " + f"CC={metrics.cyclomatic_complexity}, MI={metrics.maintainability_index}{flag}") + except Exception as e: + print(f" Error analyzing {filepath}: {e}") + + print("\n" + "=" * 60) + print("SUMMARY") + print("=" * 60) + print(f" Files analyzed: {len(all_metrics)}") + print(f" Total lines of code: {total_loc}") + print(f" Total complexity: {total_cc}") + print(f" Total functions: {total_functions}") + + if all_metrics: + avg_mi = sum(m.maintainability_index for m in all_metrics) / len(all_metrics) + print(f" Avg maintainability: {avg_mi:.1f}") + + +def main(): + parser = argparse.ArgumentParser( + description='Analyze code complexity metrics', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + %(prog)s myfile.py Analyze single file + %(prog)s before.py after.py Compare two versions + %(prog)s --dir src/ Analyze directory + %(prog)s -v myfile.py Verbose output with function details + """ + ) + parser.add_argument('files', nargs='*', help='File(s) to analyze') + parser.add_argument('--dir', '-d', help='Directory to analyze') + parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed function metrics') + parser.add_argument('--json', '-j', action='store_true', help='Output as JSON') + + args = parser.parse_args() + + if args.dir: + analyze_directory(args.dir, args.verbose) + elif len(args.files) == 1: + analyzer = ComplexityAnalyzer(args.files[0]) + metrics = analyzer.analyze() + + if args.json: + import json + print(json.dumps({ + 'filename': metrics.filename, + 'lines_of_code': metrics.lines_of_code, + 'cyclomatic_complexity': metrics.cyclomatic_complexity, + 'cognitive_complexity': metrics.cognitive_complexity, + 'maintainability_index': metrics.maintainability_index, + 'function_count': metrics.function_count, + 'avg_function_length': metrics.avg_function_length, + }, indent=2)) + else: + print_metrics(metrics, args.verbose) + elif len(args.files) == 2: + before_analyzer = ComplexityAnalyzer(args.files[0]) + after_analyzer = ComplexityAnalyzer(args.files[1]) + before_metrics = before_analyzer.analyze() + after_metrics = after_analyzer.analyze() + print_comparison(before_metrics, after_metrics) + else: + parser.print_help() + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/uk/03-skills/refactor/scripts/detect-smells.py b/uk/03-skills/refactor/scripts/detect-smells.py new file mode 100644 index 0000000..7ecd628 --- /dev/null +++ b/uk/03-skills/refactor/scripts/detect-smells.py @@ -0,0 +1,711 @@ +#!/usr/bin/env python3 +""" +Code Smell Detector + +Detects common code smells in Python, JavaScript, and TypeScript files. +Based on Martin Fowler's catalog of code smells. + +Usage: + python detect-smells.py + python detect-smells.py --dir + python detect-smells.py -v # Verbose with code snippets + +Detects: + - Long Method (>30 lines) + - Long Parameter List (>4 params) + - Duplicate Code (similar code blocks) + - Large Class (>300 lines, >10 methods) + - Dead Code (unused variables/functions) + - Complex Conditionals (deep nesting, long chains) + - Magic Numbers/Strings + - Feature Envy (methods using other class data heavily) + - Comments explaining what (not why) +""" + +import argparse +import os +import re +import sys +from dataclasses import dataclass, field +from enum import Enum +from typing import Dict, List, Optional, Set, Tuple +from collections import defaultdict + + +class SmellSeverity(Enum): + """Severity levels for code smells.""" + LOW = "Low" + MEDIUM = "Medium" + HIGH = "High" + CRITICAL = "Critical" + + +class SmellType(Enum): + """Types of code smells.""" + LONG_METHOD = "Long Method" + LONG_PARAMETER_LIST = "Long Parameter List" + DUPLICATE_CODE = "Duplicate Code" + LARGE_CLASS = "Large Class" + DEAD_CODE = "Dead Code" + COMPLEX_CONDITIONAL = "Complex Conditional" + MAGIC_NUMBER = "Magic Number/String" + FEATURE_ENVY = "Feature Envy" + EXCESSIVE_COMMENTS = "Excessive Comments" + DEEPLY_NESTED = "Deeply Nested Code" + PRIMITIVE_OBSESSION = "Primitive Obsession" + DATA_CLUMPS = "Data Clumps" + SWITCH_STATEMENT = "Switch Statement" + MESSAGE_CHAIN = "Message Chain" + + +@dataclass +class CodeSmell: + """Represents a detected code smell.""" + smell_type: SmellType + severity: SmellSeverity + location: str + line_start: int + line_end: int + description: str + suggestion: str + code_snippet: str = "" + + +@dataclass +class SmellReport: + """Report of all smells found in a file.""" + filename: str + smells: List[CodeSmell] = field(default_factory=list) + + @property + def critical_count(self) -> int: + return sum(1 for s in self.smells if s.severity == SmellSeverity.CRITICAL) + + @property + def high_count(self) -> int: + return sum(1 for s in self.smells if s.severity == SmellSeverity.HIGH) + + @property + def medium_count(self) -> int: + return sum(1 for s in self.smells if s.severity == SmellSeverity.MEDIUM) + + @property + def low_count(self) -> int: + return sum(1 for s in self.smells if s.severity == SmellSeverity.LOW) + + +class SmellDetector: + """Detect code smells in source files.""" + + # Thresholds (configurable) + THRESHOLDS = { + 'long_method_lines': 30, + 'very_long_method_lines': 50, + 'max_parameters': 4, + 'large_class_lines': 300, + 'large_class_methods': 10, + 'max_nesting_depth': 4, + 'long_chain_length': 3, + 'duplicate_min_lines': 5, + } + + def __init__(self, filepath: str): + self.filepath = filepath + self.filename = os.path.basename(filepath) + self.language = self._detect_language() + + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + self.code = f.read() + self.lines = self.code.split('\n') + self.smells: List[CodeSmell] = [] + + def _detect_language(self) -> str: + """Detect programming language from file extension.""" + ext = os.path.splitext(self.filepath)[1].lower() + ext_map = { + '.py': 'python', + '.js': 'javascript', + '.jsx': 'javascript', + '.ts': 'typescript', + '.tsx': 'typescript', + } + return ext_map.get(ext, 'python') + + def detect_all(self) -> SmellReport: + """Run all smell detectors.""" + self._detect_long_methods() + self._detect_long_parameter_lists() + self._detect_large_class() + self._detect_complex_conditionals() + self._detect_magic_numbers() + self._detect_excessive_comments() + self._detect_deeply_nested() + self._detect_switch_statements() + self._detect_message_chains() + self._detect_duplicate_code() + self._detect_dead_code() + + return SmellReport(filename=self.filename, smells=self.smells) + + def _get_snippet(self, start: int, end: int, context: int = 2) -> str: + """Get code snippet with context.""" + actual_start = max(0, start - context) + actual_end = min(len(self.lines), end + context) + snippet_lines = [] + for i in range(actual_start, actual_end): + prefix = "→ " if start <= i < end else " " + snippet_lines.append(f"{i+1:4d} {prefix}{self.lines[i]}") + return '\n'.join(snippet_lines) + + def _detect_long_methods(self) -> None: + """Detect methods that are too long.""" + if self.language == 'python': + pattern = r'^\s*def\s+(\w+)\s*\([^)]*\):' + else: + pattern = r'(?:function\s+(\w+)|(\w+)\s*[=:]\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))' + + current_method = None + method_start = 0 + brace_depth = 0 + indent_level = 0 + + for i, line in enumerate(self.lines): + match = re.search(pattern, line) + if match: + # Check previous method if exists + if current_method: + method_lines = i - method_start + self._check_method_length(current_method, method_start, i - 1, method_lines) + + current_method = match.group(1) or (match.group(2) if match.lastindex and match.lastindex > 1 else None) + method_start = i + indent_level = len(line) - len(line.lstrip()) + + # Track end of Python functions by indentation + if self.language == 'python' and current_method: + if line.strip() and not line.strip().startswith('#'): + current_indent = len(line) - len(line.lstrip()) + if current_indent <= indent_level and i > method_start: + method_lines = i - method_start + self._check_method_length(current_method, method_start, i - 1, method_lines) + current_method = None + + # Check last method + if current_method: + method_lines = len(self.lines) - method_start + self._check_method_length(current_method, method_start, len(self.lines) - 1, method_lines) + + def _check_method_length(self, name: str, start: int, end: int, lines: int) -> None: + """Check if method is too long and add smell if so.""" + if lines > self.THRESHOLDS['very_long_method_lines']: + severity = SmellSeverity.HIGH + desc = f"Method '{name}' is {lines} lines (threshold: {self.THRESHOLDS['long_method_lines']})" + elif lines > self.THRESHOLDS['long_method_lines']: + severity = SmellSeverity.MEDIUM + desc = f"Method '{name}' is {lines} lines (threshold: {self.THRESHOLDS['long_method_lines']})" + else: + return + + self.smells.append(CodeSmell( + smell_type=SmellType.LONG_METHOD, + severity=severity, + location=f"{self.filename}:{start+1}-{end+1}", + line_start=start + 1, + line_end=end + 1, + description=desc, + suggestion="Apply Extract Method to break down into smaller functions", + code_snippet=self._get_snippet(start, min(start + 5, end), 0) + )) + + def _detect_long_parameter_lists(self) -> None: + """Detect functions with too many parameters.""" + if self.language == 'python': + pattern = r'def\s+(\w+)\s*\(([^)]*)\)' + else: + pattern = r'(?:function\s+(\w+)\s*\(([^)]*)\)|(\w+)\s*[=:]\s*(?:async\s+)?(?:function\s*)?\(([^)]*)\))' + + for i, line in enumerate(self.lines): + match = re.search(pattern, line) + if match: + # Safely extract groups + groups = match.groups() + func_name = groups[0] or (groups[2] if len(groups) > 2 else None) + params_str = groups[1] if len(groups) > 1 else "" + if not params_str and len(groups) > 3: + params_str = groups[3] or "" + + # Count parameters + if params_str.strip(): + params = [p.strip() for p in params_str.split(',') if p.strip()] + # Filter out 'self', 'cls' for Python + if self.language == 'python': + params = [p for p in params if p not in ('self', 'cls')] + param_count = len(params) + + if param_count > self.THRESHOLDS['max_parameters']: + severity = SmellSeverity.HIGH if param_count > 6 else SmellSeverity.MEDIUM + self.smells.append(CodeSmell( + smell_type=SmellType.LONG_PARAMETER_LIST, + severity=severity, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description=f"Function '{func_name}' has {param_count} parameters (max: {self.THRESHOLDS['max_parameters']})", + suggestion="Consider Introduce Parameter Object or Preserve Whole Object", + code_snippet=self._get_snippet(i, i + 1, 1) + )) + + def _detect_large_class(self) -> None: + """Detect classes that are too large.""" + if self.language == 'python': + class_pattern = r'^\s*class\s+(\w+)' + method_pattern = r'^\s+def\s+\w+' + else: + class_pattern = r'class\s+(\w+)' + method_pattern = r'(?:^\s+\w+\s*\([^)]*\)\s*\{|^\s+(?:async\s+)?\w+\s*=)' + + current_class = None + class_start = 0 + method_count = 0 + class_indent = 0 + + for i, line in enumerate(self.lines): + class_match = re.search(class_pattern, line) + if class_match: + # Check previous class + if current_class: + self._check_class_size(current_class, class_start, i - 1, method_count) + + current_class = class_match.group(1) + class_start = i + method_count = 0 + class_indent = len(line) - len(line.lstrip()) + + # Count methods in current class + if current_class and re.search(method_pattern, line): + method_count += 1 + + # Check last class + if current_class: + self._check_class_size(current_class, class_start, len(self.lines) - 1, method_count) + + def _check_class_size(self, name: str, start: int, end: int, methods: int) -> None: + """Check if class is too large.""" + lines = end - start + 1 + + issues = [] + severity = SmellSeverity.MEDIUM + + if lines > self.THRESHOLDS['large_class_lines']: + issues.append(f"{lines} lines (max: {self.THRESHOLDS['large_class_lines']})") + severity = SmellSeverity.HIGH + + if methods > self.THRESHOLDS['large_class_methods']: + issues.append(f"{methods} methods (max: {self.THRESHOLDS['large_class_methods']})") + if severity != SmellSeverity.HIGH: + severity = SmellSeverity.MEDIUM + + if issues: + self.smells.append(CodeSmell( + smell_type=SmellType.LARGE_CLASS, + severity=severity, + location=f"{self.filename}:{start+1}-{end+1}", + line_start=start + 1, + line_end=end + 1, + description=f"Class '{name}' is too large: {', '.join(issues)}", + suggestion="Apply Extract Class to split responsibilities", + code_snippet=self._get_snippet(start, start + 3, 0) + )) + + def _detect_complex_conditionals(self) -> None: + """Detect complex conditional expressions.""" + for i, line in enumerate(self.lines): + # Count logical operators in line + and_or_count = len(re.findall(r'\b(and|or|&&|\|\|)\b', line)) + + if and_or_count >= 3: + self.smells.append(CodeSmell( + smell_type=SmellType.COMPLEX_CONDITIONAL, + severity=SmellSeverity.MEDIUM, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description=f"Complex conditional with {and_or_count} logical operators", + suggestion="Apply Decompose Conditional or Consolidate Conditional Expression", + code_snippet=self._get_snippet(i, i + 1, 1) + )) + + def _detect_magic_numbers(self) -> None: + """Detect magic numbers and strings.""" + # Skip common acceptable values + acceptable = {'0', '1', '-1', '2', '100', 'true', 'false', 'null', 'None', '""', "''"} + + for i, line in enumerate(self.lines): + # Skip comments and imports + stripped = line.strip() + if stripped.startswith('#') or stripped.startswith('//') or \ + stripped.startswith('import') or stripped.startswith('from'): + continue + + # Find numeric literals (excluding in variable names) + numbers = re.findall(r'(? 2: + # Check if it's likely a magic number (in calculation or comparison) + if re.search(rf'[<>=+\-*/]\s*{re.escape(num)}|{re.escape(num)}\s*[<>=+\-*/]', line): + self.smells.append(CodeSmell( + smell_type=SmellType.MAGIC_NUMBER, + severity=SmellSeverity.LOW, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description=f"Magic number '{num}' - consider using a named constant", + suggestion="Replace magic number with named constant", + code_snippet=self._get_snippet(i, i + 1, 0) + )) + break # One magic number per line is enough + + def _detect_excessive_comments(self) -> None: + """Detect comments that explain 'what' instead of 'why'.""" + what_patterns = [ + r'#\s*(set|get|return|loop|iterate|check|if|increment|decrement)', + r'//\s*(set|get|return|loop|iterate|check|if|increment|decrement)', + ] + + for i, line in enumerate(self.lines): + for pattern in what_patterns: + if re.search(pattern, line, re.IGNORECASE): + self.smells.append(CodeSmell( + smell_type=SmellType.EXCESSIVE_COMMENTS, + severity=SmellSeverity.LOW, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description="Comment explains 'what' not 'why' - consider renaming or removing", + suggestion="Use Extract Method with descriptive name instead of comment", + code_snippet=self._get_snippet(i, i + 1, 0) + )) + break + + def _detect_deeply_nested(self) -> None: + """Detect deeply nested code blocks.""" + max_depth = 0 + current_depth = 0 + depth_start = 0 + + for i, line in enumerate(self.lines): + if self.language == 'python': + # Count by indentation + if line.strip(): + indent = len(line) - len(line.lstrip()) + depth = indent // 4 # Assume 4-space indent + if depth > current_depth: + if depth > max_depth: + max_depth = depth + if depth >= self.THRESHOLDS['max_nesting_depth']: + depth_start = i + current_depth = depth + else: + # Count braces + current_depth += line.count('{') - line.count('}') + if current_depth > max_depth: + max_depth = current_depth + if current_depth >= self.THRESHOLDS['max_nesting_depth']: + depth_start = i + + if max_depth >= self.THRESHOLDS['max_nesting_depth']: + self.smells.append(CodeSmell( + smell_type=SmellType.DEEPLY_NESTED, + severity=SmellSeverity.HIGH if max_depth > 5 else SmellSeverity.MEDIUM, + location=f"{self.filename}:{depth_start+1}", + line_start=depth_start + 1, + line_end=depth_start + 1, + description=f"Code nested {max_depth} levels deep (max: {self.THRESHOLDS['max_nesting_depth']})", + suggestion="Apply Replace Nested Conditional with Guard Clauses or Extract Method", + code_snippet=self._get_snippet(depth_start, depth_start + 5, 0) + )) + + def _detect_switch_statements(self) -> None: + """Detect switch statements that might need polymorphism.""" + if self.language == 'python': + # Python 3.10+ match statements or if/elif chains + pattern = r'^\s*(if|elif).*==.*:' + consecutive_conditions = 0 + chain_start = 0 + + for i, line in enumerate(self.lines): + if re.search(pattern, line): + if consecutive_conditions == 0: + chain_start = i + consecutive_conditions += 1 + else: + if consecutive_conditions >= 4: + self._add_switch_smell(chain_start, i - 1, consecutive_conditions) + consecutive_conditions = 0 + else: + # JavaScript/TypeScript switch + pattern = r'\bswitch\s*\(' + for i, line in enumerate(self.lines): + if re.search(pattern, line): + # Count cases + case_count = 0 + for j in range(i, min(i + 50, len(self.lines))): + case_count += len(re.findall(r'\bcase\b', self.lines[j])) + if case_count >= 4: + self._add_switch_smell(i, i + 1, case_count) + + def _add_switch_smell(self, start: int, end: int, cases: int) -> None: + """Add a switch statement smell.""" + self.smells.append(CodeSmell( + smell_type=SmellType.SWITCH_STATEMENT, + severity=SmellSeverity.MEDIUM, + location=f"{self.filename}:{start+1}", + line_start=start + 1, + line_end=end + 1, + description=f"Switch/case statement with {cases} cases - consider polymorphism", + suggestion="Apply Replace Conditional with Polymorphism", + code_snippet=self._get_snippet(start, start + 5, 0) + )) + + def _detect_message_chains(self) -> None: + """Detect long method chains (train wrecks).""" + chain_pattern = r'(\w+(?:\.\w+\([^)]*\)){3,})' + + for i, line in enumerate(self.lines): + matches = re.findall(chain_pattern, line) + for match in matches: + chain_length = match.count('.') + if chain_length >= self.THRESHOLDS['long_chain_length']: + self.smells.append(CodeSmell( + smell_type=SmellType.MESSAGE_CHAIN, + severity=SmellSeverity.MEDIUM, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description=f"Message chain with {chain_length} calls - violates Law of Demeter", + suggestion="Apply Hide Delegate to reduce coupling", + code_snippet=self._get_snippet(i, i + 1, 0) + )) + + def _detect_duplicate_code(self) -> None: + """Detect potential duplicate code blocks (simplified).""" + # Create line hashes for comparison + line_hashes: Dict[str, List[int]] = defaultdict(list) + + for i, line in enumerate(self.lines): + normalized = re.sub(r'\s+', ' ', line.strip()) + if len(normalized) > 20: # Only significant lines + line_hashes[normalized].append(i) + + # Find duplicates + for normalized, positions in line_hashes.items(): + if len(positions) >= 3: # At least 3 occurrences + self.smells.append(CodeSmell( + smell_type=SmellType.DUPLICATE_CODE, + severity=SmellSeverity.MEDIUM, + location=f"{self.filename}:{positions[0]+1}", + line_start=positions[0] + 1, + line_end=positions[0] + 1, + description=f"Potential duplicate code found {len(positions)} times", + suggestion="Apply Extract Method to eliminate duplication", + code_snippet=self._get_snippet(positions[0], positions[0] + 1, 0) + )) + + def _detect_dead_code(self) -> None: + """Detect potentially dead code (simplified).""" + # Look for common dead code patterns + patterns = [ + (r'^\s*#.*TODO.*delete', "TODO to delete"), + (r'^\s*#.*FIXME.*remove', "FIXME to remove"), + (r'^\s*//.*TODO.*delete', "TODO to delete"), + (r'^\s*//.*FIXME.*remove', "FIXME to remove"), + (r'^\s*if\s+False:', "Code behind 'if False'"), + (r'^\s*if\s*\(\s*false\s*\)', "Code behind 'if (false)'"), + ] + + for i, line in enumerate(self.lines): + for pattern, desc in patterns: + if re.search(pattern, line, re.IGNORECASE): + self.smells.append(CodeSmell( + smell_type=SmellType.DEAD_CODE, + severity=SmellSeverity.LOW, + location=f"{self.filename}:{i+1}", + line_start=i + 1, + line_end=i + 1, + description=f"Potential dead code: {desc}", + suggestion="Remove dead code", + code_snippet=self._get_snippet(i, i + 1, 0) + )) + + +def print_report(report: SmellReport, verbose: bool = False) -> None: + """Print smell report in readable format.""" + print("=" * 70) + print(f"CODE SMELL DETECTION REPORT: {report.filename}") + print("=" * 70) + + print(f"\n📊 SUMMARY") + print("-" * 40) + print(f" Total smells found: {len(report.smells)}") + print(f" Critical: {report.critical_count}") + print(f" High: {report.high_count}") + print(f" Medium: {report.medium_count}") + print(f" Low: {report.low_count}") + + if not report.smells: + print("\n✅ No code smells detected!") + print("=" * 70) + return + + # Group by type + by_type: Dict[SmellType, List[CodeSmell]] = defaultdict(list) + for smell in report.smells: + by_type[smell.smell_type].append(smell) + + print(f"\n📋 FINDINGS BY TYPE") + print("-" * 40) + + for smell_type, smells in sorted(by_type.items(), key=lambda x: -len(x[1])): + print(f"\n### {smell_type.value} ({len(smells)} found)") + + for smell in sorted(smells, key=lambda x: x.severity.value): + severity_icon = { + SmellSeverity.CRITICAL: "🔴", + SmellSeverity.HIGH: "🟠", + SmellSeverity.MEDIUM: "🟡", + SmellSeverity.LOW: "🟢", + }[smell.severity] + + print(f"\n {severity_icon} [{smell.severity.value}] {smell.location}") + print(f" {smell.description}") + print(f" 💡 {smell.suggestion}") + + if verbose and smell.code_snippet: + print(f"\n Code:") + for snippet_line in smell.code_snippet.split('\n'): + print(f" {snippet_line}") + + print("\n" + "=" * 70) + print("💡 RECOMMENDED ACTIONS") + print("-" * 40) + + if report.critical_count > 0: + print(" 1. Address CRITICAL issues immediately") + if report.high_count > 0: + print(" 2. Plan to fix HIGH severity issues this sprint") + if report.medium_count > 0: + print(" 3. Schedule MEDIUM issues for upcoming work") + if report.low_count > 0: + print(" 4. Fix LOW issues opportunistically") + + print("\n" + "=" * 70) + + +def analyze_directory(directory: str, verbose: bool = False) -> None: + """Analyze all supported files in a directory.""" + supported_extensions = ['.py', '.js', '.jsx', '.ts', '.tsx'] + files = [] + + for root, _, filenames in os.walk(directory): + for filename in filenames: + if any(filename.endswith(ext) for ext in supported_extensions): + files.append(os.path.join(root, filename)) + + if not files: + print(f"No supported files found in {directory}") + return + + print(f"Scanning {len(files)} files in {directory}...\n") + + total_smells = 0 + total_critical = 0 + total_high = 0 + files_with_smells = 0 + + for filepath in sorted(files): + try: + detector = SmellDetector(filepath) + report = detector.detect_all() + + if report.smells: + files_with_smells += 1 + total_smells += len(report.smells) + total_critical += report.critical_count + total_high += report.high_count + + flag = " 🔴" if report.critical_count else (" 🟠" if report.high_count else " 🟡") + print(f" {report.filename}: {len(report.smells)} smells{flag}") + + if verbose: + for smell in report.smells: + print(f" - [{smell.severity.value}] {smell.smell_type.value}: line {smell.line_start}") + else: + print(f" {report.filename}: ✅ Clean") + + except Exception as e: + print(f" Error analyzing {filepath}: {e}") + + print("\n" + "=" * 60) + print("SUMMARY") + print("=" * 60) + print(f" Files analyzed: {len(files)}") + print(f" Files with smells: {files_with_smells}") + print(f" Total smells found: {total_smells}") + print(f" Critical issues: {total_critical}") + print(f" High severity issues: {total_high}") + + +def main(): + parser = argparse.ArgumentParser( + description='Detect code smells in source files', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + %(prog)s myfile.py Analyze single file + %(prog)s --dir src/ Analyze directory + %(prog)s -v myfile.py Verbose with code snippets + """ + ) + parser.add_argument('file', nargs='?', help='File to analyze') + parser.add_argument('--dir', '-d', help='Directory to analyze') + parser.add_argument('--verbose', '-v', action='store_true', help='Show code snippets') + parser.add_argument('--json', '-j', action='store_true', help='Output as JSON') + + args = parser.parse_args() + + if args.dir: + analyze_directory(args.dir, args.verbose) + elif args.file: + detector = SmellDetector(args.file) + report = detector.detect_all() + + if args.json: + import json + smells_data = [{ + 'type': s.smell_type.value, + 'severity': s.severity.value, + 'location': s.location, + 'line_start': s.line_start, + 'line_end': s.line_end, + 'description': s.description, + 'suggestion': s.suggestion, + } for s in report.smells] + print(json.dumps({ + 'filename': report.filename, + 'total_smells': len(report.smells), + 'critical': report.critical_count, + 'high': report.high_count, + 'medium': report.medium_count, + 'low': report.low_count, + 'smells': smells_data + }, indent=2)) + else: + print_report(report, args.verbose) + else: + parser.print_help() + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/uk/05-mcp/README.md b/uk/05-mcp/README.md new file mode 100644 index 0000000..3e6d476 --- /dev/null +++ b/uk/05-mcp/README.md @@ -0,0 +1,1086 @@ + + + + + + + Claude How To + + +# MCP (Model Context Protocol) + +Ця папка містить вичерпну документацію та приклади конфігурацій MCP-серверів та їх використання з Claude Code. + +## Огляд + +MCP (Model Context Protocol) — це стандартизований спосіб доступу Claude до зовнішніх інструментів, API та джерел даних у реальному часі. На відміну від пам'яті, MCP забезпечує живий доступ до змінюваних даних. + +Ключові характеристики: +- Доступ до зовнішніх сервісів у реальному часі +- Синхронізація даних у реальному часі +- Розширювана архітектура +- Безпечна автентифікація +- Взаємодія на основі інструментів + +## Архітектура MCP + +```mermaid +graph TB + A["Claude"] + B["MCP Server"] + C["External Service"] + + A -->|Request: list_issues| B + B -->|Query| C + C -->|Data| B + B -->|Response| A + + A -->|Request: create_issue| B + B -->|Action| C + C -->|Result| B + B -->|Response| A + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#f3e5f5,stroke:#333,color:#333 + style C fill:#e8f5e9,stroke:#333,color:#333 +``` + +## Екосистема MCP + +```mermaid +graph TB + A["Claude"] -->|MCP| B["Filesystem
MCP Server"] + A -->|MCP| C["GitHub
MCP Server"] + A -->|MCP| D["Database
MCP Server"] + A -->|MCP| E["Slack
MCP Server"] + A -->|MCP| F["Google Docs
MCP Server"] + + B -->|File I/O| G["Local Files"] + C -->|API| H["GitHub Repos"] + D -->|Query| I["PostgreSQL/MySQL"] + E -->|Messages| J["Slack Workspace"] + F -->|Docs| K["Google Drive"] + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#f3e5f5,stroke:#333,color:#333 + style C fill:#f3e5f5,stroke:#333,color:#333 + style D fill:#f3e5f5,stroke:#333,color:#333 + style E fill:#f3e5f5,stroke:#333,color:#333 + style F fill:#f3e5f5,stroke:#333,color:#333 + style G fill:#e8f5e9,stroke:#333,color:#333 + style H fill:#e8f5e9,stroke:#333,color:#333 + style I fill:#e8f5e9,stroke:#333,color:#333 + style J fill:#e8f5e9,stroke:#333,color:#333 + style K fill:#e8f5e9,stroke:#333,color:#333 +``` + +## Методи встановлення MCP + +Claude Code підтримує кілька транспортних протоколів для підключення до MCP-серверів: + +### HTTP-транспорт (рекомендовано) + +```bash +# Базове HTTP-підключення +claude mcp add --transport http notion https://mcp.notion.com/mcp + +# HTTP з заголовком автентифікації +claude mcp add --transport http secure-api https://api.example.com/mcp \ + --header "Authorization: Bearer your-token" +``` + +### Stdio-транспорт (локальний) + +Для локально запущених MCP-серверів: + +```bash +# Локальний Node.js-сервер +claude mcp add --transport stdio myserver -- npx @myorg/mcp-server + +# Зі змінними оточення +claude mcp add --transport stdio myserver --env KEY=value -- npx server +``` + +### SSE-транспорт (застарілий) + +Транспорт Server-Sent Events застарілий на користь `http`, але все ще підтримується: + +```bash +claude mcp add --transport sse legacy-server https://example.com/sse +``` + +### Примітка для Windows + +На нативній Windows (не WSL) використовуйте `cmd /c` для команд npx: + +```bash +claude mcp add --transport stdio my-server -- cmd /c npx -y @some/package +``` + +### Автентифікація OAuth 2.0 + +Claude Code підтримує OAuth 2.0 для MCP-серверів, що його потребують. При підключенні до сервера з OAuth Claude Code обробляє весь потік автентифікації: + +```bash +# Підключення до MCP-сервера з OAuth (інтерактивний потік) +claude mcp add --transport http my-service https://my-service.example.com/mcp + +# Попередньо налаштовані облікові дані OAuth для неінтерактивного встановлення +claude mcp add --transport http my-service https://my-service.example.com/mcp \ + --client-id "your-client-id" \ + --client-secret "your-client-secret" \ + --callback-port 8080 +``` + +| Функція | Опис | +|---------|------| +| **Інтерактивний OAuth** | Використовуйте `/mcp` для запуску OAuth-потоку через браузер | +| **Попередньо налаштовані OAuth-клієнти** | Вбудовані OAuth-клієнти для популярних сервісів: Notion, Stripe та інших (v2.1.30+) | +| **Попередньо налаштовані облікові дані** | Прапорці `--client-id`, `--client-secret`, `--callback-port` для автоматизованого встановлення | +| **Зберігання токенів** | Токени зберігаються безпечно у системному keychain | +| **Step-up auth** | Підтримка step-up автентифікації для привілейованих операцій | +| **Кешування виявлення** | Метадані OAuth discovery кешуються для швидших перепідключень | +| **Перевизначення метаданих** | `oauth.authServerMetadataUrl` у `.mcp.json` для перевизначення стандартного OAuth metadata discovery | + +#### Перевизначення OAuth Metadata Discovery + +Якщо ваш MCP-сервер повертає помилки на стандартному ендпоінті OAuth metadata (`/.well-known/oauth-authorization-server`), але має робочий OIDC-ендпоінт, ви можете вказати Claude Code отримувати метадані OAuth з конкретного URL. Встановіть `authServerMetadataUrl` в об'єкті `oauth` конфігурації сервера: + +```json +{ + "mcpServers": { + "my-server": { + "type": "http", + "url": "https://mcp.example.com/mcp", + "oauth": { + "authServerMetadataUrl": "https://auth.example.com/.well-known/openid-configuration" + } + } + } +} +``` + +URL повинен використовувати `https://`. Ця опція потребує Claude Code v2.1.64 або новішої. + +### MCP-конектори Claude.ai + +MCP-сервери, налаштовані у вашому обліковому записі Claude.ai, автоматично доступні в Claude Code. Будь-які MCP-підключення, налаштовані через веб-інтерфейс Claude.ai, будуть доступні без додаткової конфігурації. + +MCP-конектори Claude.ai також доступні в режимі `--print` (v2.1.83+), що дозволяє неінтерактивне та скриптове використання. + +Для вимкнення MCP-серверів Claude.ai у Claude Code встановіть змінну оточення `ENABLE_CLAUDEAI_MCP_SERVERS` у `false`: + +```bash +ENABLE_CLAUDEAI_MCP_SERVERS=false claude +``` + +> **Примітка:** Ця функція доступна лише для користувачів, авторизованих через облікові записи Claude.ai. + +## Процес налаштування MCP + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Config as Config File + participant Service as External Service + + User->>Claude: Type /mcp + Claude->>Claude: List available MCP servers + Claude->>User: Show options + User->>Claude: Select GitHub MCP + Claude->>Config: Update configuration + Config->>Claude: Activate connection + Claude->>Service: Test connection + Service-->>Claude: Authentication successful + Claude->>User: ✅ MCP connected! +``` + +## Пошук інструментів MCP + +Коли описи інструментів MCP перевищують 10% контекстного вікна, Claude Code автоматично вмикає пошук інструментів для ефективного вибору правильних інструментів без перевантаження контексту моделі. + +| Налаштування | Значення | Опис | +|-------------|----------|------| +| `ENABLE_TOOL_SEARCH` | `auto` (за замовч.) | Автоматично вмикається, коли описи інструментів перевищують 10% контексту | +| `ENABLE_TOOL_SEARCH` | `auto:` | Автоматично вмикається при користувацькому порозі `N` інструментів | +| `ENABLE_TOOL_SEARCH` | `true` | Завжди увімкнено незалежно від кількості інструментів | +| `ENABLE_TOOL_SEARCH` | `false` | Вимкнено; всі описи інструментів надсилаються повністю | + +> **Примітка:** Пошук інструментів потребує Sonnet 4 або новіший, або Opus 4 або новіший. Моделі Haiku не підтримують пошук інструментів. + +## Динамічне оновлення інструментів + +Claude Code підтримує сповіщення MCP `list_changed`. Коли MCP-сервер динамічно додає, видаляє або змінює доступні інструменти, Claude Code отримує оновлення та автоматично коригує список інструментів — без потреби перепідключення або перезапуску. + +## MCP Apps + +MCP Apps — перше офіційне розширення MCP, що дозволяє викликам інструментів MCP повертати інтерактивні UI-компоненти, які рендеряться безпосередньо в інтерфейсі чату. Замість текстових відповідей MCP-сервери можуть надавати інтерактивні дашборди, форми, візуалізації даних та багатокрокові воркфлови — все відображається прямо в розмові. + +## MCP Elicitation + +MCP-сервери можуть запитувати структурований ввід від користувача через інтерактивні діалоги (v2.1.49+). Це дозволяє MCP-серверу запитувати додаткову інформацію під час воркфлову — наприклад, підтвердження, вибір зі списку опцій або заповнення обов'язкових полів — додаючи інтерактивність до взаємодії з MCP-серверами. + +## Ліміт описів інструментів та інструкцій + +Починаючи з v2.1.84, Claude Code встановлює **ліміт 2 КБ** на описи та інструкції інструментів для кожного MCP-сервера. Це запобігає споживанню надмірного контексту окремими серверами з занадто багатослівними визначеннями інструментів. + +## MCP Prompts як слеш-команди + +MCP-сервери можуть надавати промпти, що відображаються як слеш-команди в Claude Code. Промпти доступні за конвенцією іменування: + +``` +/mcp____ +``` + +Наприклад, якщо сервер `github` надає промпт `review`, його можна викликати як `/mcp__github__review`. + +## Дедуплікація серверів + +Коли один і той самий MCP-сервер визначений на кількох рівнях (local, project, user), локальна конфігурація має пріоритет. Це дозволяє перевизначати налаштування MCP рівня проєкту або користувача локальними кастомізаціями без конфліктів. + +## MCP-ресурси через @-згадки + +Ви можете посилатися на MCP-ресурси безпосередньо в промптах через синтаксис `@`: + +``` +@server-name:protocol://resource/path +``` + +Наприклад, для посилання на конкретний ресурс бази даних: + +``` +@database:postgres://mydb/users +``` + +Це дозволяє Claude отримувати та включати вміст MCP-ресурсів у контекст розмови. + +## Рівні MCP + +Конфігурації MCP можна зберігати на різних рівнях з різним ступенем поширення: + +| Рівень | Розташування | Опис | Доступний для | Потребує підтвердження | +|--------|-------------|------|---------------|----------------------| +| **Local** (за замовч.) | `~/.claude.json` (під шляхом проєкту) | Приватний для поточного користувача, лише поточний проєкт (раніше називався `project`) | Лише ви | Ні | +| **Project** | `.mcp.json` | Комітиться в git-репозиторій | Члени команди | Так (при першому використанні) | +| **User** | `~/.claude.json` | Доступний у всіх проєктах (раніше називався `global`) | Лише ви | Ні | + +### Використання рівня Project + +Зберігайте конфігурації MCP, специфічні для проєкту, у `.mcp.json`: + +```json +{ + "mcpServers": { + "github": { + "type": "http", + "url": "https://api.github.com/mcp" + } + } +} +``` + +Члени команди побачать запит на підтвердження при першому використанні MCP проєкту. + +## Управління конфігурацією MCP + +### Додавання MCP-серверів + +```bash +# Додати HTTP-сервер +claude mcp add --transport http github https://api.github.com/mcp + +# Додати локальний stdio-сервер +claude mcp add --transport stdio database -- npx @company/db-server + +# Список всіх MCP-серверів +claude mcp list + +# Деталі конкретного сервера +claude mcp get github + +# Видалити MCP-сервер +claude mcp remove github + +# Скинути вибори підтвердження для проєкту +claude mcp reset-project-choices + +# Імпорт з Claude Desktop +claude mcp add-from-claude-desktop +``` + +## Таблиця доступних MCP-серверів + +| MCP-сервер | Призначення | Типові інструменти | Авторизація | Реальний час | +|-----------|------------|-------------------|-------------|-------------| +| **Filesystem** | Файлові операції | read, write, delete | Дозволи ОС | ✅ Так | +| **GitHub** | Управління репозиторіями | list_prs, create_issue, push | OAuth | ✅ Так | +| **Slack** | Командна комунікація | send_message, list_channels | Токен | ✅ Так | +| **Database** | SQL-запити | query, insert, update | Облікові дані | ✅ Так | +| **Google Docs** | Доступ до документів | read, write, share | OAuth | ✅ Так | +| **Asana** | Управління проєктами | create_task, update_status | API Key | ✅ Так | +| **Stripe** | Платіжні дані | list_charges, create_invoice | API Key | ✅ Так | +| **Memory** | Постійна пам'ять | store, retrieve, delete | Локальна | ❌ Ні | + +## Практичні приклади + +### Приклад 1: Конфігурація GitHub MCP + +**Файл:** `.mcp.json` (корінь проєкту) + +```json +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} +``` + +**Доступні інструменти GitHub MCP:** + +#### Управління Pull Request +- `list_prs` — список усіх PR у репозиторії +- `get_pr` — деталі PR, включаючи diff +- `create_pr` — створення нового PR +- `update_pr` — оновлення опису/назви PR +- `merge_pr` — мердж PR у main +- `review_pr` — додавання коментарів рев'ю + +**Приклад запиту:** +``` +/mcp__github__get_pr 456 + +# Повертає: +Title: Add dark mode support +Author: @alice +Description: Implements dark theme using CSS variables +Status: OPEN +Reviewers: @bob, @charlie +``` + +#### Управління Issue +- `list_issues` — список усіх issue +- `get_issue` — деталі issue +- `create_issue` — створення нового issue +- `close_issue` — закриття issue +- `add_comment` — додавання коментаря + +#### Інформація про репозиторій +- `get_repo_info` — деталі репозиторію +- `list_files` — структура файлового дерева +- `get_file_content` — читання вмісту файлу +- `search_code` — пошук по кодовій базі + +#### Операції з комітами +- `list_commits` — історія комітів +- `get_commit` — деталі конкретного коміту +- `create_commit` — створення нового коміту + +**Налаштування**: +```bash +export GITHUB_TOKEN="your_github_token" +# Або додайте через CLI: +claude mcp add --transport stdio github -- npx @modelcontextprotocol/server-github +``` + +### Підстановка змінних оточення в конфігурації + +Конфігурації MCP підтримують підстановку змінних оточення з резервними значеннями. Синтаксис `${VAR}` та `${VAR:-default}` працює в полях: `command`, `args`, `env`, `url` та `headers`. + +```json +{ + "mcpServers": { + "api-server": { + "type": "http", + "url": "${API_BASE_URL:-https://api.example.com}/mcp", + "headers": { + "Authorization": "Bearer ${API_KEY}", + "X-Custom-Header": "${CUSTOM_HEADER:-default-value}" + } + }, + "local-server": { + "command": "${MCP_BIN_PATH:-npx}", + "args": ["${MCP_PACKAGE:-@company/mcp-server}"], + "env": { + "DB_URL": "${DATABASE_URL:-postgresql://localhost/dev}" + } + } + } +} +``` + +Змінні розгортаються під час виконання: +- `${VAR}` — використовує змінну оточення, помилка якщо не встановлена +- `${VAR:-default}` — використовує змінну оточення, резервне значення якщо не встановлена + +### Приклад 2: Налаштування Database MCP + +**Конфігурація:** + +```json +{ + "mcpServers": { + "database": { + "command": "npx", + "args": ["@modelcontextprotocol/server-database"], + "env": { + "DATABASE_URL": "postgresql://user:pass@localhost/mydb" + } + } + } +} +``` + +**Приклад використання:** + +```markdown +User: Fetch all users with more than 10 orders + +Claude: I'll query your database to find that information. + +# Використання інструменту MCP database: +SELECT u.*, COUNT(o.id) as order_count +FROM users u +LEFT JOIN orders o ON u.id = o.user_id +GROUP BY u.id +HAVING COUNT(o.id) > 10 +ORDER BY order_count DESC; + +# Результати: +- Alice: 15 orders +- Bob: 12 orders +- Charlie: 11 orders +``` + +**Налаштування**: +```bash +export DATABASE_URL="postgresql://user:pass@localhost/mydb" +# Або додайте через CLI: +claude mcp add --transport stdio database -- npx @modelcontextprotocol/server-database +``` + +### Приклад 3: Мульти-MCP воркфлов + +**Сценарій: генерація щоденного звіту** + +```markdown +# Щоденний звіт з використанням кількох MCP + +## Налаштування +1. GitHub MCP — метрики PR +2. Database MCP — дані продажів +3. Slack MCP — публікація звіту +4. Filesystem MCP — збереження звіту + +## Воркфлов + +### Крок 1: Отримання даних GitHub +/mcp__github__list_prs completed:true last:7days + +### Крок 2: Запит до бази даних +SELECT COUNT(*) as sales, SUM(amount) as revenue +FROM orders +WHERE created_at > NOW() - INTERVAL '1 day' + +### Крок 3: Генерація звіту + +### Крок 4: Збереження у файлову систему + +### Крок 5: Публікація в Slack +``` + +### Приклад 4: Операції Filesystem MCP + +**Конфігурація:** + +```json +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["@modelcontextprotocol/server-filesystem", "/home/user/projects"] + } + } +} +``` + +**Доступні операції:** + +| Операція | Команда | Призначення | +|---------|---------|------------| +| Список файлів | `ls ~/projects` | Показати вміст каталогу | +| Читання файлу | `cat src/main.ts` | Читання вмісту файлу | +| Запис файлу | `create docs/api.md` | Створення нового файлу | +| Редагування файлу | `edit src/app.ts` | Модифікація файлу | +| Пошук | `grep "async function"` | Пошук у файлах | +| Видалення | `rm old-file.js` | Видалення файлу | + +## MCP vs Пам'ять: матриця вибору + +```mermaid +graph TD + A["Need external data?"] + A -->|No| B["Use Memory"] + A -->|Yes| C["Does it change frequently?"] + C -->|No/Rarely| B + C -->|Yes/Often| D["Use MCP"] + + B -->|Stores| E["Preferences
Context
History"] + D -->|Accesses| F["Live APIs
Databases
Services"] + + style A fill:#fff3e0,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#fff3e0,stroke:#333,color:#333 + style D fill:#f3e5f5,stroke:#333,color:#333 + style E fill:#e8f5e9,stroke:#333,color:#333 + style F fill:#e8f5e9,stroke:#333,color:#333 +``` + +## Патерн запит/відповідь + +```mermaid +sequenceDiagram + participant App as Claude + participant MCP as MCP Server + participant DB as Database + + App->>MCP: Request: "SELECT * FROM users WHERE id=1" + MCP->>DB: Execute query + DB-->>MCP: Result set + MCP-->>App: Return parsed data + App->>App: Process result + App->>App: Continue task + + Note over MCP,DB: Real-time access
No caching +``` + +## Змінні оточення + +Зберігайте конфіденційні облікові дані у змінних оточення: + +```bash +# ~/.bashrc або ~/.zshrc +export GITHUB_TOKEN="ghp_xxxxxxxxxxxxx" +export DATABASE_URL="postgresql://user:pass@localhost/mydb" +export SLACK_TOKEN="xoxb-xxxxxxxxxxxxx" +``` + +Потім посилайтесь на них у конфігурації MCP: + +```json +{ + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } +} +``` + +## Claude як MCP-сервер (`claude mcp serve`) + +Сам Claude Code може працювати як MCP-сервер для інших додатків. Це дозволяє зовнішнім інструментам, редакторам та системам автоматизації використовувати можливості Claude через стандартний протокол MCP. + +```bash +# Запуск Claude Code як MCP-сервера через stdio +claude mcp serve +``` + +Інші додатки можуть підключатися до цього сервера як до будь-якого stdio-сервера MCP. Наприклад, додавання Claude Code як MCP-сервера в іншому екземплярі Claude Code: + +```bash +claude mcp add --transport stdio claude-agent -- claude mcp serve +``` + +Це корисно для побудови мультиагентних воркфловів, де один екземпляр Claude оркеструє інший. + +## Managed MCP Configuration (Enterprise) + +Для корпоративних розгортань IT-адміністратори можуть застосовувати політики MCP-серверів через конфігураційний файл `managed-mcp.json`. Цей файл забезпечує ексклюзивний контроль над дозволеними або заблокованими MCP-серверами на рівні організації. + +**Розташування:** +- macOS: `/Library/Application Support/ClaudeCode/managed-mcp.json` +- Linux: `~/.config/ClaudeCode/managed-mcp.json` +- Windows: `%APPDATA%\ClaudeCode\managed-mcp.json` + +**Функції:** +- `allowedMcpServers` — білий список дозволених серверів +- `deniedMcpServers` — чорний список заборонених серверів +- Підтримує зіставлення за назвою сервера, командою та URL-патернами +- Загальноорганізаційні політики MCP застосовуються перед конфігурацією користувача +- Запобігає неавторизованим підключенням серверів + +**Приклад конфігурації:** + +```json +{ + "allowedMcpServers": [ + { + "serverName": "github", + "serverUrl": "https://api.github.com/mcp" + }, + { + "serverName": "company-internal", + "serverCommand": "company-mcp-server" + } + ], + "deniedMcpServers": [ + { + "serverName": "untrusted-*" + }, + { + "serverUrl": "http://*" + } + ] +} +``` + +> **Примітка:** Коли і `allowedMcpServers`, і `deniedMcpServers` збігаються з сервером, правило заборони має пріоритет. + +## MCP-сервери плагінів + +Плагіни можуть включати власні MCP-сервери, які автоматично доступні при встановленні плагіна. MCP-сервери плагінів визначаються двома способами: + +1. **Окремий `.mcp.json`** — розміщення файлу `.mcp.json` у кореневому каталозі плагіна +2. **Вбудований у `plugin.json`** — визначення MCP-серверів безпосередньо у маніфесті плагіна + +Використовуйте змінну `${CLAUDE_PLUGIN_ROOT}` для посилання на шляхи відносно каталогу встановлення плагіна: + +```json +{ + "mcpServers": { + "plugin-tools": { + "command": "node", + "args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp-server.js"], + "env": { + "CONFIG_PATH": "${CLAUDE_PLUGIN_ROOT}/config.json" + } + } + } +} +``` + +## MCP, обмежений субагентом + +MCP-сервери можна визначати вбудовано у фронтматері агента через ключ `mcpServers:`, обмежуючи їх конкретним субагентом, а не всім проєктом. Це корисно, коли агенту потрібен доступ до конкретного MCP-сервера, який не потрібен іншим агентам у воркфлові. + +```yaml +--- +mcpServers: + my-tool: + type: http + url: https://my-tool.example.com/mcp +--- + +You are an agent with access to my-tool for specialized operations. +``` + +MCP-сервери, обмежені субагентом, доступні лише в контексті виконання цього агента і не поширюються на батьківського чи суміжних агентів. + +## Ліміти виводу MCP + +Claude Code встановлює ліміти на вивід інструментів MCP для запобігання переповненню контексту: + +| Ліміт | Поріг | Поведінка | +|-------|-------|----------| +| **Попередження** | 10 000 токенів | Відображається попередження про великий вивід | +| **Максимум за замовч.** | 25 000 токенів | Вивід обрізається за цим лімітом | +| **Збереження на диск** | 50 000 символів | Результати інструментів, що перевищують 50K символів, зберігаються на диск | + +Максимальний ліміт виводу налаштовується через змінну оточення `MAX_MCP_OUTPUT_TOKENS`: + +```bash +# Збільшити максимальний вивід до 50 000 токенів +export MAX_MCP_OUTPUT_TOKENS=50000 +``` + +## Розв'язання проблеми роздування контексту через виконання коду + +З масштабуванням MCP підключення до десятків серверів із сотнями або тисячами інструментів створює значну проблему: **роздування контексту** (context bloat). Це, мабуть, найбільша проблема MCP у масштабі, і інженерна команда Anthropic запропонувала елегантне рішення — використання виконання коду замість прямих викликів інструментів. + +> **Джерело**: [Code Execution with MCP: Building More Efficient Agents](https://www.anthropic.com/engineering/code-execution-with-mcp) — блог Anthropic Engineering + +### Проблема: два джерела марнування токенів + +**1. Визначення інструментів перевантажують контекстне вікно** + +Більшість MCP-клієнтів завантажують усі визначення інструментів наперед. При підключенні до тисяч інструментів модель повинна обробити сотні тисяч токенів, перш ніж прочитати запит користувача. + +**2. Проміжні результати споживають додаткові токени** + +Кожен проміжний результат інструменту проходить через контекст моделі. Наприклад, при перенесенні транскрипту зустрічі з Google Drive до Salesforce — повний транскрипт проходить через контекст **двічі**: при читанні та при записі в призначення. Дводинна зустріч може означати 50 000+ додаткових токенів. + +```mermaid +graph LR + A["Model"] -->|"Tool Call: getDocument"| B["MCP Server"] + B -->|"Full transcript (50K tokens)"| A + A -->|"Tool Call: updateRecord
(re-sends full transcript)"| B + B -->|"Confirmation"| A + + style A fill:#ffcdd2,stroke:#333,color:#333 + style B fill:#f3e5f5,stroke:#333,color:#333 +``` + +### Рішення: MCP-інструменти як код-API + +Замість передачі визначень інструментів та результатів через контекстне вікно, агент **пише код**, який викликає MCP-інструменти як API. Код виконується в ізольованому середовищі, і лише кінцевий результат повертається до моделі. + +```mermaid +graph LR + A["Model"] -->|"Writes code"| B["Code Execution
Environment"] + B -->|"Calls tools directly"| C["MCP Servers"] + C -->|"Data stays in
execution env"| B + B -->|"Only final result
(minimal tokens)"| A + + style A fill:#c8e6c9,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#f3e5f5,stroke:#333,color:#333 +``` + +#### Як це працює + +MCP-інструменти представляються як файлове дерево типізованих функцій: + +``` +servers/ +├── google-drive/ +│ ├── getDocument.ts +│ └── index.ts +├── salesforce/ +│ ├── updateRecord.ts +│ └── index.ts +└── ... +``` + +Кожен файл інструменту містить типізовану обгортку: + +```typescript +// ./servers/google-drive/getDocument.ts +import { callMCPTool } from "../../../client.js"; + +interface GetDocumentInput { + documentId: string; +} + +interface GetDocumentResponse { + content: string; +} + +export async function getDocument( + input: GetDocumentInput +): Promise { + return callMCPTool( + 'google_drive__get_document', input + ); +} +``` + +Агент пише код для оркестрації інструментів: + +```typescript +import * as gdrive from './servers/google-drive'; +import * as salesforce from './servers/salesforce'; + +// Дані передаються безпосередньо між інструментами — ніколи через модель +const transcript = ( + await gdrive.getDocument({ documentId: 'abc123' }) +).content; + +await salesforce.updateRecord({ + objectType: 'SalesMeeting', + recordId: '00Q5f000001abcXYZ', + data: { Notes: transcript } +}); +``` + +**Результат: використання токенів знижується з ~150 000 до ~2 000 — зменшення на 98,7%.** + +### Ключові переваги + +| Перевага | Опис | +|---------|------| +| **Прогресивне розкриття** | Агент переглядає файлову систему для завантаження лише потрібних визначень інструментів | +| **Ефективність контексту** | Дані фільтруються/трансформуються в середовищі виконання перед поверненням до моделі | +| **Потужний контроль потоку** | Цикли, умови та обробка помилок виконуються в коді без повернення через модель | +| **Збереження конфіденційності** | Проміжні дані (персональні дані, чутливі записи) залишаються в середовищі виконання; ніколи не потрапляють у контекст моделі | +| **Збереження стану** | Агенти можуть зберігати проміжні результати у файли та будувати повторно використовувані функції | + +#### Приклад: фільтрація великих наборів даних + +```typescript +// Без виконання коду — всі 10 000 рядків проходять через контекст +// TOOL CALL: gdrive.getSheet(sheetId: 'abc123') +// -> повертає 10 000 рядків у контекст + +// З виконанням коду — фільтрація в середовищі виконання +const allRows = await gdrive.getSheet({ sheetId: 'abc123' }); +const pendingOrders = allRows.filter( + row => row["Status"] === 'pending' +); +console.log(`Found ${pendingOrders.length} pending orders`); +console.log(pendingOrders.slice(0, 5)); // Лише 5 рядків потрапляють до моделі +``` + +#### Приклад: цикл без повернення через модель + +```typescript +// Опитування для сповіщення про деплой — виконується цілком у коді +let found = false; +while (!found) { + const messages = await slack.getChannelHistory({ + channel: 'C123456' + }); + found = messages.some( + m => m.text.includes('deployment complete') + ); + if (!found) await new Promise(r => setTimeout(r, 5000)); +} +console.log('Deployment notification received'); +``` + +### Компроміси + +Виконання коду додає власну складність. Запуск коду, згенерованого агентом, потребує: + +- **Безпечного ізольованого середовища виконання** з відповідними лімітами ресурсів +- **Моніторингу та логування** виконаного коду +- Додаткових **інфраструктурних витрат** порівняно з прямими викликами інструментів + +Переваги — зменшення вартості токенів, нижча затримка, покращена композиція інструментів — слід зважити проти цих витрат на впровадження. Для агентів з кількома MCP-серверами прямі виклики інструментів можуть бути простішими. Для агентів у масштабі (десятки серверів, сотні інструментів) виконання коду — значне покращення. + +### MCPorter: середовище виконання для композиції MCP-інструментів + +[MCPorter](https://github.com/steipete/mcporter) — TypeScript-середовище виконання та CLI-інструментарій для виклику MCP-серверів без шаблонного коду, що допомагає зменшити роздування контексту через вибіркове надання інструментів та типізовані обгортки. + +**Що вирішує:** замість завантаження всіх визначень інструментів з усіх MCP-серверів наперед, MCPorter дозволяє виявляти, інспектувати та викликати конкретні інструменти за потребою — тримаючи контекст компактним. + +**Ключові функції:** + +| Функція | Опис | +|---------|------| +| **Zero-config discovery** | Автовиявлення MCP-серверів з Cursor, Claude, Codex або локальних конфігурацій | +| **Типізовані клієнти інструментів** | `mcporter emit-ts` генерує `.d.ts` інтерфейси та готові обгортки | +| **Composable API** | `createServerProxy()` надає інструменти як camelCase-методи з хелперами `.text()`, `.json()`, `.markdown()` | +| **Генерація CLI** | `mcporter generate-cli` перетворює будь-який MCP-сервер у CLI з фільтрацією `--include-tools` / `--exclude-tools` | +| **Приховування параметрів** | Опціональні параметри приховані за замовчуванням, зменшуючи багатослівність схеми | + +**Встановлення:** + +```bash +npx mcporter list # Без встановлення — виявлення серверів миттєво +pnpm add mcporter # Додати до проєкту +brew install steipete/tap/mcporter # macOS через Homebrew +``` + +**Приклад — композиція інструментів у TypeScript:** + +```typescript +import { createRuntime, createServerProxy } from "mcporter"; + +const runtime = await createRuntime(); +const gdrive = createServerProxy(runtime, "google-drive"); +const salesforce = createServerProxy(runtime, "salesforce"); + +// Дані передаються між інструментами без проходження через контекст моделі +const doc = await gdrive.getDocument({ documentId: "abc123" }); +await salesforce.updateRecord({ + objectType: "SalesMeeting", + recordId: "00Q5f000001abcXYZ", + data: { Notes: doc.text() } +}); +``` + +**Приклад — виклик інструменту через CLI:** + +```bash +# Виклик конкретного інструменту +npx mcporter call linear.create_comment issueId:ENG-123 body:'Looks good!' + +# Список доступних серверів та інструментів +npx mcporter list +``` + +MCPorter доповнює підхід з виконанням коду, описаний вище, надаючи інфраструктуру для виклику MCP-інструментів як типізованих API — спрощуючи утримання проміжних даних поза контекстом моделі. + +## Найкращі практики + +### Безпекові рекомендації + +#### Рекомендовано ✅ +- Використовуйте змінні оточення для всіх облікових даних +- Регулярно ротуйте токени та API-ключі (рекомендовано щомісяця) +- Використовуйте токени лише для читання, де можливо +- Обмежуйте область доступу MCP-серверів до мінімально необхідної +- Моніторте використання MCP-серверів та журнали доступу +- Використовуйте OAuth для зовнішніх сервісів, де доступно +- Впроваджуйте rate limiting для MCP-запитів +- Тестуйте MCP-підключення перед продакшен-використанням +- Документуйте всі активні MCP-підключення +- Тримайте пакети MCP-серверів оновленими + +#### Не рекомендовано ❌ +- Не хардкодьте облікові дані в конфігураційних файлах +- Не комітьте токени чи секрети в git +- Не поширюйте токени в командних чатах чи листах +- Не використовуйте персональні токени для командних проєктів +- Не надавайте зайвих дозволів +- Не ігноруйте помилки автентифікації +- Не відкривайте MCP-ендпоінти публічно +- Не запускайте MCP-сервери з правами root/admin +- Не кешуйте чутливі дані в журналах +- Не вимикайте механізми автентифікації + +### Найкращі практики конфігурації + +1. **Контроль версій**: тримайте `.mcp.json` у git, але використовуйте змінні оточення для секретів +2. **Мінімальні привілеї**: надавайте мінімальні дозволи для кожного MCP-сервера +3. **Ізоляція**: запускайте різні MCP-сервери в окремих процесах, де можливо +4. **Моніторинг**: логуйте всі MCP-запити та помилки для аудиту +5. **Тестування**: тестуйте всі конфігурації MCP перед розгортанням у продакшен + +### Поради щодо продуктивності + +- Кешуйте часто запитувані дані на рівні додатку +- Використовуйте конкретні MCP-запити для зменшення передачі даних +- Моніторте час відповіді MCP-операцій +- Розгляньте rate limiting для зовнішніх API +- Використовуйте пакетну обробку для кількох операцій + +## Інструкції з встановлення + +### Передумови +- Node.js та npm встановлені +- Claude Code CLI встановлений +- API-токени/облікові дані для зовнішніх сервісів + +### Покрокове налаштування + +1. **Додайте перший MCP-сервер** через CLI (приклад: GitHub): +```bash +claude mcp add --transport stdio github -- npx @modelcontextprotocol/server-github +``` + + Або створіть файл `.mcp.json` у корені проєкту: +```json +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} +``` + +2. **Встановіть змінні оточення:** +```bash +export GITHUB_TOKEN="your_github_personal_access_token" +``` + +3. **Протестуйте підключення:** +```bash +claude /mcp +``` + +4. **Використовуйте MCP-інструменти:** +```bash +/mcp__github__list_prs +/mcp__github__create_issue "Title" "Description" +``` + +### Встановлення конкретних сервісів + +**GitHub MCP:** +```bash +npm install -g @modelcontextprotocol/server-github +``` + +**Database MCP:** +```bash +npm install -g @modelcontextprotocol/server-database +``` + +**Filesystem MCP:** +```bash +npm install -g @modelcontextprotocol/server-filesystem +``` + +**Slack MCP:** +```bash +npm install -g @modelcontextprotocol/server-slack +``` + +## Усунення несправностей + +### MCP-сервер не знайдено +```bash +# Перевірте, чи встановлений MCP-сервер +npm list -g @modelcontextprotocol/server-github + +# Встановіть, якщо відсутній +npm install -g @modelcontextprotocol/server-github +``` + +### Помилка автентифікації +```bash +# Перевірте, чи встановлена змінна оточення +echo $GITHUB_TOKEN + +# Перевстановіть, якщо потрібно +export GITHUB_TOKEN="your_token" + +# Перевірте дозволи токена +# Дозволи GitHub-токена: https://github.com/settings/tokens +``` + +### Таймаут з'єднання +- Перевірте мережеве з'єднання: `ping api.github.com` +- Перевірте доступність API-ендпоінта +- Перевірте rate limits API +- Спробуйте збільшити таймаут у конфігурації +- Перевірте наявність фаєрволу або проксі + +### MCP-сервер аварійно завершується +- Перевірте журнали MCP-сервера: `~/.claude/logs/` +- Перевірте, що всі змінні оточення встановлені +- Перевірте дозволи файлів +- Спробуйте перевстановити пакет MCP-сервера +- Перевірте конфліктуючі процеси на тому ж порту + +## Пов'язані концепції + +### Пам'ять vs MCP +- **Пам'ять**: зберігає постійні, незмінні дані (налаштування, контекст, історія) +- **MCP**: доступ до живих, змінюваних даних (API, бази даних, сервіси реального часу) + +### Коли використовувати кожен +- **Пам'ять** для: налаштувань користувача, історії розмов, засвоєного контексту +- **MCP** для: поточних GitHub issue, живих запитів до бази даних, даних реального часу + +### Інтеграція з іншими функціями Claude +- Комбінуйте MCP з пам'яттю для збагаченого контексту +- Використовуйте MCP-інструменти в промптах для кращого міркування +- Поєднуйте кілька MCP для складних воркфловів + +## Додаткові ресурси + +- [Офіційна документація MCP](https://code.claude.com/docs/en/mcp) +- [Специфікація протоколу MCP](https://modelcontextprotocol.io/specification) +- [GitHub-репозиторій MCP](https://github.com/modelcontextprotocol/servers) +- [Доступні MCP-сервери](https://github.com/modelcontextprotocol/servers) +- [MCPorter](https://github.com/steipete/mcporter) — TypeScript-середовище та CLI для виклику MCP-серверів +- [Code Execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp) — блог Anthropic Engineering +- [Довідник CLI Claude Code](https://code.claude.com/docs/en/cli-reference) +- [Документація Claude API](https://docs.anthropic.com) + +--- +**Останнє оновлення**: 9 квітня 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 diff --git a/uk/05-mcp/database-mcp.json b/uk/05-mcp/database-mcp.json new file mode 100644 index 0000000..eaa832a --- /dev/null +++ b/uk/05-mcp/database-mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "database": { + "command": "npx", + "args": ["@modelcontextprotocol/server-database"], + "env": { + "DATABASE_URL": "postgresql://user:pass@localhost/mydb" + } + } + } +} diff --git a/uk/05-mcp/filesystem-mcp.json b/uk/05-mcp/filesystem-mcp.json new file mode 100644 index 0000000..c76fdf6 --- /dev/null +++ b/uk/05-mcp/filesystem-mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["@modelcontextprotocol/server-filesystem", "/home/user/projects"] + } + } +} diff --git a/uk/05-mcp/github-mcp.json b/uk/05-mcp/github-mcp.json new file mode 100644 index 0000000..0f62131 --- /dev/null +++ b/uk/05-mcp/github-mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} diff --git a/uk/05-mcp/multi-mcp.json b/uk/05-mcp/multi-mcp.json new file mode 100644 index 0000000..62d8fa5 --- /dev/null +++ b/uk/05-mcp/multi-mcp.json @@ -0,0 +1,29 @@ +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + }, + "database": { + "command": "npx", + "args": ["@modelcontextprotocol/server-database"], + "env": { + "DATABASE_URL": "${DATABASE_URL}" + } + }, + "slack": { + "command": "npx", + "args": ["@modelcontextprotocol/server-slack"], + "env": { + "SLACK_TOKEN": "${SLACK_TOKEN}" + } + }, + "filesystem": { + "command": "npx", + "args": ["@modelcontextprotocol/server-filesystem", "/home/user/projects"] + } + } +} diff --git a/uk/06-hooks/context-tracker-tiktoken.py b/uk/06-hooks/context-tracker-tiktoken.py new file mode 100644 index 0000000..11786bf --- /dev/null +++ b/uk/06-hooks/context-tracker-tiktoken.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +""" +Context Usage Tracker (tiktoken version) - Tracks token consumption per request. + +Uses UserPromptSubmit as "pre-message" hook and Stop as "post-response" hook +to calculate the delta in token usage for each request. + +This version uses tiktoken with p50k_base encoding for ~90-95% accuracy. +Requires: pip install tiktoken + +For a zero-dependency version, see context-tracker.py. + +Usage: + Configure both hooks to use the same script: + - UserPromptSubmit: saves current token count + - Stop: calculates delta and reports usage +""" +import json +import os +import sys +import tempfile + +try: + import tiktoken + + TIKTOKEN_AVAILABLE = True +except ImportError: + TIKTOKEN_AVAILABLE = False + print( + "Warning: tiktoken not installed. Install with: pip install tiktoken", + file=sys.stderr, + ) + +# Configuration +CONTEXT_LIMIT = 128000 # Claude's context window (adjust for your model) + + +def get_state_file(session_id: str) -> str: + """Get temp file path for storing pre-message token count, isolated by session.""" + return os.path.join(tempfile.gettempdir(), f"claude-context-{session_id}.json") + + +def count_tokens(text: str) -> int: + """ + Count tokens using tiktoken with p50k_base encoding. + + This provides ~90-95% accuracy compared to Claude's actual tokenizer. + Falls back to character estimation if tiktoken is not available. + + Note: Anthropic hasn't released an official offline tokenizer. + tiktoken with p50k_base is a reasonable approximation since both + Claude and GPT models use BPE (byte-pair encoding). + """ + if TIKTOKEN_AVAILABLE: + enc = tiktoken.get_encoding("p50k_base") + return len(enc.encode(text)) + else: + # Fallback to character estimation (~4 chars per token) + return len(text) // 4 + + +def read_transcript(transcript_path: str) -> str: + """Read and concatenate all content from transcript file.""" + if not transcript_path or not os.path.exists(transcript_path): + return "" + + content = [] + with open(transcript_path, "r") as f: + for line in f: + try: + entry = json.loads(line.strip()) + # Extract text content from various message formats + if "message" in entry: + msg = entry["message"] + if isinstance(msg.get("content"), str): + content.append(msg["content"]) + elif isinstance(msg.get("content"), list): + for block in msg["content"]: + if isinstance(block, dict) and block.get("type") == "text": + content.append(block.get("text", "")) + except json.JSONDecodeError: + continue + + return "\n".join(content) + + +def handle_user_prompt_submit(data: dict) -> None: + """Pre-message hook: Save current token count before request.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens(transcript_content) + + # Save to temp file for later comparison + state_file = get_state_file(session_id) + with open(state_file, "w") as f: + json.dump({"pre_tokens": current_tokens}, f) + + +def handle_stop(data: dict) -> None: + """Post-response hook: Calculate and report token delta.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens(transcript_content) + + # Load pre-message count + state_file = get_state_file(session_id) + pre_tokens = 0 + if os.path.exists(state_file): + try: + with open(state_file, "r") as f: + state = json.load(f) + pre_tokens = state.get("pre_tokens", 0) + except (json.JSONDecodeError, IOError): + pass + + # Calculate delta + delta_tokens = current_tokens - pre_tokens + remaining = CONTEXT_LIMIT - current_tokens + percentage = (current_tokens / CONTEXT_LIMIT) * 100 + + # Report usage (stderr so it doesn't interfere with hook output) + method = "tiktoken" if TIKTOKEN_AVAILABLE else "estimated" + print( + f"Context ({method}): ~{current_tokens:,} tokens " + f"({percentage:.1f}% used, ~{remaining:,} remaining)", + file=sys.stderr, + ) + if delta_tokens > 0: + print(f"This request: ~{delta_tokens:,} tokens", file=sys.stderr) + + +def main(): + data = json.load(sys.stdin) + event = data.get("hook_event_name", "") + + if event == "UserPromptSubmit": + handle_user_prompt_submit(data) + elif event == "Stop": + handle_stop(data) + + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/uk/06-hooks/context-tracker.py b/uk/06-hooks/context-tracker.py new file mode 100644 index 0000000..eb5daf9 --- /dev/null +++ b/uk/06-hooks/context-tracker.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +""" +Context Usage Tracker - Tracks token consumption per request. + +Uses UserPromptSubmit as "pre-message" hook and Stop as "post-response" hook +to calculate the delta in token usage for each request. + +This version uses character-based estimation (no dependencies). +For better accuracy, see context-tracker-tiktoken.py. + +Usage: + Configure both hooks to use the same script: + - UserPromptSubmit: saves current token count + - Stop: calculates delta and reports usage +""" +import json +import os +import sys +import tempfile + +# Configuration +CONTEXT_LIMIT = 128000 # Claude's context window (adjust for your model) + + +def get_state_file(session_id: str) -> str: + """Get temp file path for storing pre-message token count, isolated by session.""" + return os.path.join(tempfile.gettempdir(), f"claude-context-{session_id}.json") + + +def count_tokens_estimate(text: str) -> int: + """ + Estimate token count using character-based approximation. + + Uses ~4 characters per token ratio, which provides ~80-90% accuracy + for English text. Less accurate for code and non-English text. + """ + return len(text) // 4 + + +def read_transcript(transcript_path: str) -> str: + """Read and concatenate all content from transcript file.""" + if not transcript_path or not os.path.exists(transcript_path): + return "" + + content = [] + with open(transcript_path, "r") as f: + for line in f: + try: + entry = json.loads(line.strip()) + # Extract text content from various message formats + if "message" in entry: + msg = entry["message"] + if isinstance(msg.get("content"), str): + content.append(msg["content"]) + elif isinstance(msg.get("content"), list): + for block in msg["content"]: + if isinstance(block, dict) and block.get("type") == "text": + content.append(block.get("text", "")) + except json.JSONDecodeError: + continue + + return "\n".join(content) + + +def handle_user_prompt_submit(data: dict) -> None: + """Pre-message hook: Save current token count before request.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens_estimate(transcript_content) + + # Save to temp file for later comparison + state_file = get_state_file(session_id) + with open(state_file, "w") as f: + json.dump({"pre_tokens": current_tokens}, f) + + +def handle_stop(data: dict) -> None: + """Post-response hook: Calculate and report token delta.""" + session_id = data.get("session_id", "unknown") + transcript_path = data.get("transcript_path", "") + + transcript_content = read_transcript(transcript_path) + current_tokens = count_tokens_estimate(transcript_content) + + # Load pre-message count + state_file = get_state_file(session_id) + pre_tokens = 0 + if os.path.exists(state_file): + try: + with open(state_file, "r") as f: + state = json.load(f) + pre_tokens = state.get("pre_tokens", 0) + except (json.JSONDecodeError, IOError): + pass + + # Calculate delta + delta_tokens = current_tokens - pre_tokens + remaining = CONTEXT_LIMIT - current_tokens + percentage = (current_tokens / CONTEXT_LIMIT) * 100 + + # Report usage (stderr so it doesn't interfere with hook output) + print( + f"Context (estimated): ~{current_tokens:,} tokens " + f"({percentage:.1f}% used, ~{remaining:,} remaining)", + file=sys.stderr, + ) + if delta_tokens > 0: + print(f"This request: ~{delta_tokens:,} tokens", file=sys.stderr) + + +def main(): + data = json.load(sys.stdin) + event = data.get("hook_event_name", "") + + if event == "UserPromptSubmit": + handle_user_prompt_submit(data) + elif event == "Stop": + handle_stop(data) + + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/uk/06-hooks/dependency-check.sh b/uk/06-hooks/dependency-check.sh new file mode 100644 index 0000000..c659b9f --- /dev/null +++ b/uk/06-hooks/dependency-check.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# Check for known vulnerabilities in dependencies after manifest files are modified. +# Hook: PostToolUse:Write + +FILE=$1 + +if [ -z "$FILE" ]; then + echo "Usage: $0 " + exit 0 +fi + +# Use basename for matching — $1 may be an absolute path +BASENAME=$(basename "$FILE") + +# Only run when a dependency manifest is written +case "$BASENAME" in + package.json|package-lock.json|yarn.lock|pnpm-lock.yaml| \ + requirements.txt|Pipfile|Pipfile.lock|pyproject.toml| \ + go.mod|go.sum| \ + Cargo.toml|Cargo.lock| \ + Gemfile|Gemfile.lock| \ + composer.json|composer.lock| \ + pom.xml|build.gradle|build.gradle.kts) + echo "📦 Dependency manifest updated: $FILE — scanning for vulnerabilities..." + ;; + *) + exit 0 + ;; +esac + +ISSUES_FOUND=0 + +# ── npm / yarn / pnpm ──────────────────────────────────────────────────────── +if [[ "$BASENAME" == package*.json || "$BASENAME" == yarn.lock || "$BASENAME" == pnpm-lock.yaml ]]; then + if command -v npm &>/dev/null; then + echo "🔍 Running npm audit..." + if ! npm audit --audit-level=high --json 2>/dev/null | \ + python3 -c " +import sys, json +data = json.load(sys.stdin) +vulns = data.get('metadata', {}).get('vulnerabilities', {}) +high = vulns.get('high', 0) + vulns.get('critical', 0) +if high: + print(f' ⚠️ {high} high/critical npm vulnerabilities found. Run: npm audit fix') + sys.exit(1) +" 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ No high/critical npm vulnerabilities" + fi + fi + + if command -v yarn &>/dev/null && [[ "$BASENAME" == yarn.lock ]]; then + echo "🔍 Running yarn audit..." + if ! yarn audit --level high --json 2>/dev/null | \ + grep -q '"type":"auditAdvisory"' 2>/dev/null; then + echo " ✅ No high yarn vulnerabilities" + else + echo " ⚠️ yarn audit found vulnerabilities. Run: yarn audit --level high" + ISSUES_FOUND=1 + fi + fi +fi + +# ── Python ─────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == requirements.txt || "$BASENAME" == Pipfile* || "$BASENAME" == pyproject.toml ]]; then + if command -v pip-audit &>/dev/null; then + echo "🔍 Running pip-audit..." + if pip-audit --format=json 2>/dev/null | \ + python3 -c " +import sys, json +data = json.load(sys.stdin) +vulns = [d for d in data.get('dependencies', []) if d.get('vulns')] +if vulns: + for dep in vulns: + for v in dep['vulns']: + print(f' ⚠️ {dep[\"name\"]} {dep[\"version\"]}: {v[\"id\"]} — {v[\"fix_versions\"]}') + sys.exit(1) +" 2>/dev/null; then + echo " ✅ No Python vulnerabilities found" + else + ISSUES_FOUND=1 + echo " Run: pip-audit for details" + fi + elif command -v safety &>/dev/null; then + echo "🔍 Running safety check..." + OUTPUT=$(safety check --short-report 2>&1) + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo " ✅ No Python vulnerabilities found" + elif echo "$OUTPUT" | grep -qiE "vulnerability|CVE|insecure"; then + echo "$OUTPUT" + ISSUES_FOUND=1 + else + echo " ⚠️ safety check could not complete (network or config error)" >&2 + fi + fi +fi + +# ── Go ─────────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == go.mod || "$BASENAME" == go.sum ]]; then + if command -v govulncheck &>/dev/null; then + echo "🔍 Running govulncheck..." + OUTPUT=$(govulncheck ./... 2>&1) + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo " ✅ No Go vulnerabilities found" + elif echo "$OUTPUT" | grep -q "Vulnerability #"; then + echo "$OUTPUT" + ISSUES_FOUND=1 + else + echo " ⚠️ govulncheck could not complete: $OUTPUT" >&2 + fi + fi +fi + +# ── Rust ───────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == Cargo.toml || "$BASENAME" == Cargo.lock ]]; then + if command -v cargo-audit &>/dev/null; then + echo "🔍 Running cargo audit..." + if ! cargo audit 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ No Rust vulnerabilities found" + fi + fi +fi + +# ── Ruby ───────────────────────────────────────────────────────────────────── +if [[ "$BASENAME" == Gemfile || "$BASENAME" == Gemfile.lock ]]; then + if command -v bundler-audit &>/dev/null; then + echo "🔍 Running bundler-audit..." + bundler-audit check --update 2>/dev/null || ISSUES_FOUND=1 + fi +fi + +# ── Generic fallback: trivy ────────────────────────────────────────────────── +if command -v trivy &>/dev/null; then + echo "🔍 Running trivy fs scan..." + if ! trivy fs --exit-code 1 --severity HIGH,CRITICAL --quiet . 2>/dev/null; then + ISSUES_FOUND=1 + else + echo " ✅ trivy found no HIGH/CRITICAL issues" + fi +fi + +if [ "$ISSUES_FOUND" -eq 0 ]; then + echo "✅ Dependency check passed — no vulnerabilities detected" +else + echo "" + echo "⚠️ Vulnerabilities detected. Review and update dependencies before committing." + echo " This hook is advisory only and will not block your workflow." +fi + +# Always exit 0 — this hook warns but does not block +exit 0 diff --git a/uk/06-hooks/format-code.sh b/uk/06-hooks/format-code.sh new file mode 100644 index 0000000..9841b9e --- /dev/null +++ b/uk/06-hooks/format-code.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Auto-format code after writing +# Hook: PostToolUse:Write +# +# Reads the target file path from stdin JSON and runs the appropriate formatter +# in-place on the file after Claude writes it. +# +# Compatible with: macOS, Linux, Windows (Git Bash) + +# Read JSON input from stdin (Claude Code hook protocol) +INPUT=$(cat) + +# Extract file_path using sed (compatible with all platforms) +FILE_PATH=$(echo "$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + +if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then + exit 0 +fi + +# Detect file type and format accordingly +case "$FILE_PATH" in + *.js|*.jsx|*.ts|*.tsx) + if command -v prettier &> /dev/null; then + prettier --write "$FILE_PATH" 2>/dev/null + fi + ;; + *.py) + if command -v black &> /dev/null; then + black "$FILE_PATH" 2>/dev/null + fi + ;; + *.go) + if command -v gofmt &> /dev/null; then + gofmt -w "$FILE_PATH" 2>/dev/null + fi + ;; + *.rs) + if command -v rustfmt &> /dev/null; then + rustfmt "$FILE_PATH" 2>/dev/null + fi + ;; + *.java) + if command -v google-java-format &> /dev/null; then + google-java-format -i "$FILE_PATH" 2>/dev/null + fi + ;; +esac + +exit 0 diff --git a/uk/06-hooks/log-bash.sh b/uk/06-hooks/log-bash.sh new file mode 100644 index 0000000..2ca16d9 --- /dev/null +++ b/uk/06-hooks/log-bash.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Log all bash commands +# Hook: PostToolUse:Bash +# +# Reads the executed command from stdin JSON and logs it to a file. +# +# Compatible with: macOS, Linux, Windows (Git Bash) + +# Read JSON input from stdin (Claude Code hook protocol) +INPUT=$(cat) + +# Extract the bash command from tool_input +# Note: sed [^"]* stops at escaped quotes in JSON; for commands with double-quoted +# strings, only the portion up to the first \" will be captured — this is a known +# limitation of sed-based JSON parsing and is acceptable for logging purposes. +COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + +if [ -z "$COMMAND" ]; then + exit 0 +fi + +TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S") +LOGFILE="$HOME/.claude/bash-commands.log" + +# Create log directory if it doesn't exist +mkdir -p "$(dirname "$LOGFILE")" + +# Log the command +echo "[$TIMESTAMP] $COMMAND" >> "$LOGFILE" + +exit 0 diff --git a/uk/06-hooks/notify-team.sh b/uk/06-hooks/notify-team.sh new file mode 100644 index 0000000..1894218 --- /dev/null +++ b/uk/06-hooks/notify-team.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Send notifications on events +# Hook: PostToolUse (matcher: Bash) — run after bash commands; filter for git push in script logic +# Note: Claude Code has no native PostPush event. To trigger on git push, check the bash command +# string for "git push" using a matcher or conditional logic within this script. + +REPO_NAME=$(basename $(git rev-parse --show-toplevel 2>/dev/null) 2>/dev/null) +COMMIT_MSG=$(git log -1 --pretty=%B 2>/dev/null) +AUTHOR=$(git log -1 --pretty=%an 2>/dev/null) +BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + +echo "📢 Sending notification to team..." + +# Slack webhook example (replace with your webhook URL) +SLACK_WEBHOOK="${SLACK_WEBHOOK_URL:-}" + +if [ -n "$SLACK_WEBHOOK" ]; then + curl -X POST "$SLACK_WEBHOOK" \ + -H 'Content-Type: application/json' \ + -d "{ + \"text\": \"New push to *$REPO_NAME*\", + \"attachments\": [{ + \"color\": \"good\", + \"fields\": [ + {\"title\": \"Branch\", \"value\": \"$BRANCH\", \"short\": true}, + {\"title\": \"Author\", \"value\": \"$AUTHOR\", \"short\": true}, + {\"title\": \"Commit\", \"value\": \"$COMMIT_MSG\"} + ] + }] + }" \ + --silent --output /dev/null + + echo "✅ Slack notification sent" +fi + +# Discord webhook example (replace with your webhook URL) +DISCORD_WEBHOOK="${DISCORD_WEBHOOK_URL:-}" + +if [ -n "$DISCORD_WEBHOOK" ]; then + curl -X POST "$DISCORD_WEBHOOK" \ + -H 'Content-Type: application/json' \ + -d "{ + \"content\": \"**New push to $REPO_NAME**\", + \"embeds\": [{ + \"title\": \"$COMMIT_MSG\", + \"color\": 3066993, + \"fields\": [ + {\"name\": \"Branch\", \"value\": \"$BRANCH\", \"inline\": true}, + {\"name\": \"Author\", \"value\": \"$AUTHOR\", \"inline\": true} + ] + }] + }" \ + --silent --output /dev/null + + echo "✅ Discord notification sent" +fi + +# Email notification example +EMAIL_TO="${TEAM_EMAIL:-}" + +if [ -n "$EMAIL_TO" ]; then + echo "New push to $REPO_NAME by $AUTHOR" | \ + mail -s "Git Push: $BRANCH" "$EMAIL_TO" + + echo "✅ Email notification sent" +fi + +exit 0 diff --git a/uk/06-hooks/pre-commit.sh b/uk/06-hooks/pre-commit.sh new file mode 100644 index 0000000..2e9b27a --- /dev/null +++ b/uk/06-hooks/pre-commit.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Run tests before commit +# Hook: PreToolUse (matcher: Bash) - checks if the command is a git commit +# Note: There is no "PreCommit" hook event. Use PreToolUse with a Bash matcher +# and inspect the command to detect git commit operations. + +echo "🧪 Running tests before commit..." + +# Check if package.json exists (Node.js project) +if [ -f "package.json" ]; then + if grep -q "\"test\":" package.json; then + npm test + if [ $? -ne 0 ]; then + echo "❌ Tests failed! Commit blocked." + exit 1 + fi + fi +fi + +# Check if pytest is available (Python project) +if [ -f "pytest.ini" ] || [ -f "setup.py" ]; then + if command -v pytest &> /dev/null; then + pytest + if [ $? -ne 0 ]; then + echo "❌ Tests failed! Commit blocked." + exit 1 + fi + fi +fi + +# Check if go.mod exists (Go project) +if [ -f "go.mod" ]; then + go test ./... + if [ $? -ne 0 ]; then + echo "❌ Tests failed! Commit blocked." + exit 1 + fi +fi + +# Check if Cargo.toml exists (Rust project) +if [ -f "Cargo.toml" ]; then + cargo test + if [ $? -ne 0 ]; then + echo "❌ Tests failed! Commit blocked." + exit 1 + fi +fi + +echo "✅ All tests passed! Proceeding with commit." +exit 0 diff --git a/uk/06-hooks/pre-tool-check.sh b/uk/06-hooks/pre-tool-check.sh new file mode 100644 index 0000000..932395e --- /dev/null +++ b/uk/06-hooks/pre-tool-check.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# Pre-tool safety check for Bash commands +# Hook: PreToolUse (matcher: Bash) +# +# This hook runs before every Bash tool execution and blocks or warns on +# potentially destructive or high-risk shell commands. +# +# Setup: +# cp 06-hooks/pre-tool-check.sh ~/.claude/hooks/ +# chmod +x ~/.claude/hooks/pre-tool-check.sh +# +# Configure in ~/.claude/settings.json: +# { +# "hooks": { +# "PreToolUse": [ +# { +# "matcher": "Bash", +# "hooks": [ +# { +# "type": "command", +# "command": "~/.claude/hooks/pre-tool-check.sh" +# } +# ] +# } +# ] +# } +# } +# +# Input: JSON via stdin with the shape: +# { "tool_name": "Bash", "tool_input": { "command": "..." } } +# +# Output: Exit 0 to allow, exit 2 to block, or print JSON to modify behavior. + +# Read the full JSON input from stdin +INPUT=$(cat) + +# Extract the command using portable sed (compatible with macOS and Linux) +COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + +# Fall back to the raw input if extraction fails +if [ -z "$COMMAND" ]; then + COMMAND="$INPUT" +fi + +# ── Blocked patterns ────────────────────────────────────────────────────────── +# These commands are blocked unconditionally because they are almost always +# destructive and rarely intentional in an automated context. + +BLOCKED_PATTERNS=( + "rm -rf /" + "rm -rf \*" + "dd if=/dev/zero" + "dd if=/dev/random" + ":(){:|:&};:" # Fork bomb + "mkfs\." # Filesystem format + "format c:" # Windows disk format +) + +for pattern in "${BLOCKED_PATTERNS[@]}"; do + if echo "$COMMAND" | grep -qE "$pattern"; then + echo "❌ Blocked: Potentially destructive command detected: $pattern" + echo " Command: $COMMAND" + exit 2 + fi +done + +# ── Warning patterns ────────────────────────────────────────────────────────── +# These patterns are risky but may be intentional. Log a warning and allow. + +WARNING_PATTERNS=( + "rm -rf" + "git push --force" + "git reset --hard" + "git clean -f" + "chmod -R 777" + "sudo rm" + "DROP TABLE" + "DROP DATABASE" + "truncate" +) + +WARNINGS=0 +for pattern in "${WARNING_PATTERNS[@]}"; do + if echo "$COMMAND" | grep -qi "$pattern"; then + echo "⚠️ Warning: High-risk operation detected: $pattern" + WARNINGS=$((WARNINGS + 1)) + fi +done + +if [ "$WARNINGS" -gt 0 ]; then + echo " Command: $COMMAND" + echo " Proceeding — review the above warnings before continuing." +fi + +# ── Allow ───────────────────────────────────────────────────────────────────── +exit 0 diff --git a/uk/06-hooks/security-scan.sh b/uk/06-hooks/security-scan.sh new file mode 100644 index 0000000..81e3a5b --- /dev/null +++ b/uk/06-hooks/security-scan.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# Security scan on file write +# Hook: PostToolUse:Write +# +# Scans files for hardcoded secrets, API keys, and credentials. +# Outputs a non-blocking warning via additionalContext when issues are found. +# +# Compatible with: macOS, Linux, Windows (Git Bash) + +# Read JSON input from stdin (Claude Code hook protocol) +INPUT=$(cat) + +# Extract file_path using sed (compatible with all platforms including Windows Git Bash) +# Avoids grep -P (not available on Windows Git Bash) and python3 dependency +FILE_PATH=$(echo "$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + +if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then + exit 0 +fi + +# Skip binary files, vendor dirs, and build artifacts +case "$FILE_PATH" in + *.png|*.jpg|*.jpeg|*.gif|*.svg|*.ico|*.woff|*.woff2|*.ttf|*.eot) exit 0 ;; + */node_modules/*|*/.git/*|*/dist/*|*/build/*) exit 0 ;; +esac + +ISSUES="" + +# Check for hardcoded passwords +# Handles both JSON format ("password": "value") and code format (password = 'value') +# Use \\n as separator — it is a valid JSON newline escape and passes through printf safely +if grep -qiE '"password"[[:space:]]*:[[:space:]]*"[^"]+"' "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n" +elif grep -qiE '(password|passwd|pwd)[[:space:]]*=[[:space:]]*'"'"'[^'"'"']+'"'"'' "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n" +fi + +# Check for hardcoded API keys +if grep -qiE '"(api[_-]?key|apikey|access[_-]?token)"[[:space:]]*:[[:space:]]*"[^"]+"' "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Potential hardcoded API key detected\\n" +fi + +# Check for hardcoded secrets and tokens +if grep -qiE '(secret|token)[[:space:]]*=[[:space:]]*['"'"'"][^'"'"'"]+['"'"'"]' "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Potential hardcoded secret or token detected\\n" +fi + +# Check for private keys +if grep -q "BEGIN.*PRIVATE KEY" "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: Private key detected\\n" +fi + +# Check for AWS keys +if grep -qE "AKIA[0-9A-Z]{16}" "$FILE_PATH" 2>/dev/null; then + ISSUES="${ISSUES}- WARNING: AWS access key detected\\n" +fi + +# Scan with semgrep if available (stdout suppressed to avoid mixing with JSON output) +if command -v semgrep &> /dev/null; then + semgrep --config=auto "$FILE_PATH" --quiet >/dev/null 2>/dev/null +fi + +# Scan with trufflehog if available (stdout suppressed to avoid mixing with JSON output) +if command -v trufflehog &> /dev/null; then + trufflehog filesystem "$FILE_PATH" --only-verified --quiet >/dev/null 2>/dev/null +fi + +# If issues found, output as additionalContext (non-blocking warning) +# Use hookSpecificOutput format required by Claude Code PostToolUse protocol +if [ -n "$ISSUES" ]; then + # Escape file path for JSON (backslash and double-quote) + # ISSUES already uses \\n as separator (valid JSON escape) — only escape double-quotes + SAFE_PATH=$(printf '%s' "$FILE_PATH" | sed 's/\\/\\\\/g; s/"/\\"/g') + SAFE_ISSUES=$(printf '%s' "$ISSUES" | sed 's/"/\\"/g') + printf '{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Security scan found issues in %s:\\n%sPlease review and use environment variables instead."}}' "$SAFE_PATH" "$SAFE_ISSUES" +fi + +exit 0 diff --git a/uk/06-hooks/validate-prompt.sh b/uk/06-hooks/validate-prompt.sh new file mode 100644 index 0000000..b2701f3 --- /dev/null +++ b/uk/06-hooks/validate-prompt.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Validate user prompts +# Hook: UserPromptSubmit +# +# Reads the user prompt from stdin JSON and blocks dangerous operations. +# +# Compatible with: macOS, Linux, Windows (Git Bash) + +# Read JSON input from stdin (Claude Code hook protocol) +INPUT=$(cat) + +# Extract the prompt text from JSON input +# Claude Code sends UserPromptSubmit with field "user_prompt" (falls back to "prompt") +PROMPT=$(echo "$INPUT" | sed -n 's/.*"user_prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) +if [ -z "$PROMPT" ]; then + PROMPT=$(echo "$INPUT" | sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) +fi + +if [ -z "$PROMPT" ]; then + exit 0 +fi + +# Check for dangerous operations +DANGEROUS_PATTERNS=( + "rm -rf /" + "delete database" + "drop database" + "format disk" + "dd if=" +) + +for pattern in "${DANGEROUS_PATTERNS[@]}"; do + if echo "$PROMPT" | grep -qi "$pattern"; then + printf '{"decision": "block", "reason": "Dangerous operation detected: %s"}' "$pattern" + exit 0 + fi +done + +# Check for production deployments +if echo "$PROMPT" | grep -qiE "(deploy|push).*production"; then + if [ ! -f ".deployment-approved" ]; then + echo '{"decision": "block", "reason": "Production deployment requires approval. Create .deployment-approved file to proceed."}' + exit 0 + fi +fi + +# Check for required context in certain operations +if echo "$PROMPT" | grep -qi "refactor"; then + if [ ! -d "tests" ] && [ ! -d "test" ]; then + printf '{"additionalContext": "Warning: Refactoring without tests may be risky. Consider writing tests first."}' + fi +fi + +exit 0 diff --git a/uk/07-plugins/devops-automation/.claude-plugin/plugin.json b/uk/07-plugins/devops-automation/.claude-plugin/plugin.json new file mode 100644 index 0000000..3b7bf75 --- /dev/null +++ b/uk/07-plugins/devops-automation/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "devops-automation", + "version": "1.0.0", + "description": "Complete DevOps automation for deployment, monitoring, and incident response", + "author": { + "name": "Community" + }, + "license": "MIT" +} diff --git a/uk/07-plugins/devops-automation/README.md b/uk/07-plugins/devops-automation/README.md new file mode 100644 index 0000000..d0226bd --- /dev/null +++ b/uk/07-plugins/devops-automation/README.md @@ -0,0 +1,107 @@ + + + Claude How To + + +# DevOps Automation Plugin + +Complete DevOps automation for deployment, monitoring, and incident response. + +## Features + +✅ Automated deployments +✅ Rollback procedures +✅ System health monitoring +✅ Incident response workflows +✅ Kubernetes integration + +## Installation + +```bash +/plugin install devops-automation +``` + +## What's Included + +### Slash Commands +- `/deploy` - Deploy to production or staging +- `/rollback` - Rollback to previous version +- `/status` - Check system health +- `/incident` - Handle production incidents + +### Subagents +- `deployment-specialist` - Deployment operations +- `incident-commander` - Incident coordination +- `alert-analyzer` - System health analysis + +### MCP Servers +- Kubernetes integration + +### Scripts +- `deploy.sh` - Deployment automation +- `rollback.sh` - Rollback automation +- `health-check.sh` - Health check utilities + +### Hooks +- `pre-deploy.js` - Pre-deployment validation +- `post-deploy.js` - Post-deployment tasks + +## Usage + +### Deploy to Staging +``` +/deploy staging +``` + +### Deploy to Production +``` +/deploy production +``` + +### Rollback +``` +/rollback production +``` + +### Check Status +``` +/status +``` + +### Handle Incident +``` +/incident +``` + +## Requirements + +- Claude Code 1.0+ +- Kubernetes CLI (kubectl) +- Cluster access configured + +## Configuration + +Set up your Kubernetes config: +```bash +export KUBECONFIG=~/.kube/config +``` + +## Example Workflow + +``` +User: /deploy production + +Claude: +1. Runs pre-deploy hook (validates kubectl, cluster connection) +2. Delegates to deployment-specialist subagent +3. Runs deploy.sh script +4. Monitors deployment progress via Kubernetes MCP +5. Runs post-deploy hook (waits for pods, smoke tests) +6. Provides deployment summary + +Result: +✅ Deployment complete +📦 Version: v2.1.0 +🚀 Pods: 3/3 ready +⏱️ Time: 2m 34s +``` diff --git a/uk/07-plugins/devops-automation/agents/alert-analyzer.md b/uk/07-plugins/devops-automation/agents/alert-analyzer.md new file mode 100644 index 0000000..d455e24 --- /dev/null +++ b/uk/07-plugins/devops-automation/agents/alert-analyzer.md @@ -0,0 +1,14 @@ +--- +name: alert-analyzer +description: Analyzes monitoring alerts and system metrics +tools: read, grep, bash +--- + +# Alert Analyzer + +Analyzes system health and alerts: +- Alert correlation +- Trend analysis +- Root cause identification +- Metric visualization +- Proactive issue detection diff --git a/uk/07-plugins/devops-automation/agents/deployment-specialist.md b/uk/07-plugins/devops-automation/agents/deployment-specialist.md new file mode 100644 index 0000000..47fe3f7 --- /dev/null +++ b/uk/07-plugins/devops-automation/agents/deployment-specialist.md @@ -0,0 +1,14 @@ +--- +name: deployment-specialist +description: Handles all deployment operations +tools: read, write, bash, grep +--- + +# Deployment Specialist + +Expert in deployment operations: +- Blue-green deployments +- Canary releases +- Rollback procedures +- Health checks +- Database migrations diff --git a/uk/07-plugins/devops-automation/agents/incident-commander.md b/uk/07-plugins/devops-automation/agents/incident-commander.md new file mode 100644 index 0000000..d73929c --- /dev/null +++ b/uk/07-plugins/devops-automation/agents/incident-commander.md @@ -0,0 +1,14 @@ +--- +name: incident-commander +description: Coordinates incident response +tools: read, write, bash, grep +--- + +# Incident Commander + +Manages incident response: +- Severity assessment +- Team coordination +- Status updates +- Resolution tracking +- Post-mortem facilitation diff --git a/uk/07-plugins/devops-automation/commands/deploy.md b/uk/07-plugins/devops-automation/commands/deploy.md new file mode 100644 index 0000000..4873ca3 --- /dev/null +++ b/uk/07-plugins/devops-automation/commands/deploy.md @@ -0,0 +1,15 @@ +--- +name: Deploy +description: Deploy application to production or staging +--- + +# Deploy Application + +Execute deployment workflow: + +1. Run pre-deployment checks +2. Build application +3. Run tests +4. Deploy to target environment +5. Run health checks +6. Notify team on Slack diff --git a/uk/07-plugins/devops-automation/commands/incident.md b/uk/07-plugins/devops-automation/commands/incident.md new file mode 100644 index 0000000..b5c0459 --- /dev/null +++ b/uk/07-plugins/devops-automation/commands/incident.md @@ -0,0 +1,16 @@ +--- +name: Incident Response +description: Handle production incidents with structured response +--- + +# Incident Response + +Structured incident response workflow: + +1. Create incident record +2. Assess severity and impact +3. Notify on-call team +4. Gather diagnostic information +5. Coordinate response efforts +6. Document resolution +7. Schedule post-mortem diff --git a/uk/07-plugins/devops-automation/commands/rollback.md b/uk/07-plugins/devops-automation/commands/rollback.md new file mode 100644 index 0000000..2eb20a3 --- /dev/null +++ b/uk/07-plugins/devops-automation/commands/rollback.md @@ -0,0 +1,14 @@ +--- +name: Rollback +description: Rollback to previous deployment +--- + +# Rollback Deployment + +Rollback to previous stable version: + +1. Identify previous deployment +2. Verify rollback target is healthy +3. Execute rollback procedure +4. Run health checks +5. Notify team diff --git a/uk/07-plugins/devops-automation/commands/status.md b/uk/07-plugins/devops-automation/commands/status.md new file mode 100644 index 0000000..6c2e670 --- /dev/null +++ b/uk/07-plugins/devops-automation/commands/status.md @@ -0,0 +1,15 @@ +--- +name: System Status +description: Check overall system health and status +--- + +# System Status Check + +Check system health across all services: + +1. Query Kubernetes pod status +2. Check database connections +3. Monitor API response times +4. Review error rates +5. Check resource utilization +6. Report overall health diff --git a/uk/07-plugins/devops-automation/hooks/post-deploy.js b/uk/07-plugins/devops-automation/hooks/post-deploy.js new file mode 100644 index 0000000..5c6537e --- /dev/null +++ b/uk/07-plugins/devops-automation/hooks/post-deploy.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node + +/** + * Post-deployment hook + * Runs after deployment completes + */ + +async function postDeploy() { + console.log('Running post-deployment tasks...'); + + const { execSync } = require('child_process'); + + // Wait for pods to be ready + console.log('Waiting for pods to be ready...'); + try { + execSync('kubectl wait --for=condition=ready pod -l app=myapp --timeout=300s', { + stdio: 'inherit' + }); + } catch (error) { + console.error('❌ Pods failed to become ready'); + process.exit(1); + } + + // Run smoke tests + console.log('Running smoke tests...'); + // Add your smoke test commands here + + console.log('✅ Post-deployment tasks complete'); +} + +postDeploy().catch(error => { + console.error('Post-deploy hook failed:', error); + process.exit(1); +}); diff --git a/uk/07-plugins/devops-automation/hooks/pre-deploy.js b/uk/07-plugins/devops-automation/hooks/pre-deploy.js new file mode 100644 index 0000000..98983a4 --- /dev/null +++ b/uk/07-plugins/devops-automation/hooks/pre-deploy.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node + +/** + * Pre-deployment hook + * Validates environment and prerequisites before deployment + */ + +async function preDeploy() { + console.log('Running pre-deployment checks...'); + + const { execSync } = require('child_process'); + + // Check if kubectl is installed + try { + execSync('which kubectl', { stdio: 'pipe' }); + } catch (error) { + console.error('❌ kubectl not found. Please install Kubernetes CLI.'); + process.exit(1); + } + + // Check if connected to cluster + try { + execSync('kubectl cluster-info', { stdio: 'pipe' }); + } catch (error) { + console.error('❌ Not connected to Kubernetes cluster'); + process.exit(1); + } + + console.log('✅ Pre-deployment checks passed'); +} + +preDeploy().catch(error => { + console.error('Pre-deploy hook failed:', error); + process.exit(1); +}); diff --git a/uk/07-plugins/devops-automation/mcp/kubernetes-config.json b/uk/07-plugins/devops-automation/mcp/kubernetes-config.json new file mode 100644 index 0000000..3f3b842 --- /dev/null +++ b/uk/07-plugins/devops-automation/mcp/kubernetes-config.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "kubernetes": { + "command": "npx", + "args": ["@modelcontextprotocol/server-kubernetes"], + "env": { + "KUBECONFIG": "${KUBECONFIG}" + } + } + } +} diff --git a/uk/07-plugins/devops-automation/scripts/deploy.sh b/uk/07-plugins/devops-automation/scripts/deploy.sh new file mode 100644 index 0000000..9acf5bd --- /dev/null +++ b/uk/07-plugins/devops-automation/scripts/deploy.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +echo "🚀 Starting deployment..." + +# Load environment +ENV=${1:-staging} +echo "📦 Target environment: $ENV" + +# Pre-deployment checks +echo "✓ Running pre-deployment checks..." +npm run lint +npm test + +# Build +echo "🔨 Building application..." +npm run build + +# Deploy +echo "🚢 Deploying to $ENV..." +kubectl apply -f k8s/$ENV/ + +# Health check +echo "🏥 Running health checks..." +sleep 10 +curl -f http://api.$ENV.example.com/health + +echo "✅ Deployment complete!" diff --git a/uk/07-plugins/devops-automation/scripts/health-check.sh b/uk/07-plugins/devops-automation/scripts/health-check.sh new file mode 100644 index 0000000..2ded117 --- /dev/null +++ b/uk/07-plugins/devops-automation/scripts/health-check.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +echo "🏥 System Health Check" +echo "====================" + +ENV=${1:-production} + +# Check API +echo -n "API: " +if curl -sf http://api.$ENV.example.com/health > /dev/null; then + echo "✅ Healthy" +else + echo "❌ Unhealthy" +fi + +# Check Database +echo -n "Database: " +if pg_isready -h db.$ENV.example.com > /dev/null 2>&1; then + echo "✅ Healthy" +else + echo "❌ Unhealthy" +fi + +# Check Pods +echo -n "Kubernetes Pods: " +PODS_READY=$(kubectl get pods -n $ENV --no-headers | grep "Running" | wc -l) +PODS_TOTAL=$(kubectl get pods -n $ENV --no-headers | wc -l) +echo "$PODS_READY/$PODS_TOTAL ready" + +echo "====================" diff --git a/uk/07-plugins/devops-automation/scripts/rollback.sh b/uk/07-plugins/devops-automation/scripts/rollback.sh new file mode 100644 index 0000000..0fe0cc2 --- /dev/null +++ b/uk/07-plugins/devops-automation/scripts/rollback.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e + +echo "⏪ Starting rollback..." + +ENV=${1:-staging} +echo "📦 Target environment: $ENV" + +# Get previous deployment +PREVIOUS=$(kubectl rollout history deployment/app -n $ENV | tail -2 | head -1 | awk '{print $1}') +echo "🔄 Rolling back to revision: $PREVIOUS" + +# Execute rollback +kubectl rollout undo deployment/app -n $ENV + +# Wait for rollback +echo "⏳ Waiting for rollback to complete..." +kubectl rollout status deployment/app -n $ENV + +# Health check +echo "🏥 Running health checks..." +sleep 5 +curl -f http://api.$ENV.example.com/health + +echo "✅ Rollback complete!" diff --git a/uk/07-plugins/documentation/.claude-plugin/plugin.json b/uk/07-plugins/documentation/.claude-plugin/plugin.json new file mode 100644 index 0000000..b1d520d --- /dev/null +++ b/uk/07-plugins/documentation/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "documentation", + "version": "1.0.0", + "description": "Comprehensive documentation generation and maintenance", + "author": { + "name": "Community" + }, + "license": "MIT" +} diff --git a/uk/07-plugins/documentation/README.md b/uk/07-plugins/documentation/README.md new file mode 100644 index 0000000..0934147 --- /dev/null +++ b/uk/07-plugins/documentation/README.md @@ -0,0 +1,119 @@ + + + Claude How To + + +# Documentation Plugin + +Comprehensive documentation generation and maintenance for your project. + +## Features + +✅ API documentation generation +✅ README creation and updates +✅ Documentation synchronization +✅ Code comment improvements +✅ Example generation + +## Installation + +```bash +/plugin install documentation +``` + +## What's Included + +### Slash Commands +- `/generate-api-docs` - Generate API documentation +- `/generate-readme` - Create or update README +- `/sync-docs` - Sync docs with code changes +- `/validate-docs` - Validate documentation + +### Subagents +- `api-documenter` - API documentation specialist +- `code-commentator` - Code comment improvements +- `example-generator` - Code example creation + +### Templates +- `api-endpoint.md` - API endpoint documentation template +- `function-docs.md` - Function documentation template +- `adr-template.md` - Architecture Decision Record template + +### MCP Servers +- GitHub integration for documentation syncing + +## Usage + +### Generate API Documentation +``` +/generate-api-docs +``` + +### Create README +``` +/generate-readme +``` + +### Sync Documentation +``` +/sync-docs +``` + +### Validate Documentation +``` +/validate-docs +``` + +## Requirements + +- Claude Code 1.0+ +- GitHub access (optional) + +## Example Workflow + +``` +User: /generate-api-docs + +Claude: +1. Scans all API endpoints in /src/api/ +2. Delegates to api-documenter subagent +3. Extracts function signatures and JSDoc +4. Organizes by module/endpoint +5. Uses api-endpoint.md template +6. Generates comprehensive markdown docs +7. Includes curl, JavaScript, and Python examples + +Result: +✅ API documentation generated +📄 Files created: + - docs/api/users.md + - docs/api/auth.md + - docs/api/products.md +📊 Coverage: 23/23 endpoints documented +``` + +## Templates Usage + +### API Endpoint Template +Use for documenting REST API endpoints with full examples. + +### Function Documentation Template +Use for documenting individual functions/methods. + +### ADR Template +Use for documenting architectural decisions. + +## Configuration + +Set up GitHub token for documentation syncing: +```bash +export GITHUB_TOKEN="your_github_token" +``` + +## Best Practices + +- Keep documentation close to code +- Update docs with code changes +- Include practical examples +- Validate regularly +- Use templates for consistency diff --git a/uk/07-plugins/documentation/agents/api-documenter.md b/uk/07-plugins/documentation/agents/api-documenter.md new file mode 100644 index 0000000..487c5a4 --- /dev/null +++ b/uk/07-plugins/documentation/agents/api-documenter.md @@ -0,0 +1,14 @@ +--- +name: api-documenter +description: API documentation specialist +tools: read, write, grep +--- + +# API Documenter + +Creates comprehensive API documentation: +- Endpoint documentation +- Parameter descriptions +- Response schemas +- Code examples (curl, JS, Python) +- Error codes diff --git a/uk/07-plugins/documentation/agents/code-commentator.md b/uk/07-plugins/documentation/agents/code-commentator.md new file mode 100644 index 0000000..a039443 --- /dev/null +++ b/uk/07-plugins/documentation/agents/code-commentator.md @@ -0,0 +1,14 @@ +--- +name: code-commentator +description: Code comment and inline documentation specialist +tools: read, write, edit +--- + +# Code Commentator + +Improves code documentation: +- JSDoc/docstring comments +- Inline explanations +- Parameter descriptions +- Return type documentation +- Usage examples diff --git a/uk/07-plugins/documentation/agents/example-generator.md b/uk/07-plugins/documentation/agents/example-generator.md new file mode 100644 index 0000000..1cd1c7e --- /dev/null +++ b/uk/07-plugins/documentation/agents/example-generator.md @@ -0,0 +1,14 @@ +--- +name: example-generator +description: Code example and tutorial specialist +tools: read, write +--- + +# Example Generator + +Creates practical code examples: +- Getting started guides +- Common use cases +- Integration examples +- Best practices +- Troubleshooting scenarios diff --git a/uk/07-plugins/documentation/commands/generate-api-docs.md b/uk/07-plugins/documentation/commands/generate-api-docs.md new file mode 100644 index 0000000..a5bda46 --- /dev/null +++ b/uk/07-plugins/documentation/commands/generate-api-docs.md @@ -0,0 +1,15 @@ +--- +name: Generate API Documentation +description: Generate comprehensive API documentation from source code +--- + +# API Documentation Generator + +Generate complete API documentation: + +1. Scan API endpoints +2. Extract function signatures and JSDoc +3. Organize by module/endpoint +4. Create markdown with examples +5. Include request/response schemas +6. Add error documentation diff --git a/uk/07-plugins/documentation/commands/generate-readme.md b/uk/07-plugins/documentation/commands/generate-readme.md new file mode 100644 index 0000000..119310a --- /dev/null +++ b/uk/07-plugins/documentation/commands/generate-readme.md @@ -0,0 +1,15 @@ +--- +name: Generate README +description: Create or update project README +--- + +# README Generator + +Generate comprehensive README: + +1. Project overview and description +2. Installation instructions +3. Usage examples +4. API documentation links +5. Contributing guidelines +6. License information diff --git a/uk/07-plugins/documentation/commands/sync-docs.md b/uk/07-plugins/documentation/commands/sync-docs.md new file mode 100644 index 0000000..9681cc8 --- /dev/null +++ b/uk/07-plugins/documentation/commands/sync-docs.md @@ -0,0 +1,14 @@ +--- +name: Sync Documentation +description: Sync documentation with code changes +--- + +# Documentation Sync + +Synchronize documentation with codebase: + +1. Detect code changes +2. Identify outdated documentation +3. Update affected docs +4. Verify examples still work +5. Update version numbers diff --git a/uk/07-plugins/documentation/commands/validate-docs.md b/uk/07-plugins/documentation/commands/validate-docs.md new file mode 100644 index 0000000..bd41f57 --- /dev/null +++ b/uk/07-plugins/documentation/commands/validate-docs.md @@ -0,0 +1,14 @@ +--- +name: Validate Documentation +description: Validate documentation for completeness and accuracy +--- + +# Documentation Validation + +Validate documentation quality: + +1. Check for broken links +2. Verify code examples +3. Ensure completeness +4. Check formatting +5. Validate against actual code diff --git a/uk/07-plugins/documentation/mcp/github-docs-config.json b/uk/07-plugins/documentation/mcp/github-docs-config.json new file mode 100644 index 0000000..0f62131 --- /dev/null +++ b/uk/07-plugins/documentation/mcp/github-docs-config.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} diff --git a/uk/07-plugins/documentation/templates/adr-template.md b/uk/07-plugins/documentation/templates/adr-template.md new file mode 100644 index 0000000..8cc3fc3 --- /dev/null +++ b/uk/07-plugins/documentation/templates/adr-template.md @@ -0,0 +1,39 @@ +# ADR [Number]: [Title] + +## Status +[Proposed | Accepted | Deprecated | Superseded] + +## Context +What is the issue that we're seeing that is motivating this decision or change? + +## Decision +What is the change that we're proposing and/or doing? + +## Consequences +What becomes easier or more difficult to do because of this change? + +### Positive +- Benefit 1 +- Benefit 2 + +### Negative +- Drawback 1 +- Drawback 2 + +### Neutral +- Consideration 1 +- Consideration 2 + +## Alternatives Considered +What other options were considered and why were they not chosen? + +### Alternative 1 +Description and reason for not choosing. + +### Alternative 2 +Description and reason for not choosing. + +## References +- Related ADRs +- External documentation +- Discussion links diff --git a/uk/07-plugins/documentation/templates/api-endpoint.md b/uk/07-plugins/documentation/templates/api-endpoint.md new file mode 100644 index 0000000..33c3996 --- /dev/null +++ b/uk/07-plugins/documentation/templates/api-endpoint.md @@ -0,0 +1,101 @@ +# [METHOD] /api/v1/[endpoint] + +## Description +Brief explanation of what this endpoint does. + +## Authentication +Required authentication method (e.g., Bearer token). + +## Parameters + +### Path Parameters +| Name | Type | Required | Description | +|------|------|----------|-------------| +| id | string | Yes | Resource ID | + +### Query Parameters +| Name | Type | Required | Description | +|------|------|----------|-------------| +| page | integer | No | Page number (default: 1) | +| limit | integer | No | Items per page (default: 20) | + +### Request Body +```json +{ + "field": "value" +} +``` + +## Responses + +### 200 OK +```json +{ + "success": true, + "data": { + "id": "123", + "name": "Example" + } +} +``` + +### 400 Bad Request +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "Invalid input" + } +} +``` + +### 404 Not Found +```json +{ + "success": false, + "error": { + "code": "NOT_FOUND", + "message": "Resource not found" + } +} +``` + +## Examples + +### cURL +```bash +curl -X GET "https://api.example.com/api/v1/endpoint" \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" +``` + +### JavaScript +```javascript +const response = await fetch('/api/v1/endpoint', { + headers: { + 'Authorization': 'Bearer token', + 'Content-Type': 'application/json' + } +}); +const data = await response.json(); +``` + +### Python +```python +import requests + +response = requests.get( + 'https://api.example.com/api/v1/endpoint', + headers={'Authorization': 'Bearer token'} +) +data = response.json() +``` + +## Rate Limits +- 1000 requests per hour for authenticated users +- 100 requests per hour for public endpoints + +## Related Endpoints +- [GET /api/v1/related](#) +- [POST /api/v1/related](#) diff --git a/uk/07-plugins/documentation/templates/function-docs.md b/uk/07-plugins/documentation/templates/function-docs.md new file mode 100644 index 0000000..b1e137d --- /dev/null +++ b/uk/07-plugins/documentation/templates/function-docs.md @@ -0,0 +1,50 @@ +# Function: `functionName` + +## Description +Brief description of what the function does. + +## Signature +```typescript +function functionName(param1: Type1, param2: Type2): ReturnType +``` + +## Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| param1 | Type1 | Yes | Description of param1 | +| param2 | Type2 | No | Description of param2 | + +## Returns +**Type**: `ReturnType` + +Description of what is returned. + +## Throws +- `Error`: When invalid input is provided +- `TypeError`: When wrong type is passed + +## Examples + +### Basic Usage +```typescript +const result = functionName('value1', 'value2'); +console.log(result); +``` + +### Advanced Usage +```typescript +const result = functionName( + complexParam1, + { option: true } +); +``` + +## Notes +- Additional notes or warnings +- Performance considerations +- Best practices + +## See Also +- [Related Function](#) +- [API Documentation](#) diff --git a/uk/07-plugins/pr-review/.claude-plugin/plugin.json b/uk/07-plugins/pr-review/.claude-plugin/plugin.json new file mode 100644 index 0000000..9e953c4 --- /dev/null +++ b/uk/07-plugins/pr-review/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "pr-review", + "version": "1.0.0", + "description": "Complete PR review workflow with security, testing, and docs", + "author": { + "name": "Anthropic" + }, + "license": "MIT" +} diff --git a/uk/07-plugins/pr-review/README.md b/uk/07-plugins/pr-review/README.md new file mode 100644 index 0000000..9fe1c3b --- /dev/null +++ b/uk/07-plugins/pr-review/README.md @@ -0,0 +1,91 @@ + + + Claude How To + + +# PR Review Plugin + +Complete PR review workflow with security, testing, and documentation checks. + +## Features + +✅ Security analysis +✅ Test coverage checking +✅ Documentation verification +✅ Code quality assessment +✅ Performance impact analysis + +## Installation + +```bash +/plugin install pr-review +``` + +## What's Included + +### Slash Commands +- `/review-pr` - Comprehensive PR review +- `/check-security` - Security-focused review +- `/check-tests` - Test coverage analysis + +### Subagents +- `security-reviewer` - Security vulnerability detection +- `test-checker` - Test coverage analysis +- `performance-analyzer` - Performance impact evaluation + +### MCP Servers +- GitHub integration for PR data + +### Hooks +- `pre-review.js` - Pre-review validation + +## Usage + +### Basic PR Review +``` +/review-pr +``` + +### Security Check Only +``` +/check-security +``` + +### Test Coverage Check +``` +/check-tests +``` + +## Requirements + +- Claude Code 1.0+ +- GitHub access +- Git repository + +## Configuration + +Set up your GitHub token: +```bash +export GITHUB_TOKEN="your_github_token" +``` + +## Example Workflow + +``` +User: /review-pr + +Claude: +1. Runs pre-review hook (validates git repo) +2. Fetches PR data via GitHub MCP +3. Delegates security review to security-reviewer subagent +4. Delegates testing to test-checker subagent +5. Delegates performance to performance-analyzer subagent +6. Synthesizes all findings +7. Provides comprehensive review report + +Result: +✅ Security: No critical issues found +⚠️ Testing: Coverage is 65%, recommend 80%+ +✅ Performance: No significant impact +📝 Recommendations: Add tests for edge cases +``` diff --git a/uk/07-plugins/pr-review/agents/performance-analyzer.md b/uk/07-plugins/pr-review/agents/performance-analyzer.md new file mode 100644 index 0000000..2f70938 --- /dev/null +++ b/uk/07-plugins/pr-review/agents/performance-analyzer.md @@ -0,0 +1,13 @@ +--- +name: performance-analyzer +description: Performance impact analysis +tools: read, grep, bash +--- + +# Performance Analyzer + +Evaluates performance impact of changes: +- Algorithm complexity +- Database query efficiency +- Memory usage +- Caching opportunities diff --git a/uk/07-plugins/pr-review/agents/security-reviewer.md b/uk/07-plugins/pr-review/agents/security-reviewer.md new file mode 100644 index 0000000..b5b2a16 --- /dev/null +++ b/uk/07-plugins/pr-review/agents/security-reviewer.md @@ -0,0 +1,13 @@ +--- +name: security-reviewer +description: Security-focused code review +tools: read, grep, diff +--- + +# Security Reviewer + +Specializes in finding security vulnerabilities: +- Authentication/authorization issues +- Data exposure +- Injection attacks +- Secure configuration diff --git a/uk/07-plugins/pr-review/agents/test-checker.md b/uk/07-plugins/pr-review/agents/test-checker.md new file mode 100644 index 0000000..90a065d --- /dev/null +++ b/uk/07-plugins/pr-review/agents/test-checker.md @@ -0,0 +1,13 @@ +--- +name: test-checker +description: Test coverage and quality analysis +tools: read, bash, grep +--- + +# Test Checker + +Analyzes test coverage and quality: +- Coverage percentage +- Missing test cases +- Test quality assessment +- Edge case identification diff --git a/uk/07-plugins/pr-review/commands/check-security.md b/uk/07-plugins/pr-review/commands/check-security.md new file mode 100644 index 0000000..58d5a68 --- /dev/null +++ b/uk/07-plugins/pr-review/commands/check-security.md @@ -0,0 +1,14 @@ +--- +name: Security Check +description: Run security-focused code review +--- + +# Security Check + +Perform focused security analysis on code changes: + +1. Authentication/authorization checks +2. Data exposure risks +3. Injection vulnerabilities +4. Cryptographic weaknesses +5. Sensitive data in logs diff --git a/uk/07-plugins/pr-review/commands/check-tests.md b/uk/07-plugins/pr-review/commands/check-tests.md new file mode 100644 index 0000000..6674562 --- /dev/null +++ b/uk/07-plugins/pr-review/commands/check-tests.md @@ -0,0 +1,14 @@ +--- +name: Test Coverage Check +description: Verify test coverage and quality +--- + +# Test Coverage Check + +Analyze test coverage and quality: + +1. Check test coverage percentage +2. Identify untested code paths +3. Review test quality +4. Suggest missing test cases +5. Verify edge cases are covered diff --git a/uk/07-plugins/pr-review/commands/review-pr.md b/uk/07-plugins/pr-review/commands/review-pr.md new file mode 100644 index 0000000..0078be3 --- /dev/null +++ b/uk/07-plugins/pr-review/commands/review-pr.md @@ -0,0 +1,14 @@ +--- +name: Review PR +description: Start comprehensive PR review with security and testing checks +--- + +# PR Review + +This command initiates a complete pull request review including: + +1. Security analysis +2. Test coverage verification +3. Documentation updates +4. Code quality checks +5. Performance impact assessment diff --git a/uk/07-plugins/pr-review/hooks/pre-review.js b/uk/07-plugins/pr-review/hooks/pre-review.js new file mode 100644 index 0000000..2127709 --- /dev/null +++ b/uk/07-plugins/pr-review/hooks/pre-review.js @@ -0,0 +1,37 @@ +#!/usr/bin/env node + +/** + * Pre-review hook + * Runs before starting PR review to ensure prerequisites are met + */ + +async function preReview() { + console.log('Running pre-review checks...'); + + // Check if git repository + const { execSync } = require('child_process'); + try { + execSync('git rev-parse --git-dir', { stdio: 'pipe' }); + } catch (error) { + console.error('❌ Not a git repository'); + process.exit(1); + } + + // Check for uncommitted changes + try { + const status = execSync('git status --porcelain', { encoding: 'utf-8' }); + if (status.trim()) { + console.warn('⚠️ Warning: Uncommitted changes detected'); + } + } catch (error) { + console.error('❌ Failed to check git status'); + process.exit(1); + } + + console.log('✅ Pre-review checks passed'); +} + +preReview().catch(error => { + console.error('Pre-review hook failed:', error); + process.exit(1); +}); diff --git a/uk/07-plugins/pr-review/mcp/github-config.json b/uk/07-plugins/pr-review/mcp/github-config.json new file mode 100644 index 0000000..0f62131 --- /dev/null +++ b/uk/07-plugins/pr-review/mcp/github-config.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} diff --git a/uk/09-advanced-features/config-examples.json b/uk/09-advanced-features/config-examples.json new file mode 100644 index 0000000..a67f08c --- /dev/null +++ b/uk/09-advanced-features/config-examples.json @@ -0,0 +1,267 @@ +{ + "description": "Example Claude Code configurations for different use cases", + + "examples": { + "development": { + "name": "Development Environment", + "description": "Configuration for active development work", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.7 + }, + "planning": { + "autoEnter": true, + "complexityThreshold": 3, + "requireApproval": true + }, + "permissions": { + "mode": "unrestricted" + }, + "backgroundTasks": { + "enabled": true, + "maxConcurrentTasks": 3 + }, + "hooks": { + "PreToolUse:Write": "prettier --write ${file_path}", + "PostToolUse:Write": "eslint ${file_path}" + } + } + }, + + "code_review": { + "name": "Code Review Mode", + "description": "Configuration for reviewing code without modifications", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.3 + }, + "permissions": { + "mode": "plan" + }, + "extendedThinking": { + "enabled": true, + "showThinkingProcess": true + }, + "planning": { + "autoEnter": false + } + } + }, + + "learning": { + "name": "Learning Mode", + "description": "Configuration for learning and experimentation", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.5 + }, + "permissions": { + "mode": "confirm" + }, + "extendedThinking": { + "enabled": true, + "showThinkingProcess": true + }, + "planning": { + "autoEnter": true, + "requireApproval": true, + "showTimeEstimates": true + }, + "checkpoints": { + "autoCheckpoint": true + } + } + }, + + "production": { + "name": "Production Deployment", + "description": "Configuration for production operations with safety checks", + "config": { + "general": { + "model": "claude-opus-4", + "temperature": 0.1 + }, + "permissions": { + "mode": "confirm", + "requireConfirmationFor": ["Bash", "Git", "Write", "Edit"] + }, + "hooks": { + "PreToolUse": "~/.claude/hooks/pre-commit.sh" + }, + "checkpoints": { + "autoCheckpoint": true + }, + "planning": { + "autoEnter": true, + "requireApproval": true + } + } + }, + + "ci_cd": { + "name": "CI/CD Pipeline", + "description": "Configuration for automated CI/CD operations", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0 + }, + "permissions": { + "mode": "unrestricted" + }, + "headless": { + "exitOnError": true, + "verbose": true, + "timeout": 3600 + }, + "logging": { + "level": "debug", + "file": "./ci-claude.log" + }, + "planning": { + "autoEnter": false, + "requireApproval": false + } + } + }, + + "security_audit": { + "name": "Security Audit", + "description": "Configuration for security-focused code analysis", + "config": { + "general": { + "model": "claude-opus-4", + "temperature": 0.2 + }, + "permissions": { + "mode": "plan" + }, + "extendedThinking": { + "enabled": true, + "showThinkingProcess": true, + "minThinkingTime": 10 + }, + "hooks": { + "PostToolUse:Read": "~/.claude/hooks/security-scan.sh ${file_path}" + } + } + }, + + "performance_optimization": { + "name": "Performance Optimization", + "description": "Configuration for performance analysis and optimization", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.4 + }, + "planning": { + "autoEnter": true, + "requireApproval": true + }, + "backgroundTasks": { + "enabled": true, + "maxConcurrentTasks": 5 + }, + "checkpoints": { + "autoCheckpoint": true + } + } + }, + + "pair_programming": { + "name": "Pair Programming", + "description": "Configuration for collaborative development", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.6 + }, + "permissions": { + "mode": "confirm" + }, + "planning": { + "autoEnter": true, + "requireApproval": true, + "showTimeEstimates": true + }, + "extendedThinking": { + "enabled": true, + "showThinkingProcess": true + }, + "ui": { + "compactMode": false, + "showProgress": true + } + } + }, + + "refactoring": { + "name": "Large Refactoring", + "description": "Configuration for major refactoring work", + "config": { + "general": { + "model": "claude-opus-4", + "temperature": 0.3 + }, + "planning": { + "autoEnter": true, + "requireApproval": true, + "showTimeEstimates": true + }, + "checkpoints": { + "autoCheckpoint": true + }, + "hooks": { + "PreToolUse:Edit": "~/.claude/hooks/backup-file.sh ${file_path}", + "PostToolUse:Edit": "npm test -- --findRelatedTests ${file_path}" + }, + "permissions": { + "mode": "confirm" + } + } + }, + + "autonomous": { + "name": "Autonomous Development", + "description": "Configuration for autonomous work with auto mode safety checks", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.5 + }, + "permissions": { + "mode": "auto" + }, + "sandbox": { + "enabled": true, + "failIfUnavailable": false + }, + "backgroundTasks": { + "enabled": true, + "maxConcurrentTasks": 3 + } + } + }, + + "documentation": { + "name": "Documentation Writing", + "description": "Configuration for writing documentation", + "config": { + "general": { + "model": "claude-sonnet-4-6", + "temperature": 0.7 + }, + "permissions": { + "mode": "unrestricted" + }, + "hooks": { + "PostToolUse:Write": "markdownlint ${file_path}" + } + } + } + } +} diff --git a/uk/09-advanced-features/setup-auto-mode-permissions.py b/uk/09-advanced-features/setup-auto-mode-permissions.py new file mode 100644 index 0000000..a677314 --- /dev/null +++ b/uk/09-advanced-features/setup-auto-mode-permissions.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 +""" +setup-auto-mode-permissions.py + +Seed ~/.claude/settings.json with a conservative baseline of safe permissions +for Claude Code. The default set is read-only and local-inspection oriented; +optional flags let you widen the allowlist for editing, test execution, git +write operations, package installs, and GitHub CLI writes. + +Usage: + python3 setup-auto-mode-permissions.py + python3 setup-auto-mode-permissions.py --dry-run + python3 setup-auto-mode-permissions.py --include-edits --include-tests +""" + +from __future__ import annotations + +import argparse +import json +import tempfile +from pathlib import Path +from typing import Iterable + +SETTINGS_PATH = Path.home() / ".claude" / "settings.json" + +# Core baseline: read-only inspection and low-risk local shell commands. +CORE_PERMISSIONS = [ + "Read(*)", + "Glob(*)", + "Grep(*)", + "Agent(*)", + "Skill(*)", + "WebSearch(*)", + "WebFetch(*)", + "Bash(ls:*)", + "Bash(pwd:*)", + "Bash(which:*)", + "Bash(echo:*)", + "Bash(cat:*)", + "Bash(head:*)", + "Bash(tail:*)", + "Bash(wc:*)", + "Bash(sort:*)", + "Bash(uniq:*)", + "Bash(find:*)", + "Bash(dirname:*)", + "Bash(basename:*)", + "Bash(realpath:*)", + "Bash(file:*)", + "Bash(stat:*)", + "Bash(diff:*)", + "Bash(md5sum:*)", + "Bash(sha256sum:*)", + "Bash(date:*)", + "Bash(env:*)", + "Bash(printenv:*)", + "Bash(git status:*)", + "Bash(git log:*)", + "Bash(git diff:*)", + "Bash(git branch:*)", + "Bash(git show:*)", + "Bash(git rev-parse:*)", + "Bash(git remote -v:*)", + "Bash(git remote get-url:*)", + "Bash(git stash list:*)", +] + +# Optional but still local: file edits and task bookkeeping. +EDITING_PERMISSIONS = [ + "Edit(*)", + "Write(*)", + "NotebookEdit(*)", + "TaskCreate(*)", + "TaskUpdate(*)", +] + +# Optional dev/test commands. These can still execute arbitrary project scripts, +# so keep them opt-in rather than part of the default baseline. +TEST_AND_BUILD_PERMISSIONS = [ + "Bash(npm test:*)", + "Bash(cargo test:*)", + "Bash(go test:*)", + "Bash(pytest:*)", + "Bash(python3 -m pytest:*)", + "Bash(make:*)", + "Bash(cmake:*)", +] + +# Optional local git write operations. History-rewriting commands stay out of +# the default baseline because they are easy to misuse. +GIT_WRITE_PERMISSIONS = [ + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git checkout:*)", + "Bash(git switch:*)", + "Bash(git stash:*)", + "Bash(git tag:*)", +] + +# Optional dependency/package commands. These are intentionally excluded from +# the default baseline because they can execute project hooks or fetch code. +PACKAGE_MANAGER_PERMISSIONS = [ + "Bash(npm ci:*)", + "Bash(npm install:*)", + "Bash(pip install:*)", + "Bash(pip3 install:*)", +] + +# Optional GitHub CLI write access. +GITHUB_WRITE_PERMISSIONS = [ + "Bash(gh pr create:*)", +] + +# Optional extra GitHub CLI read access. +GITHUB_READ_PERMISSIONS = [ + "Bash(gh pr view:*)", + "Bash(gh pr list:*)", + "Bash(gh issue view:*)", + "Bash(gh issue list:*)", + "Bash(gh repo view:*)", +] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Seed Claude Code settings with a conservative permission baseline." + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Preview the rules that would be added without writing settings.json", + ) + parser.add_argument( + "--include-edits", + action="store_true", + help="Add file-editing permissions (Edit/Write/NotebookEdit/TaskCreate/TaskUpdate)", + ) + parser.add_argument( + "--include-tests", + action="store_true", + help="Add local build/test commands such as pytest, cargo test, and make", + ) + parser.add_argument( + "--include-git-write", + action="store_true", + help="Add local git mutation commands such as add, commit, checkout, and stash", + ) + parser.add_argument( + "--include-packages", + action="store_true", + help="Add package install commands such as npm ci, npm install, and pip install", + ) + parser.add_argument( + "--include-gh-write", + action="store_true", + help="Add GitHub CLI write permissions such as gh pr create", + ) + parser.add_argument( + "--include-gh-read", + action="store_true", + help="Add GitHub CLI read permissions such as gh pr view and gh repo view", + ) + return parser.parse_args() + + +def load_settings(path: Path) -> dict: + if not path.exists(): + return {} + + try: + with path.open() as f: + settings = json.load(f) + except json.JSONDecodeError as exc: + raise SystemExit(f"Invalid JSON in {path}: {exc}") from exc + + if not isinstance(settings, dict): + raise SystemExit(f"Expected {path} to contain a JSON object.") + + return settings + + +def build_permissions(args: argparse.Namespace) -> list[str]: + permissions = list(CORE_PERMISSIONS) + + if args.include_edits: + permissions.extend(EDITING_PERMISSIONS) + + if args.include_tests: + permissions.extend(TEST_AND_BUILD_PERMISSIONS) + + if args.include_git_write: + permissions.extend(GIT_WRITE_PERMISSIONS) + + if args.include_packages: + permissions.extend(PACKAGE_MANAGER_PERMISSIONS) + + if args.include_gh_write: + permissions.extend(GITHUB_WRITE_PERMISSIONS) + + if args.include_gh_read: + permissions.extend(GITHUB_READ_PERMISSIONS) + + return permissions + + +def append_unique(existing: list, new_items: Iterable[str]) -> list[str]: + seen = set(existing) + added: list[str] = [] + for item in new_items: + if item not in seen: + existing.append(item) + seen.add(item) + added.append(item) + return added + + +def atomic_write_json(path: Path, payload: dict) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile( + "w", + encoding="utf-8", + dir=str(path.parent), + delete=False, + ) as tmp: + json.dump(payload, tmp, indent=2) + tmp.write("\n") + tmp_path = Path(tmp.name) + + tmp_path.replace(path) + + +def main() -> None: + args = parse_args() + permissions_to_add = build_permissions(args) + + settings = load_settings(SETTINGS_PATH) + permissions = settings.setdefault("permissions", {}) + + if not isinstance(permissions, dict): + raise SystemExit("Expected permissions to be a JSON object.") + + allow = permissions.setdefault("allow", []) + if not isinstance(allow, list): + raise SystemExit("Expected permissions.allow to be a JSON array.") + + added = append_unique(allow, permissions_to_add) + + if not added: + print("Nothing to add — all selected rules already present.") + return + + print(f"{'Would add' if args.dry_run else 'Adding'} {len(added)} rule(s):") + for rule in added: + print(f" + {rule}") + + if args.dry_run: + print("\nDry run — no changes written.") + return + + atomic_write_json(SETTINGS_PATH, settings) + print(f"\nDone. {len(added)} rule(s) added to {SETTINGS_PATH}") + + +if __name__ == "__main__": + main() diff --git a/uk/CHANGELOG.md b/uk/CHANGELOG.md new file mode 100644 index 0000000..7a87b86 --- /dev/null +++ b/uk/CHANGELOG.md @@ -0,0 +1,154 @@ +# Changelog + +## v2.3.0 — 2026-04-07 + +### Features + +- build and publish EPUB artifacts per language (90e9c30) @Thiên Toán +- add missing pre-tool-check.sh hook to 06-hooks (b511ed1) @JiayuWang +- add Chinese translations in zh/ directory (89e89d4) @Luong NGUYEN +- Add performance-optimizer subagent and dependency-check hook (f53d080) @qk + +### Bug Fixes + +- Windows Git Bash compatibility + stdin JSON protocol (2cbb10c) @Luong NGUYEN +- correct autoCheckpoint config documentation in 08-checkpoints (749c79f) @JiayuWang +- embed SVG images instead of replacing with placeholders (1b16709) @Thiên Toán +- nested code fence rendering in memory README (ce24423) @Zhaoshan Duan +- apply review fixes dropped by squash merge (34259ca) @Luong NGUYEN +- make hook scripts compatible with Windows Git Bash and use stdin JSON protocol (107153d) @binyu li + +### Documentation + +- sync all tutorials with latest Claude Code docs (April 2026) (72d3b01) @Luong NGUYEN +- add Chinese language link to language switcher (6cbaa4d) @Luong NGUYEN +- add language switcher between English and Vietnamese (100c45e) @Luong NGUYEN +- add GitHub #1 Trending badge (0ca8c37) @Luong NGUYEN +- Introduce cc-context-stats for context zone monitoring (d41b335) @Luong NGUYEN +- Introduce luongnv89/skills collection and luongnv89/asm skill manager (7e3c0b6) @Luong NGUYEN +- Update README stats to reflect current GitHub metrics (5,900+ stars, 690+ forks) (5001525) @Luong NGUYEN +- Update README stats to reflect current GitHub metrics (3,900+ stars, 460+ forks) (9cb92d6) @Luong NGUYEN + +### Refactoring + +- replace Kroki HTTP dependency with local mmdc rendering (e76bbe4) @Luong NGUYEN +- shift quality checks to pre-commit, CI as 2nd pass (6d1e0ae) @Luong NGUYEN +- narrow auto-mode permissions baseline (2790fb2) @Luong NGUYEN +- Replace auto-adapt hook with one-time permissions setup script (995a5d6) @Luong NGUYEN + +### Other + +- shift-left quality gates — add mypy to pre-commit, fix CI failures (699fb39) @Luong NGUYEN +- Add Vietnamese (Tiếng Việt) Localization (a70777e) @Thiên Toán + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/v2.2.0...v2.3.0 + +--- + +## v2.2.0 — 2026-03-26 + +### Documentation + +- Sync all tutorials and references with Claude Code v2.1.84 (f78c094) @luongnv89 + - Update slash commands to 55+ built-in + 5 bundled skills, mark 3 deprecated + - Expand hook events from 18 to 25, add `agent` hook type (now 4 types) + - Add Auto Mode, Channels, Voice Dictation to advanced features + - Add `effort`, `shell` skill frontmatter fields; `initialPrompt`, `disallowedTools` agent fields + - Add WebSocket MCP transport, elicitation, 2KB tool cap + - Add plugin LSP support, `userConfig`, `${CLAUDE_PLUGIN_DATA}` + - Update all reference docs (CATALOG, QUICK_REFERENCE, LEARNING-ROADMAP, INDEX) +- Rewrite README as landing-page-structured guide (32a0776) @luongnv89 + +### Bug Fixes + +- Add missing cSpell words and README sections for CI compliance (93f9d51) @luongnv89 +- Add `Sandboxing` to cSpell dictionary (b80ce6f) @luongnv89 + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/v2.1.1...v2.2.0 + +--- + +## v2.1.1 — 2026-03-13 + +### Bug Fixes + +- Remove dead marketplace link failing CI link checks (3fdf0d6) @luongnv89 +- Add `sandboxed` and `pycache` to cSpell dictionary (dc64618) @luongnv89 + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/v2.1.0...v2.1.1 + +--- + +## v2.1.0 — 2026-03-13 + +### Features + +- Add adaptive learning path with self-assessment and lesson quiz skills (1ef46cd) @luongnv89 + - `/self-assessment` — interactive proficiency quiz across 10 feature areas with personalized learning path + - `/lesson-quiz [lesson]` — per-lesson knowledge check with 8-10 targeted questions + +### Bug Fixes + +- Update broken URLs, deprecations, and outdated references (8fe4520) @luongnv89 +- Fix broken links in resources and self-assessment skill (7a05863) @luongnv89 +- Use tilde fences for nested code blocks in concepts guide (5f82719) @VikalpP +- Add missing words to cSpell dictionary (8df7572) @luongnv89 + +### Documentation + +- Phase 5 QA — fix consistency, URLs, and terminology across docs (00bbe4c) @luongnv89 +- Complete Phases 3-4 — new feature coverage and reference doc updates (132de29) @luongnv89 +- Add MCPorter runtime to MCP context bloat section (ef52705) @luongnv89 +- Add missing commands, features, and settings across 6 guides (4bc8f15) @luongnv89 +- Add style guide based on existing repo conventions (84141d0) @luongnv89 +- Add self-assessment row to guide comparison table (8fe0c96) @luongnv89 +- Add VikalpP to contributors list for PR #7 (d5b4350) @luongnv89 +- Add self-assessment and lesson-quiz skill references to README and roadmap (d5a6106) @luongnv89 + +### New Contributors + +- @VikalpP made their first contribution in #7 + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/v2.0.0...v2.1.0 + +--- + +## v2.0.0 — 2026-02-01 + +### Features + +- Sync all documentation with Claude Code February 2026 features (487c96d) + - Update 26 files across all 10 tutorial directories and 7 reference documents + - Add documentation for **Auto Memory** — persistent learnings per project + - Add documentation for **Remote Control**, **Web Sessions**, and **Desktop App** + - Add documentation for **Agent Teams** (experimental multi-agent collaboration) + - Add documentation for **MCP OAuth 2.0**, **Tool Search**, and **Claude.ai Connectors** + - Add documentation for **Persistent Memory** and **Worktree Isolation** for subagents + - Add documentation for **Background Subagents**, **Task List**, **Prompt Suggestions** + - Add documentation for **Sandboxing** and **Managed Settings** (Enterprise) + - Add documentation for **HTTP Hooks** and 7 new hook events + - Add documentation for **Plugin Settings**, **LSP Servers**, and Marketplace updates + - Add documentation for **Summarize from Checkpoint** rewind option + - Document 17 new slash commands (`/fork`, `/desktop`, `/teleport`, `/tasks`, `/fast`, etc.) + - Document new CLI flags (`--worktree`, `--from-pr`, `--remote`, `--teleport`, `--teammate-mode`, etc.) + - Document new environment variables for auto memory, effort levels, agent teams, and more + +### Design + +- Redesign logo to compass-bracket mark with minimal palette (20779db) + +### Bug Fixes / Corrections + +- Update model names: Sonnet 4.5 → **Sonnet 4.6**, Opus 4.5 → **Opus 4.6** +- Fix permission mode names: replace fictional "Unrestricted/Confirm/Read-only" with actual `default`/`acceptEdits`/`plan`/`dontAsk`/`bypassPermissions` +- Fix hook events: remove fictional `PreCommit`/`PostCommit`/`PrePush`, add real events (`SubagentStart`, `WorktreeCreate`, `ConfigChange`, etc.) +- Fix CLI syntax: replace `claude-code --headless` with `claude -p` (print mode) +- Fix checkpoint commands: replace fictional `/checkpoint save/list/rewind/diff` with actual `Esc+Esc` / `/rewind` interface +- Fix session management: replace fictional `/session list/new/switch/save` with real `/resume`/`/rename`/`/fork` +- Fix plugin manifest format: migrate `plugin.yaml` → `.claude-plugin/plugin.json` +- Fix MCP config paths: `~/.claude/mcp.json` → `.mcp.json` (project) / `~/.claude.json` (user) +- Fix documentation URLs: `docs.claude.com` → `docs.anthropic.com`; remove fictional `plugins.claude.com` +- Remove fictional configuration fields across multiple files +- Update all "Last Updated" dates to February 2026 + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/20779db...v2.0.0 diff --git a/uk/CODE_OF_CONDUCT.md b/uk/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..bc44f72 --- /dev/null +++ b/uk/CODE_OF_CONDUCT.md @@ -0,0 +1,224 @@ + + + + +# Кодекс поведінки контриб'юторів + +## Наше зобов'язання + +Ми зобов'язуємося забезпечити привітну та надихаючу спільноту для всіх. Ми запевняємо, що участь у нашій спільноті є вільною від переслідувань для кожного, незалежно від віку, статури, касти, інвалідності, етнічної приналежності, статевих ознак, гендерної ідентичності та вираження, рівня досвіду, освіти, соціально-економічного статусу, національності, зовнішнього вигляду, раси, релігії або сексуальної ідентичності та орієнтації. + +Ми прагнемо забезпечити позитивне, інклюзивне та безпечне середовище, де всі контриб'ютори відчувають повагу, цінність та можливість внести свій найкращий вклад. + +## Наші стандарти + +Приклади поведінки, що сприяє створенню позитивного середовища: + +### Будьте поважними +- Використовуйте привітну та інклюзивну мову +- Поважайте різні думки, погляди та досвід +- Приймайте конструктивну критику з гідністю +- Поважайте культурні та мовні відмінності +- Визнавайте та цінуйте різноманітне походження + +### Будьте колаборативними +- Працюйте разом над вирішенням конфліктів +- Відзначайте та визнавайте внески інших +- Допомагайте іншим вчитися та зростати +- Діліться знаннями та ставте запитання +- Підтримуйте колег по спільноті + +### Будьте професійними +- Тримайте обговорення зосередженими та продуктивними +- Уникайте принизливих або образливих зауважень +- Залишайтесь у темі в issues та обговореннях +- Використовуйте чітку та поважну комунікацію +- Припускайте добрі наміри в повідомленнях інших + +### Будьте інклюзивними +- Вітайте нових контриб'юторів +- Допомагайте адаптуватися людям, новим у проєкті +- Надавайте конструктивний зворотний зв'язок +- Залучайте людей з різними перспективами +- Створюйте простір для тихих голосів + +## Неприйнятна поведінка + +Наступні дії вважаються переслідуванням та є неприйнятними в нашій спільноті: + +### Переслідування та дискримінація +- Образливі коментарі щодо гендеру, гендерної ідентичності та вираження, сексуальної орієнтації, інвалідності, психічного захворювання, нейро(а)типовості, зовнішнього вигляду, статури, віку, раси або релігії +- Небажані коментарі щодо життєвого вибору та практик людини +- Навмисне неправильне вживання займенників або використання «мертвих» або відкинутих імен +- Безпідставні або не по темі сексуальні зображення або поведінка +- Фізичний контакт та імітований фізичний контакт без згоди або після прохання припинити + +### Зловживання +- Погрози насильством або агресивна мова, спрямована проти іншої людини +- Підбурювання до насильства або агресивна мова щодо будь-якої особи +- Навмисне залякування +- Переслідування або стеження +- Переслідування через повторні контакти +- Будь-яка інша поведінка, яку можна обґрунтовано вважати неприйнятною + +### Онлайн-переслідування +- Систематичне порушення онлайн-обговорень +- Публікація приватної інформації інших (доксинг) +- Небажана сексуальна увага або домагання +- Тролінг або навмисне порушення +- Спам або повторна реклама +- Поширення дезінформації + +### Помста +- Вжиття карних заходів проти когось за повідомлення про порушення +- Несправедливе ставлення до когось через повідомлення про неприйнятну поведінку +- Погрози повідомити про когось у відповідь + +## Область застосування + +Цей Кодекс поведінки застосовується до: +- Усіх просторів спільноти (GitHub issues, pull requests, обговорення тощо) +- Репозиторіїв та документації проєкту +- Подій та зібрань, організованих проєктом або від його імені +- Публічних просторів, де особи представляють проєкт або спільноту +- Приватних комунікацій, коли вони стосуються справ проєкту + +Кодекс поведінки застосовується до всіх просторів проєкту, а також коли особа представляє проєкт або спільноту в публічних просторах. Приклади представлення проєкту або спільноти включають використання офіційної електронної адреси проєкту, публікації через офіційний акаунт у соціальних мережах або діяльність як призначений представник на онлайн- або офлайн-заході. + +## Застосування + +Лідери спільноти відповідають за роз'яснення та дотримання наших стандартів прийнятної поведінки та вживатимуть відповідних та справедливих коригувальних дій у відповідь на будь-яку поведінку, яку вони вважають неприйнятною, загрозливою, образливою або шкідливою. + +### Повідомлення про порушення + +Якщо ви стали свідком або жертвою неприйнятної поведінки, або маєте будь-які інші занепокоєння, будь ласка, повідомте: + +1. **Email**: Зв'яжіться з мейнтейнерами проєкту +2. **GitHub Issues**: Функція приватного повідомлення (якщо доступна) +3. **Пряме повідомлення**: Зв'яжіться з мейнтейнером проєкту напряму + +Вкажіть: +- Вашу контактну інформацію +- Імена залучених осіб (якщо вам комфортно ділитися) +- Опис інциденту +- Контекст та відповідні посилання +- Як інцидент вплинув на вас + +**Усі повідомлення зберігатимуться конфіденційно.** + +### Розслідування та реагування + +Лідери спільноти: +- Переглядатимуть та розслідуватимуть усі скарги оперативно та справедливо +- Зберігатимуть конфіденційність щодо репортера +- Повідомлятимуть репортера про статус його повідомлення +- Вживатимуть відповідних дій на основі результатів + +Можливі дії: +- Приватне попередження або консультація +- Публічні вибачення (за згодою порушника) +- Тимчасове або постійне видалення з просторів спільноти +- Втрата привілеїв контриб'ютора +- Ескалація на GitHub або інші платформи за потреби + +### Процес апеляції + +Якщо ви вважаєте, що рішення було прийнято помилково, ви можете оскаржити: +1. Надавши нову інформацію або контекст +2. Запросивши перегляд кількома мейнтейнерами +3. Звернувшись протягом 30 днів після початкового рішення + +## Настанови для шанобливої незгоди + +Розбіжності є природними в технічних спільнотах. Ось як не погоджуватись шанобливо: + +### Робіть +- ✅ Зосереджуйтесь на ідеї, а не на людині +- ✅ Ставте уточнюючі запитання +- ✅ Визнавайте слушні моменти в протилежних поглядах +- ✅ Використовуйте «Я»-висловлювання («Я не погоджуюсь, тому що...») +- ✅ Посилайтесь на джерела та факти +- ✅ Дякуйте іншим за їхню перспективу + +### Не робіть +- ❌ Переходьте на особистості +- ❌ Використовуйте зневажливу мову («Це дурниця») +- ❌ Припускайте погані наміри +- ❌ Піднімайте непов'язані минулі конфлікти +- ❌ Підвищуйте тон або ставайте ворожими +- ❌ Навмисно спотворюйте погляди інших + +### Приклад шанобливої незгоди +``` +❌ Погано: "That's a dumb idea and you clearly don't understand the project." + +✅ Добре: "I see your point, but I'm concerned this approach might +not scale well with larger projects. Have you considered the +performance implications shown in this benchmark? I'd love to +hear your thoughts on this." +``` + +## Будування мостів + +Ми віримо в силу діалогу та примирення: + +- Якщо хтось вказує на вашу поведінку, слухайте та рефлексуйте +- Будьте готові вибачитися, якщо завдали шкоди +- Підтримуйте інших у навчанні та зростанні +- Визнавайте, що люди роблять помилки +- Зосереджуйтесь на рішеннях, а не на звинуваченнях +- Припускайте добрі наміри, зберігаючи відповідальність + +## Переваги дотримання цього кодексу + +Підтримуючи шанобливу та інклюзивну спільноту, ми: +- Залучаємо різноманітних контриб'юторів з різними перспективами +- Створюємо кращі рішення через співпрацю +- Будуємо міцніші стосунки +- Робимо проєкт привітнішим для новачків +- Виробляємо якіснішу документацію та приклади +- Формуємо культуру навчання та зростання + +## Спеціальні міркування + +### Для мейнтейнерів +- Подавайте приклад у дотриманні цього Кодексу +- Оперативно реагуйте на повідомлення +- Будьте прозорими щодо рішень +- Допомагайте справедливо вирішувати конфлікти +- Створюйте безпечне середовище для всіх + +### Для контриб'юторів +- Припускайте добрі наміри мейнтейнерів та інших контриб'юторів +- Надавайте конструктивний зворотний зв'язок +- Підтримуйте новачків +- Допомагайте дотримуватись стандартів спільноти +- Беріть відповідальність за культуру спільноти + +### Для всіх +- Пам'ятайте, що за кожним повідомленням стоїть людина +- Робіть перерви, якщо відчуваєте фрустрацію +- Звертайтесь до лідерів спільноти, якщо потрібна підтримка +- Допомагайте створювати спільноту, частиною якої хочете бути + +## Атрибуція + +Цей Кодекс поведінки адаптовано з: +- [Contributor Covenant](https://www.contributor-covenant.org/) +- [Mozilla Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/) +- [Python Community Code of Conduct](https://www.python.org/psf/conduct/) + +## Запитання? + +Якщо у вас є запитання щодо цього Кодексу поведінки, зверніться до мейнтейнерів проєкту. + +## Історія версій + +- **Версія 1.0** (Січень 2026) — Початковий Кодекс поведінки + +--- + +**Дякуємо за допомогу в створенні привітної, інклюзивної та шанобливої спільноти!** 🌟 + +--- +**Останнє оновлення**: Квітень 2026 diff --git a/uk/CONTRIBUTING.md b/uk/CONTRIBUTING.md new file mode 100644 index 0000000..68d8b49 --- /dev/null +++ b/uk/CONTRIBUTING.md @@ -0,0 +1,385 @@ + + + + + + + Claude How To + + +# Внесок у Claude How To + +Дякуємо за ваш інтерес до участі в цьому проєкті! Цей довідник допоможе вам зрозуміти, як ефективно зробити внесок. + +## Про цей проєкт + +Claude How To — це візуальний, заснований на прикладах довідник з Claude Code. Ми надаємо: +- **Mermaid-діаграми**, що пояснюють як працюють функції +- **Готові до продакшену шаблони**, які можна використовувати одразу +- **Реальні приклади** з контекстом та найкращими практиками +- **Прогресивні шляхи навчання** від початківця до просунутого + +## Типи внесків + +### 1. Нові приклади або шаблони +Додавайте приклади для існуючих функцій (слеш-команди, навички, хуки тощо): +- Код, готовий до копіювання та вставки +- Чіткі пояснення як це працює +- Сценарії використання та переваги +- Поради з усунення проблем + +### 2. Покращення документації +- Уточнення заплутаних розділів +- Виправлення помилок та граматики +- Додавання відсутньої інформації +- Покращення прикладів коду + +### 3. Гайди з функцій +Створюйте гайди для нових функцій Claude Code: +- Покрокові туторіали +- Архітектурні діаграми +- Поширені патерни та анти-патерни +- Реальні робочі процеси + +### 4. Звіти про помилки +Повідомляйте про проблеми: +- Опишіть, що ви очікували +- Опишіть, що сталося насправді +- Вкажіть кроки для відтворення +- Додайте версію Claude Code та ОС + +### 5. Відгуки та пропозиції +Допоможіть покращити довідник: +- Запропонуйте кращі пояснення +- Вкажіть на прогалини в покритті +- Порекомендуйте нові розділи або реорганізацію + +## Початок роботи + +### 1. Форк та клонування +```bash +git clone https://github.com/luongnv89/claude-howto.git +cd claude-howto +``` + +### 2. Створення гілки +Використовуйте описову назву гілки: +```bash +git checkout -b add/feature-name +git checkout -b fix/issue-description +git checkout -b docs/improvement-area +``` + +### 3. Налаштування середовища + +Pre-commit хуки запускають ті ж перевірки, що й CI, локально перед кожним комітом. Усі чотири перевірки повинні пройти перед прийняттям PR. + +**Необхідні залежності:** + +```bash +# Python tooling (uv is the package manager for this project) +pip install uv +uv venv +source .venv/bin/activate +uv pip install -r scripts/requirements-dev.txt + +# Markdown linter (Node.js) +npm install -g markdownlint-cli + +# Mermaid diagram validator (Node.js) +npm install -g @mermaid-js/mermaid-cli + +# Install pre-commit and activate hooks +uv pip install pre-commit +pre-commit install +``` + +**Перевірка налаштування:** + +```bash +pre-commit run --all-files +``` + +Хуки, що запускаються при кожному коміті: + +| Хук | Що перевіряє | +|-----|-------------| +| `markdown-lint` | Форматування та структуру Markdown | +| `cross-references` | Відносні посилання, якорі, блоки коду | +| `mermaid-syntax` | Усі блоки ` ```mermaid ` коректно парсяться | +| `link-check` | Зовнішні URL-адреси доступні | +| `build-epub` | EPUB генерується без помилок (при змінах `.md`) | + +## Структура каталогів + +``` +├── 01-slash-commands/ # Ярлики, ініційовані користувачем +├── 02-memory/ # Приклади постійного контексту +├── 03-skills/ # Повторно використовувані можливості +├── 04-subagents/ # Спеціалізовані AI-асистенти +├── 05-mcp/ # Приклади Model Context Protocol +├── 06-hooks/ # Автоматизація на основі подій +├── 07-plugins/ # Пакетні функції +├── 08-checkpoints/ # Знімки сесій +├── 09-advanced-features/ # Планування, мислення, фони +├── 10-cli/ # Довідник CLI +├── scripts/ # Скрипти збірки та утиліт +└── README.md # Основний довідник +``` + +## Як зробити внесок прикладів + +### Додавання слеш-команди +1. Створіть файл `.md` в `01-slash-commands/` +2. Включіть: + - Чіткий опис що вона робить + - Сценарії використання + - Інструкції з встановлення + - Приклади використання + - Поради з налаштування +3. Оновіть `01-slash-commands/README.md` + +### Додавання навички +1. Створіть каталог в `03-skills/` +2. Включіть: + - `SKILL.md` — основна документація + - `scripts/` — допоміжні скрипти за потреби + - `templates/` — шаблони промптів + - Приклади використання в README +3. Оновіть `03-skills/README.md` + +### Додавання субагента +1. Створіть файл `.md` в `04-subagents/` +2. Включіть: + - Призначення та можливості агента + - Структуру системного промпту + - Приклади використання + - Приклади інтеграції +3. Оновіть `04-subagents/README.md` + +### Додавання конфігурації MCP +1. Створіть файл `.json` в `05-mcp/` +2. Включіть: + - Пояснення конфігурації + - Необхідні змінні оточення + - Інструкції з налаштування + - Приклади використання +3. Оновіть `05-mcp/README.md` + +### Додавання хука +1. Створіть файл `.sh` в `06-hooks/` +2. Включіть: + - Shebang та опис + - Чіткі коментарі, що пояснюють логіку + - Обробку помилок + - Міркування безпеки +3. Оновіть `06-hooks/README.md` + +## Настанови з написання + +### Стиль Markdown +- Використовуйте чіткі заголовки (H2 для секцій, H3 для підсекцій) +- Тримайте абзаци короткими та зосередженими +- Використовуйте маркеровані списки +- Включайте блоки коду з вказівкою мови +- Додавайте порожні рядки між секціями + +### Приклади коду +- Робіть приклади готовими до копіювання та вставки +- Коментуйте неочевидну логіку +- Включайте і прості, і просунуті версії +- Показуйте реальні сценарії використання +- Виділяйте потенційні проблеми + +### Документація +- Пояснюйте «чому», а не тільки «що» +- Вказуйте передумови +- Додавайте розділи з усунення проблем +- Посилайтесь на пов'язані теми +- Зберігайте дружність до початківців + +### JSON/YAML +- Використовуйте правильні відступи (2 або 4 пробіли послідовно) +- Додавайте коментарі, що пояснюють конфігурацію +- Включайте приклади валідації + +### Діаграми +- Використовуйте Mermaid коли можливо +- Тримайте діаграми простими та читабельними +- Додавайте текстовий опис під діаграмами для доступності +- Посилайтесь на відповідні розділи + +## Настанови для комітів + +Дотримуйтесь формату conventional commits: +``` +type(scope): description + +[optional body] +``` + +Типи: +- `feat`: Нова функція або приклад +- `fix`: Виправлення помилки +- `docs`: Зміни документації +- `refactor`: Реструктуризація коду +- `style`: Зміни форматування +- `test`: Додавання або зміни тестів +- `chore`: Збірка, залежності тощо + +Приклади: +``` +feat(slash-commands): Add API documentation generator +docs(memory): Improve personal preferences example +fix(README): Correct table of contents link +docs(skills): Add comprehensive code review skill +``` + +## Перед відправкою + +### Чеклист +- [ ] Код відповідає стилю та конвенціям проєкту +- [ ] Нові приклади включають чітку документацію +- [ ] README файли оновлені (локальний та кореневий) +- [ ] Немає чутливої інформації (API-ключі, облікові дані) +- [ ] Приклади протестовані та працюють +- [ ] Посилання перевірені та коректні +- [ ] Файли мають правильні дозволи (скрипти виконувані) +- [ ] Повідомлення коміту чітке та описове + +### Локальне тестування +```bash +# Run all pre-commit checks (same checks as CI) +pre-commit run --all-files + +# Review your changes +git diff +``` + +## Процес Pull Request + +1. **Створіть PR з чітким описом**: + - Що додає/виправляє? + - Чому це потрібно? + - Пов'язані issues (якщо є) + +2. **Включіть відповідні деталі**: + - Нова функція? Включіть сценарії використання + - Документація? Поясніть покращення + - Приклади? Покажіть до/після + +3. **Посилайтесь на issues**: + - Використовуйте `Closes #123` для автоматичного закриття пов'язаних issues + +4. **Будьте терплячими з рев'ю**: + - Мейнтейнери можуть запропонувати покращення + - Ітеруйте на основі зворотного зв'язку + - Остаточне рішення за мейнтейнерами + +## Процес код-рев'ю + +Рецензенти перевірять: +- **Точність**: Чи працює як описано? +- **Якість**: Чи готово до продакшену? +- **Консистентність**: Чи відповідає патернам проєкту? +- **Документація**: Чи чітко та повно? +- **Безпека**: Чи є вразливості? + +## Повідомлення про проблеми + +### Звіти про помилки +Включіть: +- Версію Claude Code +- Операційну систему +- Кроки для відтворення +- Очікувану поведінку +- Фактичну поведінку +- Скріншоти (за потреби) + +### Запити на функції +Включіть: +- Сценарій використання або проблему, що вирішується +- Запропоноване рішення +- Альтернативи, які ви розглядали +- Додатковий контекст + +### Проблеми з документацією +Включіть: +- Що незрозуміло або відсутнє +- Запропоновані покращення +- Приклади або посилання + +## Політики проєкту + +### Чутлива інформація +- Ніколи не комітьте API-ключі, токени або облікові дані +- Використовуйте значення-заповнювачі в прикладах +- Включайте `.env.example` для конфігураційних файлів +- Документуйте необхідні змінні оточення + +### Якість коду +- Тримайте приклади зосередженими та читабельними +- Уникайте надмірного ускладнення рішень +- Включайте коментарі для неочевидної логіки +- Тестуйте ретельно перед відправкою + +### Інтелектуальна власність +- Оригінальний контент належить автору +- Проєкт використовує освітню ліцензію +- Поважайте існуючі авторські права +- Вказуйте атрибуцію за потреби + +## Отримання допомоги + +- **Запитання**: Відкрийте обговорення в GitHub Issues +- **Загальна допомога**: Перевірте існуючу документацію +- **Допомога з розробки**: Перегляньте подібні приклади +- **Код-рев'ю**: Позначте мейнтейнерів у PR + +## Визнання + +Контриб'юторів відзначають у: +- Секції контриб'юторів README.md +- Сторінці контриб'юторів GitHub +- Історії комітів + +## Безпека + +При внесенні прикладів та документації, будь ласка, дотримуйтесь безпечних практик кодування: + +- **Ніколи не захардкоджуйте секрети або API-ключі** — використовуйте змінні оточення +- **Попереджайте про наслідки безпеки** — виділяйте потенційні ризики +- **Використовуйте безпечні значення за замовчуванням** — увімкніть функції безпеки за замовчуванням +- **Валідуйте введення** — показуйте правильну валідацію та санітизацію введення +- **Включайте нотатки безпеки** — документуйте міркування безпеки + +Щодо проблем безпеки, див. [SECURITY.md](SECURITY.md) для нашого процесу повідомлення про вразливості. + +## Кодекс поведінки + +Ми зобов'язуємося забезпечити привітну та інклюзивну спільноту. Будь ласка, прочитайте [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) для повних стандартів спільноти. + +Коротко: +- Будьте поважними та інклюзивними +- Приймайте зворотний зв'язок з гідністю +- Допомагайте іншим вчитися та зростати +- Уникайте переслідувань або дискримінації +- Повідомляйте про проблеми мейнтейнерам + +Усі контриб'ютори повинні дотримуватися цього кодексу та ставитися одне до одного з добротою та повагою. + +## Ліцензія + +Роблячи внесок у цей проєкт, ви погоджуєтесь, що ваші внески будуть ліцензовані за ліцензією MIT. Деталі див. у файлі [LICENSE](LICENSE). + +## Запитання? + +- Перевірте [README](README.md) +- Перегляньте [LEARNING-ROADMAP.md](LEARNING-ROADMAP.md) +- Подивіться існуючі приклади +- Відкрийте issue для обговорення + +Дякуємо за ваш внесок! 🙏 + +--- +**Останнє оновлення**: Квітень 2026 diff --git a/uk/SECURITY.md b/uk/SECURITY.md new file mode 100644 index 0000000..d079c96 --- /dev/null +++ b/uk/SECURITY.md @@ -0,0 +1,338 @@ + + + + +# Політика безпеки + +## Огляд + +Безпека проєкту Claude How To є важливою для нас. Цей документ описує наші практики безпеки та пояснює, як відповідально повідомляти про вразливості. + +## Підтримувані версії + +Ми надаємо оновлення безпеки для наступних версій: + +| Версія | Статус | Підтримка до | +|--------|--------|--------------| +| Остання (main) | ✅ Активна | Поточна + 6 місяців | +| Релізи 1.x | ✅ Активна | До наступної мажорної версії | + +**Примітка**: Як освітній проєкт-довідник, ми зосереджуємося на підтримці актуальних найкращих практик та безпеки документації, а не на традиційній підтримці версій. Оновлення застосовуються безпосередньо до гілки main. + +## Практики безпеки + +### Безпека коду + +1. **Управління залежностями** + - Усі Python-залежності зафіксовані в `requirements.txt` + - Регулярні оновлення через dependabot та ручний перегляд + - Сканування безпеки за допомогою Bandit при кожному коміті + - Pre-commit хуки для перевірок безпеки + +2. **Якість коду** + - Лінтинг за допомогою Ruff виявляє поширені проблеми + - Перевірка типів за допомогою mypy запобігає вразливостям, пов'язаним з типами + - Pre-commit хуки забезпечують дотримання стандартів + - Усі зміни переглядаються перед злиттям + +3. **Контроль доступу** + - Захист гілки `main` + - Обов'язковий рев'ю перед мерджем + - Статусні перевірки повинні пройти перед мерджем + - Обмежений доступ на запис до репозиторію + +### Безпека документації + +1. **Ніяких секретів у прикладах** + - Усі API-ключі в прикладах є заповнювачами + - Облікові дані ніколи не захардкоджені + - Файли `.env.example` показують необхідні змінні + - Чіткі попередження щодо управління секретами + +2. **Найкращі практики безпеки** + - Приклади демонструють безпечні патерни + - Попередження безпеки виділені в документації + - Посилання на офіційні гайди безпеки + - Обробка облікових даних обговорюється у відповідних розділах + +3. **Перегляд контенту** + - Вся документація перевіряється на проблеми безпеки + - Міркування безпеки в настановах для контриб'юторів + - Валідація зовнішніх посилань та посилань + +### Безпека залежностей + +1. **Сканування** + - Bandit сканує весь Python-код на вразливості + - Перевірка вразливостей залежностей через GitHub security alerts + - Регулярні ручні аудити безпеки + +2. **Оновлення** + - Патчі безпеки застосовуються оперативно + - Мажорні версії оцінюються ретельно + - Changelog включає оновлення, пов'язані з безпекою + +3. **Прозорість** + - Оновлення безпеки задокументовані в комітах + - Розкриття вразливостей обробляється відповідально + - Публічні рекомендації безпеки за потреби + +## Повідомлення про вразливість + +### Проблеми безпеки, які нас цікавлять + +Ми цінуємо повідомлення про: +- **Вразливості коду** в скриптах або прикладах +- **Вразливості залежностей** у Python-пакетах +- **Проблеми криптографії** в будь-яких прикладах коду +- **Недоліки автентифікації/авторизації** в документації +- **Ризики витоку даних** у прикладах конфігурації +- **Вразливості ін'єкцій** (SQL, команди тощо) +- **Проблеми SSRF/XXE/обхід шляхів** + +### Проблеми безпеки поза межами + +Це виходить за рамки цього проєкту: +- Вразливості в самому Claude Code (повідомляйте Anthropic) +- Проблеми із зовнішніми сервісами або бібліотеками (повідомляйте upstream) +- Соціальна інженерія або навчання користувачів (не стосується цього довідника) +- Теоретичні вразливості без підтвердження концепції +- Вразливості в залежностях, повідомлені через офіційні канали + +## Як повідомити + +### Приватне повідомлення (рекомендовано) + +**Для чутливих проблем безпеки використовуйте приватне повідомлення про вразливості GitHub:** + +1. Перейдіть: https://github.com/luongnv89/claude-howto/security/advisories +2. Натисніть "Report a vulnerability" +3. Заповніть деталі вразливості +4. Вкажіть: + - Чіткий опис вразливості + - Уражений компонент (файл, розділ, приклад) + - Потенційний вплив + - Кроки для відтворення (якщо можливо) + - Запропоноване виправлення (якщо є) + +**Що відбувається далі:** +- Ми підтвердимо отримання протягом 48 годин +- Ми дослідимо та оцінимо серйозність +- Ми працюватимемо з вами над розробкою виправлення +- Ми узгодимо графік розкриття +- Ми вкажемо вас у рекомендації безпеки (якщо ви не бажаєте анонімності) + +### Публічне повідомлення + +Для нечутливих проблем або тих, що вже є публічними: + +1. **Створіть GitHub Issue** з міткою `security` +2. Вкажіть: + - Назва: `[SECURITY]` з коротким описом + - Детальний опис + - Уражений файл або розділ + - Потенційний вплив + - Запропоноване виправлення + +## Процес реагування на вразливості + +### Оцінка (24 години) + +1. Ми підтверджуємо отримання повідомлення +2. Ми оцінюємо серйозність за [CVSS v3.1](https://www.first.org/cvss/v3.1/specification-document) +3. Ми визначаємо, чи входить це в область застосування +4. Ми зв'язуємося з вами з початковою оцінкою + +### Розробка (1-7 днів) + +1. Ми розробляємо виправлення +2. Ми переглядаємо та тестуємо виправлення +3. Ми створюємо рекомендацію безпеки +4. Ми готуємо нотатки до випуску + +### Розкриття (залежно від серйозності) + +**Критична (CVSS 9.0-10.0)** +- Виправлення випускається негайно +- Публічна рекомендація видається +- 24-годинне попереднє повідомлення репортерам + +**Висока (CVSS 7.0-8.9)** +- Виправлення випускається протягом 48-72 годин +- 5-денне попереднє повідомлення репортерам +- Публічна рекомендація при випуску + +**Середня (CVSS 4.0-6.9)** +- Виправлення випускається в наступному регулярному оновленні +- Публічна рекомендація при випуску + +**Низька (CVSS 0.1-3.9)** +- Виправлення включається в наступне регулярне оновлення +- Рекомендація при випуску + +### Публікація + +Ми публікуємо рекомендації безпеки, що включають: +- Опис вразливості +- Уражені компоненти +- Оцінку серйозності (CVSS-бал) +- Версію виправлення +- Обхідні рішення (якщо є) +- Подяку репортеру (з дозволу) + +## Найкращі практики для репортерів + +### Перед повідомленням + +- **Перевірте проблему**: Чи можете ви відтворити її стабільно? +- **Шукайте існуючі issues**: Чи вже повідомлено про це? +- **Перевірте документацію**: Чи є настанови щодо безпечного використання? +- **Тестуйте виправлення**: Чи працює ваше запропоноване виправлення? + +### При повідомленні + +- **Будьте конкретними**: Вказуйте точні шляхи файлів та номери рядків +- **Додавайте контекст**: Чому це проблема безпеки? +- **Покажіть вплив**: Що міг би зробити зловмисник? +- **Надайте кроки**: Як ми можемо відтворити? +- **Запропонуйте виправлення**: Як би ви це виправили? + +### Після повідомлення + +- **Будьте терплячими**: Ми маємо обмежені ресурси +- **Будьте на зв'язку**: Відповідайте на подальші запитання швидко +- **Зберігайте конфіденційність**: Не розголошуйте публічно до виправлення +- **Дотримуйтесь координації**: Слідуйте нашому графіку розкриття + +## Заголовки безпеки та конфігурація + +### Безпека репозиторію + +- **Захист гілок**: Основна гілка потребує 2 схвалень для змін +- **Статусні перевірки**: Усі CI/CD перевірки повинні пройти +- **CODEOWNERS**: Призначені рецензенти для ключових файлів +- **Підписані коміти**: Рекомендовано для контриб'юторів + +### Безпека розробки + +```bash +# Install pre-commit hooks +pre-commit install + +# Run security scans locally +bandit -c pyproject.toml -r scripts/ +mypy scripts/ --ignore-missing-imports +ruff check scripts/ +``` + +### Безпека залежностей + +```bash +# Check for known vulnerabilities +pip install safety +safety check + +# Or use pip-audit +pip install pip-audit +pip-audit +``` + +## Настанови безпеки для контриб'юторів + +### При написанні прикладів + +1. **Ніколи не захардкоджуйте секрети** + ```python + # ❌ Bad + api_key = "sk-1234567890" + + # ✅ Good + api_key = os.getenv("API_KEY") + ``` + +2. **Попереджайте про наслідки безпеки** + ```markdown + ⚠️ **Security Note**: Never commit `.env` files to git. + Add to `.gitignore` immediately. + ``` + +3. **Використовуйте безпечні значення за замовчуванням** + - Увімкнення автентифікації за замовчуванням + - Використання HTTPS де можливо + - Валідація та санітизація введення + - Використання параметризованих запитів + +4. **Документуйте міркування безпеки** + - Пояснюйте, чому безпека важлива + - Показуйте безпечні vs. небезпечні патерни + - Посилайтесь на авторитетні джерела + - Розміщуйте попередження на видному місці + +### При перегляді внесків + +1. **Перевіряйте на відкриті секрети** + - Сканування на поширені патерни (api_key=, password=) + - Перегляд конфігураційних файлів + - Перевірка змінних оточення + +2. **Перевіряйте безпечні практики кодування** + - Відсутність захардкоджених облікових даних + - Правильна валідація введення + - Безпечна автентифікація/авторизація + - Безпечна робота з файлами + +3. **Тестуйте наслідки безпеки** + - Чи можна це зловживати? + - Який найгірший сценарій? + - Чи є граничні випадки? + +## Ресурси безпеки + +### Офіційні стандарти +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [CWE Top 25](https://cwe.mitre.org/top25/) +- [CVSS Calculator](https://www.first.org/cvss/calculator/3.1) + +### Безпека Python +- [Python Security Advisories](https://www.python.org/dev/security/) +- [PyPI Security](https://pypi.org/help/#security) +- [Bandit Documentation](https://bandit.readthedocs.io/) + +### Управління залежностями +- [OWASP Dependency Check](https://owasp.org/www-project-dependency-check/) +- [GitHub Security Alerts](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) + +### Загальна безпека +- [Anthropic Security](https://www.anthropic.com/) +- [GitHub Security Best Practices](https://docs.github.com/en/code-security) + +## Архів рекомендацій безпеки + +Минулі рекомендації безпеки доступні на вкладці [GitHub Security Advisories](https://github.com/luongnv89/claude-howto/security/advisories). + +## Контакти + +Для запитань, пов'язаних з безпекою, або для обговорення практик безпеки: + +1. **Приватне повідомлення про безпеку**: Використовуйте приватне повідомлення про вразливості GitHub +2. **Загальні питання безпеки**: Відкрийте обговорення з тегом `[SECURITY]` +3. **Відгуки про політику безпеки**: Створіть issue з міткою `security` + +## Подяки + +Ми цінуємо дослідників безпеки та учасників спільноти, які допомагають підтримувати безпеку цього проєкту. Контриб'юторів, які відповідально повідомляють про вразливості, буде відзначено в наших рекомендаціях безпеки (якщо вони не бажають анонімності). + +## Оновлення політики + +Ця політика безпеки переглядається та оновлюється: +- При виявленні нових вразливостей +- При розвитку найкращих практик безпеки +- При зміні обсягу проєкту +- Щорічно як мінімум + +**Останнє оновлення**: Квітень 2026 +**Наступний перегляд**: Квітень 2027 + +--- + +Дякуємо за допомогу в забезпеченні безпеки Claude How To! 🔒 diff --git a/uk/STYLE_GUIDE.md b/uk/STYLE_GUIDE.md new file mode 100644 index 0000000..82050ac --- /dev/null +++ b/uk/STYLE_GUIDE.md @@ -0,0 +1,637 @@ + + + + + + + Claude How To + + +# Гайд зі стилю + +> Конвенції та правила форматування для внеску в Claude How To. Дотримуйтесь цього гайду, щоб тримати контент консистентним, професійним та зручним для підтримки. + +--- + +## Зміст + +- [Іменування файлів та каталогів](#іменування-файлів-та-каталогів) +- [Структура документа](#структура-документа) +- [Заголовки](#заголовки) +- [Форматування тексту](#форматування-тексту) +- [Списки](#списки) +- [Таблиці](#таблиці) +- [Блоки коду](#блоки-коду) +- [Посилання та перехресні посилання](#посилання-та-перехресні-посилання) +- [Діаграми](#діаграми) +- [Використання емодзі](#використання-емодзі) +- [YAML Frontmatter](#yaml-frontmatter) +- [Зображення та медіа](#зображення-та-медіа) +- [Тон та голос](#тон-та-голос) +- [Повідомлення комітів](#повідомлення-комітів) +- [Чеклист для авторів](#чеклист-для-авторів) + +--- + +## Іменування файлів та каталогів + +### Каталоги уроків + +Каталоги уроків використовують **двозначний числовий префікс** з **kebab-case** описом: + +``` +01-slash-commands/ +02-memory/ +03-skills/ +04-subagents/ +05-mcp/ +``` + +Номер відображає порядок навчального шляху від початківця до просунутого. + +### Імена файлів + +| Тип | Конвенція | Приклади | +|-----|-----------|---------| +| **README уроку** | `README.md` | `01-slash-commands/README.md` | +| **Файл функції** | Kebab-case `.md` | `code-reviewer.md`, `generate-api-docs.md` | +| **Shell-скрипт** | Kebab-case `.sh` | `format-code.sh`, `validate-input.sh` | +| **Конфіг-файл** | Стандартні назви | `.mcp.json`, `settings.json` | +| **Файл пам'яті** | З префіксом области | `project-CLAUDE.md`, `personal-CLAUDE.md` | +| **Документи верхнього рівня** | UPPER_CASE `.md` | `CATALOG.md`, `QUICK_REFERENCE.md`, `CONTRIBUTING.md` | +| **Зображення** | Kebab-case | `pr-slash-command.png`, `claude-howto-logo.svg` | + +### Правила + +- Використовуйте **нижній регістр** для всіх імен файлів та каталогів (крім документів верхнього рівня як `README.md`, `CATALOG.md`) +- Використовуйте **дефіси** (`-`) як розділювачі слів, ніколи підкреслення або пробіли +- Тримайте назви описовими, але стислими + +--- + +## Структура документа + +### Кореневий README + +Кореневий `README.md` дотримується порядку: + +1. Логотип (елемент `` з варіантами dark/light) +2. Заголовок H1 +3. Вступна цитата (однорядкова ціннісна пропозиція) +4. Секція "Чому цей довідник?" з таблицею порівняння +5. Горизонтальна лінія (`---`) +6. Зміст +7. Каталог функцій +8. Швидка навігація +9. Навчальний шлях +10. Секції функцій +11. Початок роботи +12. Найкращі практики / Усунення проблем +13. Внесок / Ліцензія + +### README уроку + +Кожен `README.md` уроку дотримується порядку: + +1. Заголовок H1 (напр., `# Slash Commands`) +2. Короткий вступний абзац +3. Таблиця швидкого довідника (опціонально) +4. Архітектурна діаграма (Mermaid) +5. Детальні секції (H2) +6. Практичні приклади (нумеровані, 4-6 прикладів) +7. Найкращі практики (таблиці Do's and Don'ts) +8. Усунення проблем +9. Пов'язані гайди / Офіційна документація +10. Метадані документа у футері + +### Файл функції/прикладу + +Окремі файли функцій (напр., `optimize.md`, `pr.md`): + +1. YAML frontmatter (якщо потрібно) +2. Заголовок H1 +3. Призначення / опис +4. Інструкції з використання +5. Приклади коду +6. Поради з налаштування + +### Розділювачі секцій + +Використовуйте горизонтальні лінії (`---`) для відділення основних регіонів документа: + +```markdown +--- + +## Нова основна секція +``` + +Розміщуйте їх після вступної цитати та між логічно окремими частинами документа. + +--- + +## Заголовки + +### Ієрархія + +| Рівень | Використання | Приклад | +|--------|-------------|---------| +| `#` H1 | Заголовок сторінки (один на документ) | `# Slash Commands` | +| `##` H2 | Основні секції | `## Best Practices` | +| `###` H3 | Підсекції | `### Adding a Skill` | +| `####` H4 | Під-підсекції (рідко) | `#### Configuration Options` | + +### Правила + +- **Один H1 на документ** — лише заголовок сторінки +- **Ніколи не пропускайте рівні** — не стрибайте з H2 на H4 +- **Тримайте заголовки стислими** — прагніть до 2-5 слів +- **Використовуйте sentence case** — великі літери тільки для першого слова та власних назв (виняток: назви функцій залишаються як є) +- **Додавайте емодзі-префікси тільки в кореневому README** для заголовків секцій (див. [Використання емодзі](#використання-емодзі)) + +--- + +## Форматування тексту + +### Виділення + +| Стиль | Коли використовувати | Приклад | +|-------|---------------------|---------| +| **Жирний** (`**text**`) | Ключові терміни, мітки в таблицях, важливі поняття | `**Installation**:` | +| *Курсив* (`*text*`) | Перше згадування технічного терміну, назви книг/документів | `*frontmatter*` | +| `Код` (`` `text` ``) | Імена файлів, команди, значення конфігурації, посилання на код | `` `CLAUDE.md` `` | + +### Цитати для виносок + +Використовуйте цитати з жирними префіксами для важливих нотаток: + +```markdown +> **Note**: Custom slash commands have been merged into skills since v2.0. + +> **Important**: Never commit API keys or credentials. + +> **Tip**: Combine memory with skills for maximum effectiveness. +``` + +Підтримувані типи виносок: **Note**, **Important**, **Tip**, **Warning**. + +### Абзаци + +- Тримайте абзаци короткими (2-4 речення) +- Додавайте порожній рядок між абзацами +- Починайте з ключового моменту, потім надавайте контекст +- Пояснюйте «чому», а не тільки «що» + +--- + +## Списки + +### Ненумеровані списки + +Використовуйте дефіси (`-`) з 2-пробіловим відступом для вкладеності: + +```markdown +- First item +- Second item + - Nested item + - Another nested item + - Deep nested (avoid going deeper than 3 levels) +- Third item +``` + +### Нумеровані списки + +Використовуйте нумеровані списки для послідовних кроків, інструкцій та ранжованих елементів: + +```markdown +1. First step +2. Second step + - Sub-point detail + - Another sub-point +3. Third step +``` + +### Описові списки + +Використовуйте жирні мітки для списків ключ-значення: + +```markdown +- **Performance bottlenecks** - identify O(n^2) operations, inefficient loops +- **Memory leaks** - find unreleased resources, circular references +- **Algorithm improvements** - suggest better algorithms or data structures +``` + +### Правила + +- Підтримуйте консистентні відступи (2 пробіли на рівень) +- Додавайте порожній рядок перед та після списку +- Тримайте елементи списку паралельними за структурою +- Уникайте вкладеності глибше 3 рівнів + +--- + +## Таблиці + +### Стандартний формат + +```markdown +| Column 1 | Column 2 | Column 3 | +|----------|----------|----------| +| Data | Data | Data | +``` + +### Поширені патерни таблиць + +**Порівняння функцій (3-4 колонки):** + +```markdown +| Feature | Invocation | Persistence | Best For | +|---------|-----------|------------|----------| +| **Slash Commands** | Manual (`/cmd`) | Session only | Quick shortcuts | +| **Memory** | Auto-loaded | Cross-session | Long-term learning | +``` + +**Do's and Don'ts:** + +```markdown +| Do | Don't | +|----|-------| +| Use descriptive names | Use vague names | +| Keep files focused | Overload a single file | +``` + +**Швидкий довідник:** + +```markdown +| Aspect | Details | +|--------|---------| +| **Purpose** | Generate API documentation | +| **Scope** | Project-level | +| **Complexity** | Intermediate | +``` + +### Правила + +- **Жирний для заголовків таблиці**, коли вони є мітками рядків (перша колонка) +- Вирівнюйте пайпи для читабельності у вихідному коді (опціонально, але бажано) +- Тримайте вміст комірок стислим; використовуйте посилання для деталей +- Використовуйте `форматування коду` для команд та шляхів файлів у комірках + +--- + +## Блоки коду + +### Теги мов + +Завжди вказуйте тег мови для підсвічування синтаксису: + +| Мова | Тег | Використання | +|------|-----|-------------| +| Shell | `bash` | Команди CLI, скрипти | +| Python | `python` | Код Python | +| JavaScript | `javascript` | Код JS | +| TypeScript | `typescript` | Код TS | +| JSON | `json` | Конфігураційні файли | +| YAML | `yaml` | Frontmatter, конфіг | +| Markdown | `markdown` | Приклади Markdown | +| SQL | `sql` | Запити до бази даних | +| Звичайний текст | (без тегу) | Очікуваний вивід, дерева каталогів | + +### Конвенції + +```bash +# Comment explaining what the command does +claude mcp add notion --transport http https://mcp.notion.com/mcp +``` + +- Додавайте **рядок коментаря** перед неочевидними командами +- Робіть всі приклади **готовими до копіювання та вставки** +- Показуйте **і прості, і просунуті** версії де доречно +- Включайте **очікуваний вивід** коли це допомагає розумінню (використовуйте блок коду без тегу) + +### Блоки встановлення + +Використовуйте цей патерн для інструкцій з встановлення: + +```bash +# Copy files to your project +cp 01-slash-commands/*.md .claude/commands/ +``` + +### Багатокрокові робочі процеси + +```bash +# Step 1: Create the directory +mkdir -p .claude/commands + +# Step 2: Copy the templates +cp 01-slash-commands/*.md .claude/commands/ + +# Step 3: Verify installation +ls .claude/commands/ +``` + +--- + +## Посилання та перехресні посилання + +### Внутрішні посилання (відносні) + +Використовуйте відносні шляхи для всіх внутрішніх посилань: + +```markdown +[Slash Commands](01-slash-commands/) +[Skills Guide](03-skills/) +[Memory Architecture](02-memory/#memory-architecture) +``` + +З каталогу уроку назад до кореня або сусіда: + +```markdown +[Back to main guide](../README.md) +[Related: Skills](../03-skills/) +``` + +### Зовнішні посилання (абсолютні) + +Використовуйте повні URL з описовим текстом якоря: + +```markdown +[Anthropic's official documentation](https://code.claude.com/docs/en/overview) +``` + +- Ніколи не використовуйте "click here" або "this link" як текст якоря +- Використовуйте описовий текст, що має сенс поза контекстом + +### Якорі секцій + +Посилайтесь на секції в тому ж документі за допомогою GitHub-style якорів: + +```markdown +[Feature Catalog](#-feature-catalog) +[Best Practices](#best-practices) +``` + +### Патерн пов'язаних гайдів + +Завершуйте уроки секцією пов'язаних гайдів: + +```markdown +## Related Guides + +- [Slash Commands](../01-slash-commands/) - Quick shortcuts +- [Memory](../02-memory/) - Persistent context +- [Skills](../03-skills/) - Reusable capabilities +``` + +--- + +## Діаграми + +### Mermaid + +Використовуйте Mermaid для всіх діаграм. Підтримувані типи: + +- `graph TB` / `graph LR` — архітектура, ієрархія, потік +- `sequenceDiagram` — потоки взаємодії +- `timeline` — хронологічні послідовності + +### Стильові конвенції + +Застосовуйте консистентні кольори за допомогою блоків стилів: + +```mermaid +graph TB + A["Component A"] --> B["Component B"] + B --> C["Component C"] + + style A fill:#e1f5fe,stroke:#333,color:#333 + style B fill:#fce4ec,stroke:#333,color:#333 + style C fill:#e8f5e9,stroke:#333,color:#333 +``` + +**Палітра кольорів:** + +| Колір | Hex | Використання | +|-------|-----|-------------| +| Світло-блакитний | `#e1f5fe` | Основні компоненти, входи | +| Світло-рожевий | `#fce4ec` | Обробка, проміжне ПЗ | +| Світло-зелений | `#e8f5e9` | Виходи, результати | +| Світло-жовтий | `#fff9c4` | Конфігурація, опціональне | +| Світло-фіолетовий | `#f3e5f5` | Користувацький інтерфейс | + +### Правила + +- Використовуйте `["Label text"]` для міток вузлів (дозволяє спеціальні символи) +- Використовуйте `
` для переносу рядків у мітках +- Тримайте діаграми простими (максимум 10-12 вузлів) +- Додавайте короткий текстовий опис під діаграмою для доступності +- Використовуйте зверху вниз (`TB`) для ієрархій, зліва направо (`LR`) для робочих процесів + +--- + +## Використання емодзі + +### Де використовуються емодзі + +Емодзі використовуються **рідко та цілеспрямовано** — тільки в певних контекстах: + +| Контекст | Емодзі | Приклад | +|----------|--------|---------| +| Заголовки секцій кореневого README | Іконки категорій | `## 📚 Learning Path` | +| Індикатори рівня навичок | Кольорові кола | 🟢 Початківець, 🔵 Середній, 🔴 Просунутий | +| Do's and Don'ts | Галочки/хрестики | ✅ Робіть це, ❌ Не робіть це | +| Рейтинги складності | Зірки | ⭐⭐⭐ | + +### Стандартний набір емодзі + +| Емодзі | Значення | +|--------|---------| +| 📚 | Навчання, гайди, документація | +| ⚡ | Початок роботи, швидкий довідник | +| 🎯 | Функції, швидкий довідник | +| 🎓 | Навчальні шляхи | +| 📊 | Статистика, порівняння | +| 🚀 | Встановлення, швидкі команди | +| 🟢 | Рівень початківця | +| 🔵 | Середній рівень | +| 🔴 | Просунутий рівень | +| ✅ | Рекомендована практика | +| ❌ | Уникати / анти-патерн | +| ⭐ | Одиниця рейтингу складності | + +### Правила + +- **Ніколи не використовуйте емодзі в основному тексті** або абзацах +- **Використовуйте емодзі в заголовках тільки** в кореневому README (не в README уроків) +- **Не додавайте декоративних емодзі** — кожне емодзі повинно нести значення +- Тримайте використання емодзі консистентним з таблицею вище + +--- + +## YAML Frontmatter + +### Файли функцій (навички, команди, агенти) + +```yaml +--- +name: unique-identifier +description: What this feature does and when to use it +allowed-tools: Bash, Read, Grep +--- +``` + +### Опціональні поля + +```yaml +--- +name: my-feature +description: Brief description +argument-hint: "[file-path] [options]" +allowed-tools: Bash, Read, Grep, Write, Edit +model: opus # opus, sonnet, or haiku +disable-model-invocation: true # User-only invocation +user-invocable: false # Hidden from user menu +context: fork # Run in isolated subagent +agent: Explore # Agent type for context: fork +--- +``` + +### Правила + +- Розміщуйте frontmatter на самому початку файлу +- Використовуйте **kebab-case** для поля `name` +- Тримайте `description` в одне речення +- Включайте тільки необхідні поля + +--- + +## Зображення та медіа + +### Патерн логотипу + +Усі документи, що починаються з логотипу, використовують елемент `` для підтримки dark/light режимів: + +```html + + + Claude How To + +``` + +### Скріншоти + +- Зберігайте у відповідному каталозі уроку (напр., `01-slash-commands/pr-slash-command.png`) +- Використовуйте kebab-case імена файлів +- Включайте описовий alt-текст +- Віддавайте перевагу SVG для діаграм, PNG для скріншотів + +### Правила + +- Завжди вказуйте alt-текст для зображень +- Тримайте розмір файлів зображень розумним (< 500KB для PNG) +- Використовуйте відносні шляхи для посилань на зображення +- Зберігайте зображення в тому ж каталозі, що й документ, який на них посилається, або в `assets/` для спільних зображень + +--- + +## Тон та голос + +### Стиль написання + +- **Професійний, але доступний** — технічна точність без перевантаження жаргоном +- **Активний стан** — "Create a file", а не "A file should be created" +- **Прямі інструкції** — "Run this command", а не "You might want to run this command" +- **Дружній до початківців** — припускаємо, що читач новий у Claude Code, але не новий у програмуванні + +### Принципи контенту + +| Принцип | Приклад | +|---------|---------| +| **Показуйте, а не розповідайте** | Надавайте працюючі приклади, а не абстрактні описи | +| **Прогресивна складність** | Починайте просто, додавайте глибину в наступних секціях | +| **Пояснюйте «чому»** | "Use memory for... because...", а не просто "Use memory for..." | +| **Готове до копіювання** | Кожен блок коду повинен працювати при безпосередній вставці | +| **Реальний контекст** | Використовуйте практичні сценарії, а не штучні приклади | + +### Словник + +- Використовуйте "Claude Code" (не "Claude CLI" або "the tool") +- Використовуйте "skill" (не "custom command" — застарілий термін) +- Використовуйте "lesson" або "guide" для нумерованих секцій +- Використовуйте "example" для окремих файлів функцій + +--- + +## Повідомлення комітів + +Дотримуйтесь [Conventional Commits](https://www.conventionalcommits.org/): + +``` +type(scope): description +``` + +### Типи + +| Тип | Використання | +|-----|-------------| +| `feat` | Нова функція, приклад або гайд | +| `fix` | Виправлення помилки, корекція, зламане посилання | +| `docs` | Покращення документації | +| `refactor` | Реструктуризація без зміни поведінки | +| `style` | Тільки зміни форматування | +| `test` | Додавання або зміни тестів | +| `chore` | Збірка, залежності, CI | + +### Скоупи + +Використовуйте назву уроку або області файлу як скоуп: + +``` +feat(slash-commands): Add API documentation generator +docs(memory): Improve personal preferences example +fix(README): Correct table of contents link +docs(skills): Add comprehensive code review skill +``` + +--- + +## Метадані документа у футері + +README уроків завершуються блоком метаданих: + +```markdown +--- +**Last Updated**: March 2026 +**Claude Code Version**: 2.1.97 +**Compatible Models**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 +``` + +- Використовуйте формат місяць + рік (напр., "March 2026") +- Оновлюйте версію при зміні функцій +- Перелічуйте всі сумісні моделі + +--- + +## Чеклист для авторів + +Перед відправкою контенту перевірте: + +- [ ] Імена файлів/каталогів використовують kebab-case +- [ ] Документ починається з заголовку H1 (один на файл) +- [ ] Ієрархія заголовків коректна (без пропущених рівнів) +- [ ] Усі блоки коду мають теги мов +- [ ] Приклади коду готові до копіювання та вставки +- [ ] Внутрішні посилання використовують відносні шляхи +- [ ] Зовнішні посилання мають описовий текст якоря +- [ ] Таблиці правильно відформатовані +- [ ] Емодзі відповідають стандартному набору (якщо використовуються) +- [ ] Mermaid-діаграми використовують стандартну палітру кольорів +- [ ] Немає чутливої інформації (API-ключі, облікові дані) +- [ ] YAML frontmatter валідний (якщо використовується) +- [ ] Зображення мають alt-текст +- [ ] Абзаци короткі та зосереджені +- [ ] Секція пов'язаних гайдів посилається на відповідні уроки +- [ ] Повідомлення коміту відповідає формату conventional commits + +--- +**Останнє оновлення**: Квітень 2026 diff --git a/uk/TRANSLATION_QUEUE.md b/uk/TRANSLATION_QUEUE.md index 179040b..f49043e 100644 --- a/uk/TRANSLATION_QUEUE.md +++ b/uk/TRANSLATION_QUEUE.md @@ -2,9 +2,9 @@ # Прогрес перекладу українською -**Загальний прогрес:** 5/67 файлів (7%) +**Загальний прогрес:** 15/67 файлів (22%) -**Статус:** 🚧 В ПРОЦЕСІ — P1 ядро завершено ✅ +**Статус:** 🚧 В ПРОЦЕСІ — P1 ядро ✅ P2 модулі ✅ ## Пріоритет 1 — Ядро (5 файлів) ✅ @@ -22,18 +22,18 @@ | Модуль | Рядків | Статус | Дата | |--------|--------|--------|------| -| 01 slash-commands | 565 | ⏳ | | -| 02 memory | 1156 | ⏳ | | -| 03 skills | 811 | ⏳ | | -| 04 subagents | 1142 | ⏳ | | -| 05 mcp | 1113 | ⏳ | | -| 06 hooks | 1170 | ⏳ | | -| 07 plugins | 949 | ⏳ | | -| 08 checkpoints | 320 | ⏳ | | -| 09 advanced | 1945 | ⏳ | | -| 10 cli | 837 | ⏳ | | +| 01 slash-commands | 565 | ✅ | 2026-04-09 | +| 02 memory | 1156 | ✅ | 2026-04-09 | +| 03 skills | 811 | ✅ | 2026-04-09 | +| 04 subagents | 1142 | ✅ | 2026-04-09 | +| 05 mcp | 1113 | ✅ | 2026-04-09 | +| 06 hooks | 1170 | ✅ | 2026-04-09 | +| 07 plugins | 949 | ✅ | 2026-04-09 | +| 08 checkpoints | 320 | ✅ | 2026-04-09 | +| 09 advanced | 1945 | ✅ | 2026-04-09 | +| 10 cli | 837 | ✅ | 2026-04-09 | -**Прогрес P2:** 0/10 (0%) +**Прогрес P2:** 10/10 (100%) ✅ ## Пріоритет 3 — Приклади (47 файлів) · P4 — Допоміжні (5 файлів) From f5659be0476de396246c0027274f7f2f348ec4a0 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 00:13:13 +0300 Subject: [PATCH 13/20] i18n(uk): translate 07-plugins devops-automation & documentation - Translate READMEs, commands, agents for both plugins - Code/config/hooks files unchanged (no translation needed) Ref: luongnv89/claude-howto#63 --- uk/07-plugins/devops-automation/README.md | 100 +++++++-------- .../agents/alert-analyzer.md | 16 +-- .../agents/deployment-specialist.md | 16 +-- .../agents/incident-commander.md | 16 +-- .../devops-automation/commands/deploy.md | 18 +-- .../devops-automation/commands/incident.md | 20 +-- .../devops-automation/commands/rollback.md | 16 +-- .../devops-automation/commands/status.md | 18 +-- uk/07-plugins/documentation/README.md | 118 +++++++++--------- .../documentation/agents/api-documenter.md | 16 +-- .../documentation/agents/code-commentator.md | 16 +-- .../documentation/agents/example-generator.md | 16 +-- .../commands/generate-api-docs.md | 18 +-- .../documentation/commands/generate-readme.md | 18 +-- .../documentation/commands/sync-docs.md | 16 +-- .../documentation/commands/validate-docs.md | 16 +-- 16 files changed, 227 insertions(+), 227 deletions(-) diff --git a/uk/07-plugins/devops-automation/README.md b/uk/07-plugins/devops-automation/README.md index d0226bd..652b380 100644 --- a/uk/07-plugins/devops-automation/README.md +++ b/uk/07-plugins/devops-automation/README.md @@ -3,105 +3,105 @@ Claude How To -# DevOps Automation Plugin +# Плагін DevOps Automation -Complete DevOps automation for deployment, monitoring, and incident response. +Повна автоматизація DevOps для розгортання, моніторингу та реагування на інциденти. -## Features +## Функції -✅ Automated deployments -✅ Rollback procedures -✅ System health monitoring -✅ Incident response workflows -✅ Kubernetes integration +✅ Автоматизовані розгортання +✅ Процедури відкату +✅ Моніторинг стану системи +✅ Робочі процеси реагування на інциденти +✅ Інтеграція з Kubernetes -## Installation +## Встановлення ```bash /plugin install devops-automation ``` -## What's Included +## Що включено -### Slash Commands -- `/deploy` - Deploy to production or staging -- `/rollback` - Rollback to previous version -- `/status` - Check system health -- `/incident` - Handle production incidents +### Слеш-команди +- `/deploy` — Розгортання на продакшен або стейджинг +- `/rollback` — Відкат до попередньої версії +- `/status` — Перевірка стану системи +- `/incident` — Обробка інцидентів на продакшені -### Subagents -- `deployment-specialist` - Deployment operations -- `incident-commander` - Incident coordination -- `alert-analyzer` - System health analysis +### Субагенти +- `deployment-specialist` — Операції розгортання +- `incident-commander` — Координація інцидентів +- `alert-analyzer` — Аналіз стану системи -### MCP Servers -- Kubernetes integration +### MCP-сервери +- Інтеграція з Kubernetes -### Scripts -- `deploy.sh` - Deployment automation -- `rollback.sh` - Rollback automation -- `health-check.sh` - Health check utilities +### Скрипти +- `deploy.sh` — Автоматизація розгортання +- `rollback.sh` — Автоматизація відкату +- `health-check.sh` — Утиліти перевірки стану -### Hooks -- `pre-deploy.js` - Pre-deployment validation -- `post-deploy.js` - Post-deployment tasks +### Хуки +- `pre-deploy.js` — Передрозгортальна валідація +- `post-deploy.js` — Післярозгортальні завдання -## Usage +## Використання -### Deploy to Staging +### Розгортання на стейджинг ``` /deploy staging ``` -### Deploy to Production +### Розгортання на продакшен ``` /deploy production ``` -### Rollback +### Відкат ``` /rollback production ``` -### Check Status +### Перевірка стану ``` /status ``` -### Handle Incident +### Обробка інциденту ``` /incident ``` -## Requirements +## Вимоги - Claude Code 1.0+ - Kubernetes CLI (kubectl) -- Cluster access configured +- Налаштований доступ до кластера -## Configuration +## Конфігурація -Set up your Kubernetes config: +Налаштуйте конфіг Kubernetes: ```bash export KUBECONFIG=~/.kube/config ``` -## Example Workflow +## Приклад робочого процесу ``` User: /deploy production Claude: -1. Runs pre-deploy hook (validates kubectl, cluster connection) -2. Delegates to deployment-specialist subagent -3. Runs deploy.sh script -4. Monitors deployment progress via Kubernetes MCP -5. Runs post-deploy hook (waits for pods, smoke tests) -6. Provides deployment summary +1. Запускає pre-deploy хук (валідація kubectl, з'єднання з кластером) +2. Делегує субагенту deployment-specialist +3. Запускає скрипт deploy.sh +4. Моніторить прогрес розгортання через Kubernetes MCP +5. Запускає post-deploy хук (очікування подів, smoke-тести) +6. Надає підсумок розгортання -Result: -✅ Deployment complete -📦 Version: v2.1.0 -🚀 Pods: 3/3 ready -⏱️ Time: 2m 34s +Результат: +✅ Розгортання завершено +📦 Версія: v2.1.0 +🚀 Поди: 3/3 готові +⏱️ Час: 2хв 34с ``` diff --git a/uk/07-plugins/devops-automation/agents/alert-analyzer.md b/uk/07-plugins/devops-automation/agents/alert-analyzer.md index d455e24..cea8b9f 100644 --- a/uk/07-plugins/devops-automation/agents/alert-analyzer.md +++ b/uk/07-plugins/devops-automation/agents/alert-analyzer.md @@ -1,14 +1,14 @@ --- name: alert-analyzer -description: Analyzes monitoring alerts and system metrics +description: Аналізує алерти моніторингу та метрики системи tools: read, grep, bash --- -# Alert Analyzer +# Аналізатор алертів -Analyzes system health and alerts: -- Alert correlation -- Trend analysis -- Root cause identification -- Metric visualization -- Proactive issue detection +Аналізує стан системи та алерти: +- Кореляція алертів +- Аналіз трендів +- Визначення першопричини +- Візуалізація метрик +- Проактивне виявлення проблем diff --git a/uk/07-plugins/devops-automation/agents/deployment-specialist.md b/uk/07-plugins/devops-automation/agents/deployment-specialist.md index 47fe3f7..4871c26 100644 --- a/uk/07-plugins/devops-automation/agents/deployment-specialist.md +++ b/uk/07-plugins/devops-automation/agents/deployment-specialist.md @@ -1,14 +1,14 @@ --- name: deployment-specialist -description: Handles all deployment operations +description: Обробляє всі операції розгортання tools: read, write, bash, grep --- -# Deployment Specialist +# Спеціаліст з розгортання -Expert in deployment operations: -- Blue-green deployments -- Canary releases -- Rollback procedures -- Health checks -- Database migrations +Експерт з операцій розгортання: +- Blue-green розгортання +- Канаркові релізи +- Процедури відкату +- Перевірки стану +- Міграції бази даних diff --git a/uk/07-plugins/devops-automation/agents/incident-commander.md b/uk/07-plugins/devops-automation/agents/incident-commander.md index d73929c..4610d7a 100644 --- a/uk/07-plugins/devops-automation/agents/incident-commander.md +++ b/uk/07-plugins/devops-automation/agents/incident-commander.md @@ -1,14 +1,14 @@ --- name: incident-commander -description: Coordinates incident response +description: Координує реагування на інциденти tools: read, write, bash, grep --- -# Incident Commander +# Командир інцидентів -Manages incident response: -- Severity assessment -- Team coordination -- Status updates -- Resolution tracking -- Post-mortem facilitation +Керує реагуванням на інциденти: +- Оцінка серйозності +- Координація команди +- Оновлення статусу +- Відстеження розв'язання +- Фасилітація post-mortem diff --git a/uk/07-plugins/devops-automation/commands/deploy.md b/uk/07-plugins/devops-automation/commands/deploy.md index 4873ca3..e8a5dba 100644 --- a/uk/07-plugins/devops-automation/commands/deploy.md +++ b/uk/07-plugins/devops-automation/commands/deploy.md @@ -1,15 +1,15 @@ --- name: Deploy -description: Deploy application to production or staging +description: Розгортання застосунку на продакшен або стейджинг --- -# Deploy Application +# Розгортання застосунку -Execute deployment workflow: +Виконання робочого процесу розгортання: -1. Run pre-deployment checks -2. Build application -3. Run tests -4. Deploy to target environment -5. Run health checks -6. Notify team on Slack +1. Запуск передрозгортальних перевірок +2. Збірка застосунку +3. Запуск тестів +4. Розгортання на цільове середовище +5. Запуск перевірок стану +6. Повідомлення команди в Slack diff --git a/uk/07-plugins/devops-automation/commands/incident.md b/uk/07-plugins/devops-automation/commands/incident.md index b5c0459..a20dbd3 100644 --- a/uk/07-plugins/devops-automation/commands/incident.md +++ b/uk/07-plugins/devops-automation/commands/incident.md @@ -1,16 +1,16 @@ --- name: Incident Response -description: Handle production incidents with structured response +description: Обробка інцидентів на продакшені зі структурованим реагуванням --- -# Incident Response +# Реагування на інциденти -Structured incident response workflow: +Структурований процес реагування на інциденти: -1. Create incident record -2. Assess severity and impact -3. Notify on-call team -4. Gather diagnostic information -5. Coordinate response efforts -6. Document resolution -7. Schedule post-mortem +1. Створення запису інциденту +2. Оцінка серйозності та впливу +3. Повідомлення чергової команди +4. Збір діагностичної інформації +5. Координація зусиль з реагування +6. Документування розв'язання +7. Планування post-mortem diff --git a/uk/07-plugins/devops-automation/commands/rollback.md b/uk/07-plugins/devops-automation/commands/rollback.md index 2eb20a3..d8998b2 100644 --- a/uk/07-plugins/devops-automation/commands/rollback.md +++ b/uk/07-plugins/devops-automation/commands/rollback.md @@ -1,14 +1,14 @@ --- name: Rollback -description: Rollback to previous deployment +description: Відкат до попереднього розгортання --- -# Rollback Deployment +# Відкат розгортання -Rollback to previous stable version: +Відкат до попередньої стабільної версії: -1. Identify previous deployment -2. Verify rollback target is healthy -3. Execute rollback procedure -4. Run health checks -5. Notify team +1. Визначення попереднього розгортання +2. Перевірка працездатності цілі відкату +3. Виконання процедури відкату +4. Запуск перевірок стану +5. Повідомлення команди diff --git a/uk/07-plugins/devops-automation/commands/status.md b/uk/07-plugins/devops-automation/commands/status.md index 6c2e670..3b8b2a7 100644 --- a/uk/07-plugins/devops-automation/commands/status.md +++ b/uk/07-plugins/devops-automation/commands/status.md @@ -1,15 +1,15 @@ --- name: System Status -description: Check overall system health and status +description: Перевірка загального стану та працездатності системи --- -# System Status Check +# Перевірка стану системи -Check system health across all services: +Перевірка стану системи по всіх сервісах: -1. Query Kubernetes pod status -2. Check database connections -3. Monitor API response times -4. Review error rates -5. Check resource utilization -6. Report overall health +1. Запит статусу подів Kubernetes +2. Перевірка з'єднань з базою даних +3. Моніторинг часу відповіді API +4. Перегляд частоти помилок +5. Перевірка використання ресурсів +6. Звіт про загальний стан diff --git a/uk/07-plugins/documentation/README.md b/uk/07-plugins/documentation/README.md index 0934147..2f07044 100644 --- a/uk/07-plugins/documentation/README.md +++ b/uk/07-plugins/documentation/README.md @@ -3,117 +3,117 @@ Claude How To
-# Documentation Plugin +# Плагін Documentation -Comprehensive documentation generation and maintenance for your project. +Комплексна генерація та підтримка документації для вашого проєкту. -## Features +## Функції -✅ API documentation generation -✅ README creation and updates -✅ Documentation synchronization -✅ Code comment improvements -✅ Example generation +✅ Генерація API-документації +✅ Створення та оновлення README +✅ Синхронізація документації +✅ Покращення коментарів коду +✅ Генерація прикладів -## Installation +## Встановлення ```bash /plugin install documentation ``` -## What's Included +## Що включено -### Slash Commands -- `/generate-api-docs` - Generate API documentation -- `/generate-readme` - Create or update README -- `/sync-docs` - Sync docs with code changes -- `/validate-docs` - Validate documentation +### Слеш-команди +- `/generate-api-docs` — Генерація API-документації +- `/generate-readme` — Створення або оновлення README +- `/sync-docs` — Синхронізація документації зі змінами коду +- `/validate-docs` — Валідація документації -### Subagents -- `api-documenter` - API documentation specialist -- `code-commentator` - Code comment improvements -- `example-generator` - Code example creation +### Субагенти +- `api-documenter` — Спеціаліст з API-документації +- `code-commentator` — Покращення коментарів коду +- `example-generator` — Створення прикладів коду -### Templates -- `api-endpoint.md` - API endpoint documentation template -- `function-docs.md` - Function documentation template -- `adr-template.md` - Architecture Decision Record template +### Шаблони +- `api-endpoint.md` — Шаблон документації ендпоінту API +- `function-docs.md` — Шаблон документації функції +- `adr-template.md` — Шаблон Architecture Decision Record -### MCP Servers -- GitHub integration for documentation syncing +### MCP-сервери +- Інтеграція з GitHub для синхронізації документації -## Usage +## Використання -### Generate API Documentation +### Генерація API-документації ``` /generate-api-docs ``` -### Create README +### Створення README ``` /generate-readme ``` -### Sync Documentation +### Синхронізація документації ``` /sync-docs ``` -### Validate Documentation +### Валідація документації ``` /validate-docs ``` -## Requirements +## Вимоги - Claude Code 1.0+ -- GitHub access (optional) +- Доступ до GitHub (опціонально) -## Example Workflow +## Приклад робочого процесу ``` User: /generate-api-docs Claude: -1. Scans all API endpoints in /src/api/ -2. Delegates to api-documenter subagent -3. Extracts function signatures and JSDoc -4. Organizes by module/endpoint -5. Uses api-endpoint.md template -6. Generates comprehensive markdown docs -7. Includes curl, JavaScript, and Python examples +1. Сканує всі API-ендпоінти в /src/api/ +2. Делегує субагенту api-documenter +3. Витягує сигнатури функцій та JSDoc +4. Організує за модулями/ендпоінтами +5. Використовує шаблон api-endpoint.md +6. Генерує комплексну markdown-документацію +7. Включає приклади curl, JavaScript та Python -Result: -✅ API documentation generated -📄 Files created: +Результат: +✅ API-документація згенерована +📄 Створені файли: - docs/api/users.md - docs/api/auth.md - docs/api/products.md -📊 Coverage: 23/23 endpoints documented +📊 Покриття: 23/23 ендпоінти задокументовано ``` -## Templates Usage +## Використання шаблонів -### API Endpoint Template -Use for documenting REST API endpoints with full examples. +### Шаблон ендпоінту API +Використовуйте для документування REST API ендпоінтів з повними прикладами. -### Function Documentation Template -Use for documenting individual functions/methods. +### Шаблон документації функції +Використовуйте для документування окремих функцій/методів. -### ADR Template -Use for documenting architectural decisions. +### Шаблон ADR +Використовуйте для документування архітектурних рішень. -## Configuration +## Конфігурація -Set up GitHub token for documentation syncing: +Налаштуйте GitHub-токен для синхронізації документації: ```bash export GITHUB_TOKEN="your_github_token" ``` -## Best Practices +## Найкращі практики -- Keep documentation close to code -- Update docs with code changes -- Include practical examples -- Validate regularly -- Use templates for consistency +- Тримайте документацію близько до коду +- Оновлюйте документацію разом зі змінами коду +- Включайте практичні приклади +- Регулярно валідуйте +- Використовуйте шаблони для консистентності diff --git a/uk/07-plugins/documentation/agents/api-documenter.md b/uk/07-plugins/documentation/agents/api-documenter.md index 487c5a4..50848fc 100644 --- a/uk/07-plugins/documentation/agents/api-documenter.md +++ b/uk/07-plugins/documentation/agents/api-documenter.md @@ -1,14 +1,14 @@ --- name: api-documenter -description: API documentation specialist +description: Спеціаліст з API-документації tools: read, write, grep --- -# API Documenter +# API-документатор -Creates comprehensive API documentation: -- Endpoint documentation -- Parameter descriptions -- Response schemas -- Code examples (curl, JS, Python) -- Error codes +Створює комплексну API-документацію: +- Документація ендпоінтів +- Описи параметрів +- Схеми відповідей +- Приклади коду (curl, JS, Python) +- Коди помилок diff --git a/uk/07-plugins/documentation/agents/code-commentator.md b/uk/07-plugins/documentation/agents/code-commentator.md index a039443..9d01e52 100644 --- a/uk/07-plugins/documentation/agents/code-commentator.md +++ b/uk/07-plugins/documentation/agents/code-commentator.md @@ -1,14 +1,14 @@ --- name: code-commentator -description: Code comment and inline documentation specialist +description: Спеціаліст з коментарів коду та інлайн-документації tools: read, write, edit --- -# Code Commentator +# Коментатор коду -Improves code documentation: -- JSDoc/docstring comments -- Inline explanations -- Parameter descriptions -- Return type documentation -- Usage examples +Покращує документацію коду: +- JSDoc/docstring коментарі +- Інлайн-пояснення +- Описи параметрів +- Документація типів повернення +- Приклади використання diff --git a/uk/07-plugins/documentation/agents/example-generator.md b/uk/07-plugins/documentation/agents/example-generator.md index 1cd1c7e..59a5800 100644 --- a/uk/07-plugins/documentation/agents/example-generator.md +++ b/uk/07-plugins/documentation/agents/example-generator.md @@ -1,14 +1,14 @@ --- name: example-generator -description: Code example and tutorial specialist +description: Спеціаліст з прикладів коду та туторіалів tools: read, write --- -# Example Generator +# Генератор прикладів -Creates practical code examples: -- Getting started guides -- Common use cases -- Integration examples -- Best practices -- Troubleshooting scenarios +Створює практичні приклади коду: +- Гайди початку роботи +- Поширені сценарії використання +- Приклади інтеграції +- Найкращі практики +- Сценарії усунення проблем diff --git a/uk/07-plugins/documentation/commands/generate-api-docs.md b/uk/07-plugins/documentation/commands/generate-api-docs.md index a5bda46..4ca0f77 100644 --- a/uk/07-plugins/documentation/commands/generate-api-docs.md +++ b/uk/07-plugins/documentation/commands/generate-api-docs.md @@ -1,15 +1,15 @@ --- name: Generate API Documentation -description: Generate comprehensive API documentation from source code +description: Генерація комплексної API-документації з вихідного коду --- -# API Documentation Generator +# Генератор API-документації -Generate complete API documentation: +Генерація повної API-документації: -1. Scan API endpoints -2. Extract function signatures and JSDoc -3. Organize by module/endpoint -4. Create markdown with examples -5. Include request/response schemas -6. Add error documentation +1. Сканування API-ендпоінтів +2. Витягування сигнатур функцій та JSDoc +3. Організація за модулями/ендпоінтами +4. Створення markdown з прикладами +5. Включення схем запитів/відповідей +6. Додавання документації помилок diff --git a/uk/07-plugins/documentation/commands/generate-readme.md b/uk/07-plugins/documentation/commands/generate-readme.md index 119310a..23e8e60 100644 --- a/uk/07-plugins/documentation/commands/generate-readme.md +++ b/uk/07-plugins/documentation/commands/generate-readme.md @@ -1,15 +1,15 @@ --- name: Generate README -description: Create or update project README +description: Створення або оновлення README проєкту --- -# README Generator +# Генератор README -Generate comprehensive README: +Генерація комплексного README: -1. Project overview and description -2. Installation instructions -3. Usage examples -4. API documentation links -5. Contributing guidelines -6. License information +1. Огляд та опис проєкту +2. Інструкції з встановлення +3. Приклади використання +4. Посилання на API-документацію +5. Настанови для контриб'юторів +6. Інформація про ліцензію diff --git a/uk/07-plugins/documentation/commands/sync-docs.md b/uk/07-plugins/documentation/commands/sync-docs.md index 9681cc8..795966d 100644 --- a/uk/07-plugins/documentation/commands/sync-docs.md +++ b/uk/07-plugins/documentation/commands/sync-docs.md @@ -1,14 +1,14 @@ --- name: Sync Documentation -description: Sync documentation with code changes +description: Синхронізація документації зі змінами коду --- -# Documentation Sync +# Синхронізація документації -Synchronize documentation with codebase: +Синхронізація документації з кодовою базою: -1. Detect code changes -2. Identify outdated documentation -3. Update affected docs -4. Verify examples still work -5. Update version numbers +1. Виявлення змін коду +2. Визначення застарілої документації +3. Оновлення уражених документів +4. Перевірка працездатності прикладів +5. Оновлення номерів версій diff --git a/uk/07-plugins/documentation/commands/validate-docs.md b/uk/07-plugins/documentation/commands/validate-docs.md index bd41f57..a5186db 100644 --- a/uk/07-plugins/documentation/commands/validate-docs.md +++ b/uk/07-plugins/documentation/commands/validate-docs.md @@ -1,14 +1,14 @@ --- name: Validate Documentation -description: Validate documentation for completeness and accuracy +description: Валідація документації на повноту та точність --- -# Documentation Validation +# Валідація документації -Validate documentation quality: +Перевірка якості документації: -1. Check for broken links -2. Verify code examples -3. Ensure completeness -4. Check formatting -5. Validate against actual code +1. Перевірка на зламані посилання +2. Верифікація прикладів коду +3. Забезпечення повноти +4. Перевірка форматування +5. Валідація відповідності реальному коду From 8438a0378ac22f8e6a9e6ca2720abfebd6132710 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 00:16:09 +0300 Subject: [PATCH 14/20] i18n(uk): complete P3 examples + P4 root docs translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate 07-plugins: devops-automation, documentation, pr-review (READMEs, commands, agents, templates) - Update TRANSLATION_QUEUE.md — all priorities complete (100%) Ref: luongnv89/claude-howto#63 --- .../documentation/templates/adr-template.md | 56 ++++++------ .../documentation/templates/api-endpoint.md | 42 ++++----- .../documentation/templates/function-docs.md | 50 +++++------ uk/07-plugins/pr-review/README.md | 88 +++++++++---------- .../pr-review/agents/performance-analyzer.md | 14 +-- .../pr-review/agents/security-reviewer.md | 14 +-- .../pr-review/agents/test-checker.md | 14 +-- .../pr-review/commands/check-security.md | 16 ++-- .../pr-review/commands/check-tests.md | 16 ++-- uk/07-plugins/pr-review/commands/review-pr.md | 16 ++-- uk/TRANSLATION_QUEUE.md | 38 ++++++-- 11 files changed, 193 insertions(+), 171 deletions(-) diff --git a/uk/07-plugins/documentation/templates/adr-template.md b/uk/07-plugins/documentation/templates/adr-template.md index 8cc3fc3..e8ff079 100644 --- a/uk/07-plugins/documentation/templates/adr-template.md +++ b/uk/07-plugins/documentation/templates/adr-template.md @@ -1,39 +1,39 @@ -# ADR [Number]: [Title] +# ADR [Номер]: [Назва] -## Status -[Proposed | Accepted | Deprecated | Superseded] +## Статус +[Запропоновано | Прийнято | Застаріло | Замінено] -## Context -What is the issue that we're seeing that is motivating this decision or change? +## Контекст +Яка проблема спонукає це рішення або зміну? -## Decision -What is the change that we're proposing and/or doing? +## Рішення +Яку зміну ми пропонуємо та/або впроваджуємо? -## Consequences -What becomes easier or more difficult to do because of this change? +## Наслідки +Що стає простішим або складнішим через цю зміну? -### Positive -- Benefit 1 -- Benefit 2 +### Позитивні +- Перевага 1 +- Перевага 2 -### Negative -- Drawback 1 -- Drawback 2 +### Негативні +- Недолік 1 +- Недолік 2 -### Neutral -- Consideration 1 -- Consideration 2 +### Нейтральні +- Міркування 1 +- Міркування 2 -## Alternatives Considered -What other options were considered and why were they not chosen? +## Розглянуті альтернативи +Які інші варіанти було розглянуто та чому їх не обрано? -### Alternative 1 -Description and reason for not choosing. +### Альтернатива 1 +Опис та причина відхилення. -### Alternative 2 -Description and reason for not choosing. +### Альтернатива 2 +Опис та причина відхилення. -## References -- Related ADRs -- External documentation -- Discussion links +## Посилання +- Пов'язані ADR +- Зовнішня документація +- Посилання на обговорення diff --git a/uk/07-plugins/documentation/templates/api-endpoint.md b/uk/07-plugins/documentation/templates/api-endpoint.md index 33c3996..f6ecb89 100644 --- a/uk/07-plugins/documentation/templates/api-endpoint.md +++ b/uk/07-plugins/documentation/templates/api-endpoint.md @@ -1,32 +1,32 @@ # [METHOD] /api/v1/[endpoint] -## Description -Brief explanation of what this endpoint does. +## Опис +Короткий опис що робить цей ендпоінт. -## Authentication -Required authentication method (e.g., Bearer token). +## Автентифікація +Необхідний метод автентифікації (напр., Bearer token). -## Parameters +## Параметри -### Path Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| id | string | Yes | Resource ID | +### Параметри шляху +| Назва | Тип | Обов'язковий | Опис | +|-------|-----|-------------|------| +| id | string | Так | ID ресурсу | -### Query Parameters -| Name | Type | Required | Description | -|------|------|----------|-------------| -| page | integer | No | Page number (default: 1) | -| limit | integer | No | Items per page (default: 20) | +### Параметри запиту +| Назва | Тип | Обов'язковий | Опис | +|-------|-----|-------------|------| +| page | integer | Ні | Номер сторінки (за замовч.: 1) | +| limit | integer | Ні | Елементів на сторінку (за замовч.: 20) | -### Request Body +### Тіло запиту ```json { "field": "value" } ``` -## Responses +## Відповіді ### 200 OK ```json @@ -61,7 +61,7 @@ Required authentication method (e.g., Bearer token). } ``` -## Examples +## Приклади ### cURL ```bash @@ -92,10 +92,10 @@ response = requests.get( data = response.json() ``` -## Rate Limits -- 1000 requests per hour for authenticated users -- 100 requests per hour for public endpoints +## Обмеження частоти запитів +- 1000 запитів на годину для автентифікованих користувачів +- 100 запитів на годину для публічних ендпоінтів -## Related Endpoints +## Пов'язані ендпоінти - [GET /api/v1/related](#) - [POST /api/v1/related](#) diff --git a/uk/07-plugins/documentation/templates/function-docs.md b/uk/07-plugins/documentation/templates/function-docs.md index b1e137d..2b312d1 100644 --- a/uk/07-plugins/documentation/templates/function-docs.md +++ b/uk/07-plugins/documentation/templates/function-docs.md @@ -1,38 +1,38 @@ -# Function: `functionName` +# Функція: `functionName` -## Description -Brief description of what the function does. +## Опис +Короткий опис що робить функція. -## Signature +## Сигнатура ```typescript function functionName(param1: Type1, param2: Type2): ReturnType ``` -## Parameters +## Параметри -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| param1 | Type1 | Yes | Description of param1 | -| param2 | Type2 | No | Description of param2 | +| Параметр | Тип | Обов'язковий | Опис | +|----------|-----|-------------|------| +| param1 | Type1 | Так | Опис param1 | +| param2 | Type2 | Ні | Опис param2 | -## Returns -**Type**: `ReturnType` +## Повертає +**Тип**: `ReturnType` -Description of what is returned. +Опис того, що повертається. -## Throws -- `Error`: When invalid input is provided -- `TypeError`: When wrong type is passed +## Кидає виключення +- `Error`: При невалідному введенні +- `TypeError`: При неправильному типі -## Examples +## Приклади -### Basic Usage +### Базове використання ```typescript const result = functionName('value1', 'value2'); console.log(result); ``` -### Advanced Usage +### Просунуте використання ```typescript const result = functionName( complexParam1, @@ -40,11 +40,11 @@ const result = functionName( ); ``` -## Notes -- Additional notes or warnings -- Performance considerations -- Best practices +## Нотатки +- Додаткові нотатки або попередження +- Міркування щодо продуктивності +- Найкращі практики -## See Also -- [Related Function](#) -- [API Documentation](#) +## Див. також +- [Пов'язана функція](#) +- [API-документація](#) diff --git a/uk/07-plugins/pr-review/README.md b/uk/07-plugins/pr-review/README.md index 9fe1c3b..1c0aa9c 100644 --- a/uk/07-plugins/pr-review/README.md +++ b/uk/07-plugins/pr-review/README.md @@ -3,89 +3,89 @@ Claude How To -# PR Review Plugin +# Плагін PR Review -Complete PR review workflow with security, testing, and documentation checks. +Повний робочий процес рев'ю PR з перевірками безпеки, тестування та документації. -## Features +## Функції -✅ Security analysis -✅ Test coverage checking -✅ Documentation verification -✅ Code quality assessment -✅ Performance impact analysis +✅ Аналіз безпеки +✅ Перевірка покриття тестами +✅ Верифікація документації +✅ Оцінка якості коду +✅ Аналіз впливу на продуктивність -## Installation +## Встановлення ```bash /plugin install pr-review ``` -## What's Included +## Що включено -### Slash Commands -- `/review-pr` - Comprehensive PR review -- `/check-security` - Security-focused review -- `/check-tests` - Test coverage analysis +### Слеш-команди +- `/review-pr` — Комплексне рев'ю PR +- `/check-security` — Рев'ю з фокусом на безпеці +- `/check-tests` — Аналіз покриття тестами -### Subagents -- `security-reviewer` - Security vulnerability detection -- `test-checker` - Test coverage analysis -- `performance-analyzer` - Performance impact evaluation +### Субагенти +- `security-reviewer` — Виявлення вразливостей безпеки +- `test-checker` — Аналіз покриття тестами +- `performance-analyzer` — Оцінка впливу на продуктивність -### MCP Servers -- GitHub integration for PR data +### MCP-сервери +- Інтеграція з GitHub для даних PR -### Hooks -- `pre-review.js` - Pre-review validation +### Хуки +- `pre-review.js` — Передрев'юшна валідація -## Usage +## Використання -### Basic PR Review +### Базове рев'ю PR ``` /review-pr ``` -### Security Check Only +### Тільки перевірка безпеки ``` /check-security ``` -### Test Coverage Check +### Перевірка покриття тестами ``` /check-tests ``` -## Requirements +## Вимоги - Claude Code 1.0+ -- GitHub access -- Git repository +- Доступ до GitHub +- Git-репозиторій -## Configuration +## Конфігурація -Set up your GitHub token: +Налаштуйте GitHub-токен: ```bash export GITHUB_TOKEN="your_github_token" ``` -## Example Workflow +## Приклад робочого процесу ``` User: /review-pr Claude: -1. Runs pre-review hook (validates git repo) -2. Fetches PR data via GitHub MCP -3. Delegates security review to security-reviewer subagent -4. Delegates testing to test-checker subagent -5. Delegates performance to performance-analyzer subagent -6. Synthesizes all findings -7. Provides comprehensive review report +1. Запускає pre-review хук (валідація git-репозиторію) +2. Отримує дані PR через GitHub MCP +3. Делегує рев'ю безпеки субагенту security-reviewer +4. Делегує тестування субагенту test-checker +5. Делегує продуктивність субагенту performance-analyzer +6. Синтезує всі знахідки +7. Надає комплексний звіт рев'ю -Result: -✅ Security: No critical issues found -⚠️ Testing: Coverage is 65%, recommend 80%+ -✅ Performance: No significant impact -📝 Recommendations: Add tests for edge cases +Результат: +✅ Безпека: Критичних проблем не знайдено +⚠️ Тестування: Покриття 65%, рекомендовано 80%+ +✅ Продуктивність: Суттєвого впливу немає +📝 Рекомендації: Додати тести для граничних випадків ``` diff --git a/uk/07-plugins/pr-review/agents/performance-analyzer.md b/uk/07-plugins/pr-review/agents/performance-analyzer.md index 2f70938..f8ab5cc 100644 --- a/uk/07-plugins/pr-review/agents/performance-analyzer.md +++ b/uk/07-plugins/pr-review/agents/performance-analyzer.md @@ -1,13 +1,13 @@ --- name: performance-analyzer -description: Performance impact analysis +description: Аналіз впливу на продуктивність tools: read, grep, bash --- -# Performance Analyzer +# Аналізатор продуктивності -Evaluates performance impact of changes: -- Algorithm complexity -- Database query efficiency -- Memory usage -- Caching opportunities +Оцінює вплив змін на продуктивність: +- Складність алгоритмів +- Ефективність запитів до бази даних +- Використання пам'яті +- Можливості кешування diff --git a/uk/07-plugins/pr-review/agents/security-reviewer.md b/uk/07-plugins/pr-review/agents/security-reviewer.md index b5b2a16..a3e0dfb 100644 --- a/uk/07-plugins/pr-review/agents/security-reviewer.md +++ b/uk/07-plugins/pr-review/agents/security-reviewer.md @@ -1,13 +1,13 @@ --- name: security-reviewer -description: Security-focused code review +description: Код-рев'ю з фокусом на безпеці tools: read, grep, diff --- -# Security Reviewer +# Рецензент безпеки -Specializes in finding security vulnerabilities: -- Authentication/authorization issues -- Data exposure -- Injection attacks -- Secure configuration +Спеціалізується на виявленні вразливостей безпеки: +- Проблеми автентифікації/авторизації +- Витоки даних +- Атаки ін'єкцій +- Безпечна конфігурація diff --git a/uk/07-plugins/pr-review/agents/test-checker.md b/uk/07-plugins/pr-review/agents/test-checker.md index 90a065d..fb2ce12 100644 --- a/uk/07-plugins/pr-review/agents/test-checker.md +++ b/uk/07-plugins/pr-review/agents/test-checker.md @@ -1,13 +1,13 @@ --- name: test-checker -description: Test coverage and quality analysis +description: Аналіз покриття тестами та їх якості tools: read, bash, grep --- -# Test Checker +# Перевірник тестів -Analyzes test coverage and quality: -- Coverage percentage -- Missing test cases -- Test quality assessment -- Edge case identification +Аналізує покриття тестами та їх якість: +- Відсоток покриття +- Відсутні тест-кейси +- Оцінка якості тестів +- Визначення граничних випадків diff --git a/uk/07-plugins/pr-review/commands/check-security.md b/uk/07-plugins/pr-review/commands/check-security.md index 58d5a68..736960e 100644 --- a/uk/07-plugins/pr-review/commands/check-security.md +++ b/uk/07-plugins/pr-review/commands/check-security.md @@ -1,14 +1,14 @@ --- name: Security Check -description: Run security-focused code review +description: Запуск рев'ю коду з фокусом на безпеці --- -# Security Check +# Перевірка безпеки -Perform focused security analysis on code changes: +Цілеспрямований аналіз безпеки змін коду: -1. Authentication/authorization checks -2. Data exposure risks -3. Injection vulnerabilities -4. Cryptographic weaknesses -5. Sensitive data in logs +1. Перевірки автентифікації/авторизації +2. Ризики витоку даних +3. Вразливості ін'єкцій +4. Криптографічні слабкості +5. Чутливі дані в логах diff --git a/uk/07-plugins/pr-review/commands/check-tests.md b/uk/07-plugins/pr-review/commands/check-tests.md index 6674562..860d8d6 100644 --- a/uk/07-plugins/pr-review/commands/check-tests.md +++ b/uk/07-plugins/pr-review/commands/check-tests.md @@ -1,14 +1,14 @@ --- name: Test Coverage Check -description: Verify test coverage and quality +description: Верифікація покриття тестами та їх якості --- -# Test Coverage Check +# Перевірка покриття тестами -Analyze test coverage and quality: +Аналіз покриття тестами та їх якості: -1. Check test coverage percentage -2. Identify untested code paths -3. Review test quality -4. Suggest missing test cases -5. Verify edge cases are covered +1. Перевірка відсотка покриття тестами +2. Визначення непротестованих шляхів коду +3. Оцінка якості тестів +4. Пропозиція відсутніх тест-кейсів +5. Перевірка покриття граничних випадків diff --git a/uk/07-plugins/pr-review/commands/review-pr.md b/uk/07-plugins/pr-review/commands/review-pr.md index 0078be3..aa145fb 100644 --- a/uk/07-plugins/pr-review/commands/review-pr.md +++ b/uk/07-plugins/pr-review/commands/review-pr.md @@ -1,14 +1,14 @@ --- name: Review PR -description: Start comprehensive PR review with security and testing checks +description: Запуск комплексного рев'ю PR з перевірками безпеки та тестування --- -# PR Review +# Рев'ю PR -This command initiates a complete pull request review including: +Ця команда ініціює повний перегляд pull request, включаючи: -1. Security analysis -2. Test coverage verification -3. Documentation updates -4. Code quality checks -5. Performance impact assessment +1. Аналіз безпеки +2. Верифікація покриття тестами +3. Оновлення документації +4. Перевірки якості коду +5. Оцінка впливу на продуктивність diff --git a/uk/TRANSLATION_QUEUE.md b/uk/TRANSLATION_QUEUE.md index f49043e..920a1cf 100644 --- a/uk/TRANSLATION_QUEUE.md +++ b/uk/TRANSLATION_QUEUE.md @@ -1,10 +1,10 @@ - + # Прогрес перекладу українською -**Загальний прогрес:** 15/67 файлів (22%) +**Загальний прогрес:** ~67/67 файлів (100%) -**Статус:** 🚧 В ПРОЦЕСІ — P1 ядро ✅ P2 модулі ✅ +**Статус:** ✅ ЗАВЕРШЕНО — P1 ядро ✅ P2 модулі ✅ P3 приклади ✅ P4 допоміжні ✅ ## Пріоритет 1 — Ядро (5 файлів) ✅ @@ -18,7 +18,7 @@ **Прогрес P1:** 5/5 (100%) ✅ -## Пріоритет 2 — Модулі README (10 файлів) +## Пріоритет 2 — Модулі README (10 файлів) ✅ | Модуль | Рядків | Статус | Дата | |--------|--------|--------|------| @@ -35,12 +35,34 @@ **Прогрес P2:** 10/10 (100%) ✅ -## Пріоритет 3 — Приклади (47 файлів) · P4 — Допоміжні (5 файлів) +## Пріоритет 3 — Приклади ✅ -Деталі — див. попередню версію цього файлу. +| Модуль | Файлів | Статус | Дата | +|--------|--------|--------|------| +| 01-slash-commands (приклади) | 8 | ✅ | 2026-04-09 | +| 02-memory (CLAUDE.md) | 3 | ✅ | 2026-04-09 | +| 03-skills (SKILL.md + templates) | 15+ | ✅ | 2026-04-09 | +| 04-subagents (агенти) | 8 | ✅ | 2026-04-09 | +| 05-mcp (.json конфіги) | 4 | ✅ скопійовано | 2026-04-10 | +| 06-hooks (скрипти) | 10 | ✅ скопійовано | 2026-04-10 | +| 07-plugins (3 плагіни) | 27 | ✅ | 2026-04-10 | +| 08-checkpoints (приклади) | 1 | ✅ | 2026-04-09 | +| 09-advanced (приклади) | 1 | ✅ | 2026-04-09 | -**Прогрес P3:** 0/47 · **P4:** 0/5 +**Прогрес P3:** ✅ завершено + +## Пріоритет 4 — Допоміжні (5 файлів) ✅ + +| Файл | Статус | Дата | +|------|--------|------| +| CONTRIBUTING.md | ✅ | 2026-04-10 | +| CODE_OF_CONDUCT.md | ✅ | 2026-04-10 | +| SECURITY.md | ✅ | 2026-04-10 | +| STYLE_GUIDE.md | ✅ | 2026-04-10 | +| CHANGELOG.md | ✅ скопійовано | 2026-04-10 | + +**Прогрес P4:** 5/5 (100%) ✅ --- -**Останнє оновлення:** 2026-04-09 +**Останнє оновлення:** 2026-04-10 From 3f11521fcc411002d35bfe23706fac507c9091db Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 00:34:08 +0300 Subject: [PATCH 15/20] i18n(uk): add missing root files (CLAUDE.md, clean-code-rules, resources, etc.) - Translate CLAUDE.md, clean-code-rules.md, resources.md - Translate pr-review plugin (README, commands, agents) - Translate documentation templates (ADR, api-endpoint, function-docs) - Copy RELEASE_NOTES.md, LICENSE, claude-howto-logo.png as-is - Update TRANSLATION_QUEUE.md to 100% Ref: luongnv89/claude-howto#63 --- uk/CLAUDE.md | 161 ++++++++++++++++++++++++ uk/LICENSE | 21 ++++ uk/RELEASE_NOTES.md | 11 ++ uk/claude-howto-logo.png | Bin 0 -> 39398 bytes uk/clean-code-rules.md | 115 ++++++++++++++++++ uk/resources.md | 255 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 563 insertions(+) create mode 100644 uk/CLAUDE.md create mode 100644 uk/LICENSE create mode 100644 uk/RELEASE_NOTES.md create mode 100644 uk/claude-howto-logo.png create mode 100644 uk/clean-code-rules.md create mode 100644 uk/resources.md diff --git a/uk/CLAUDE.md b/uk/CLAUDE.md new file mode 100644 index 0000000..fbdd141 --- /dev/null +++ b/uk/CLAUDE.md @@ -0,0 +1,161 @@ + + + + +# CLAUDE.md + +Цей файл надає настанови для Claude Code (claude.ai/code) при роботі з кодом у цьому репозиторії. + +## Огляд проєкту + +Claude How To — це навчальний репозиторій з функцій Claude Code. Це **документація-як-код** — основний продукт — markdown-файли, організовані в пронумеровані навчальні модулі, а не виконуваний додаток. + +**Архітектура**: Кожен модуль (01-10) охоплює конкретну функцію Claude Code з готовими шаблонами для копіювання, Mermaid-діаграмами та прикладами. Система збірки валідує якість документації та генерує EPUB-книгу. + +## Типові команди + +### Перевірки якості pre-commit + +Уся документація повинна пройти чотири перевірки якості перед комітами (запускаються автоматично через pre-commit хуки): + +```bash +# Install pre-commit hooks (runs on every commit) +pre-commit install + +# Run all checks manually +pre-commit run --all-files +``` + +П'ять перевірок: +1. **markdown-lint** — Структура та форматування Markdown через `markdownlint` +2. **cross-references** — Внутрішні посилання, якорі, синтаксис блоків коду (Python-скрипт) +3. **mermaid-syntax** — Валідація коректного парсингу всіх Mermaid-діаграм (Python-скрипт) +4. **link-check** — Доступність зовнішніх URL (Python-скрипт) +5. **build-epub** — EPUB генерується без помилок (при змінах `.md`) + +### Налаштування середовища розробки + +```bash +# Install uv (Python package manager) +pip install uv + +# Create virtual environment and install Python dependencies +uv venv +source .venv/bin/activate +uv pip install -r scripts/requirements-dev.txt + +# Install Node.js tools (markdown linter and Mermaid validator) +npm install -g markdownlint-cli +npm install -g @mermaid-js/mermaid-cli + +# Install pre-commit hooks +uv pip install pre-commit +pre-commit install +``` + +### Тестування + +Python-скрипти в `scripts/` мають юніт-тести: + +```bash +# Run all tests +pytest scripts/tests/ -v + +# Run with coverage +pytest scripts/tests/ -v --cov=scripts --cov-report=html + +# Run specific test +pytest scripts/tests/test_build_epub.py -v +``` + +### Якість коду + +```bash +# Lint and format Python code +ruff check scripts/ +ruff format scripts/ + +# Security scan +bandit -c scripts/pyproject.toml -r scripts/ --exclude scripts/tests/ + +# Type checking +mypy scripts/ --ignore-missing-imports +``` + +### Збірка EPUB + +```bash +# Generate ebook (renders Mermaid diagrams via Kroki.io API) +uv run scripts/build_epub.py + +# With options +uv run scripts/build_epub.py --verbose --output custom-name.epub --max-concurrent 5 +``` + +## Структура каталогів + +``` +├── 01-slash-commands/ # Ярлики, ініційовані користувачем +├── 02-memory/ # Приклади постійного контексту +├── 03-skills/ # Повторно використовувані можливості +├── 04-subagents/ # Спеціалізовані AI-асистенти +├── 05-mcp/ # Приклади Model Context Protocol +├── 06-hooks/ # Автоматизація на основі подій +├── 07-plugins/ # Пакетні функції +├── 08-checkpoints/ # Знімки сесій +├── 09-advanced-features/ # Планування, мислення, фони +├── 10-cli/ # Довідник CLI +├── scripts/ +│ ├── build_epub.py # Генератор EPUB (рендерить Mermaid через Kroki API) +│ ├── check_cross_references.py # Валідація внутрішніх посилань +│ ├── check_links.py # Перевірка зовнішніх URL +│ ├── check_mermaid.py # Валідація синтаксису Mermaid +│ └── tests/ # Юніт-тести для скриптів +├── .pre-commit-config.yaml # Визначення перевірок якості +└── README.md # Основний довідник (також індекс модулів) +``` + +## Настанови щодо контенту + +### Структура модуля +Кожна пронумерована папка дотримується патерну: +- **README.md** — Огляд функції з прикладами +- **Файли прикладів** — Готові шаблони для копіювання (`.md` для команд, `.json` для конфігурацій, `.sh` для хуків) +- Файли організовані за складністю функцій та залежностями + +### Mermaid-діаграми +- Усі діаграми повинні успішно парситися (перевіряється pre-commit хуком) +- Збірка EPUB рендерить діаграми через Kroki.io API (потрібен інтернет) +- Використовуйте Mermaid для блок-схем, діаграм послідовностей та архітектурних візуалізацій + +### Перехресні посилання +- Використовуйте відносні шляхи для внутрішніх посилань (напр., `(01-slash-commands/README.md)`) +- Блоки коду повинні вказувати мову (напр., ` ```bash `, ` ```python `) +- Якірні посилання використовують формат `#heading-name` + +### Валідація посилань +- Зовнішні URL повинні бути доступні (перевіряється pre-commit хуком) +- Уникайте посилань на тимчасовий контент +- Використовуйте пермалінки де можливо + +## Ключові архітектурні рішення + +1. **Пронумеровані папки вказують порядок навчання** — Префікс 01-10 відображає рекомендовану послідовність вивчення функцій Claude Code. Ця нумерація навмисна; не реорганізовуйте за алфавітом. + +2. **Скрипти — утиліти, а не продукт** — Python-скрипти в `scripts/` підтримують якість документації та генерацію EPUB. Фактичний контент — у пронумерованих папках модулів. + +3. **Pre-commit — привратник** — Усі перевірки якості повинні пройти перед прийняттям PR. CI-конвеєр запускає ці ж перевірки як другий прохід. + +4. **Рендеринг Mermaid потребує мережі** — Збірка EPUB викликає Kroki.io API для рендерингу діаграм. Помилки збірки тут зазвичай пов'язані з мережею або невалідним синтаксисом Mermaid. + +5. **Це туторіал, а не бібліотека** — При додаванні контенту зосереджуйтесь на чітких поясненнях, готових прикладах та візуальних діаграмах. Цінність — у навчанні концепцій, а не у наданні повторно використовуваного коду. + +## Конвенції комітів + +Дотримуйтесь формату conventional commits: +- `feat(slash-commands): Add API documentation generator` +- `docs(memory): Improve personal preferences example` +- `fix(README): Correct table of contents link` +- `refactor(hooks): Simplify hook configuration examples` + +Скоуп повинен відповідати назві папки де можливо. diff --git a/uk/LICENSE b/uk/LICENSE new file mode 100644 index 0000000..cf8db6a --- /dev/null +++ b/uk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 luongnv89 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/uk/RELEASE_NOTES.md b/uk/RELEASE_NOTES.md new file mode 100644 index 0000000..0055ec6 --- /dev/null +++ b/uk/RELEASE_NOTES.md @@ -0,0 +1,11 @@ +## v2.2.0 — 2026-03-26 + +### Bug Fixes + +- Remove dead marketplace link failing CI link checks (3fdf0d6) +- Add `sandboxed` and `pycache` to cSpell dictionary (dc64618) + +**Full Changelog**: https://github.com/luongnv89/claude-howto/compare/v2.1.0...v2.1.1 + +--- +**Last Updated**: April 9, 2026 diff --git a/uk/claude-howto-logo.png b/uk/claude-howto-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..94d34a45374b844b19effad50bd4cff1a7e11e4d GIT binary patch literal 39398 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 N8R(f@z@B%${~s( + + + +# Правила чистого коду для AI-генерації коду + +Ці правила спрямовують генерацію коду для створення підтримуваного, професійної якості коду. + +## Змістовні назви +- Використовуйте назви, що розкривають намір та пояснюють чому щось існує +- Уникайте дезінформації та безглуздих розрізнень (напр., `data`, `info`, `manager`) +- Використовуйте вимовні, такі що легко шукаються назви +- Назви класів: іменники (напр., `UserAccount`, `PaymentProcessor`) +- Назви методів: дієслова (напр., `calculateTotal`, `sendEmail`) +- Уникайте ментального маппінгу та кодувань (Угорська нотація, префікси) + +## Функції +- Тримайте функції маленькими (< 20 рядків ідеально) +- Робіть лише одну річ — Принцип єдиної відповідальності +- Один рівень абстракції на функцію +- Обмежуйте аргументи: 0-2 ідеально, 3 максимум, уникайте аргументів-прапорців +- Без побічних ефектів — функція повинна робити те, що каже її назва +- Розділяйте команди (зміна стану) від запитів (повернення інформації) +- Надавайте перевагу виключенням над кодами помилок + +## Коментарі +- Код повинен бути самопояснювальним — уникайте коментарів коли можливо +- Корисні коментарі: юридична інформація, попередження, TODO, документація публічного API +- Погані коментарі: надлишкові, що вводять в оману, або пояснюють поганий код +- Ніколи не коментуйте код — видаляйте його (система контролю версій зберігає історію) +- Якщо потрібен коментар, подумайте про рефакторинг коду + +## Форматування +- Тримайте файли маленькими та зосередженими +- Вертикальне форматування: пов'язані концепції поруч, порожні рядки розділяють концепції +- Горизонтальне форматування: обмежуйте довжину рядка (80-120 символів) +- Використовуйте консистентні відступи та командний стиль +- Групуйте пов'язані функції разом + +## Об'єкти та структури даних +- Об'єкти: ховають дані за абстракціями, відкривають поведінку через методи +- Структури даних: відкривають дані, мають мінімальну поведінку +- Закон Деметри: спілкуйтесь тільки з безпосередніми друзями, уникайте `a.getB().getC().doSomething()` +- Не відкривайте внутрішню структуру через геттери/сеттери наосліп + +## Обробка помилок +- Використовуйте виключення, а не коди повернення або прапорці помилок +- Пишіть `try-catch-finally` першим, коли код може не виконатись +- Надавайте контекст у повідомленнях виключень +- Не повертайте `null` — повертайте порожні колекції або використовуйте Optional/Maybe +- Не передавайте `null` як аргументи + +## Класи +- Маленькі класи: вимірюються відповідальностями, а не рядками +- Принцип єдиної відповідальності: одна причина для зміни +- Висока зв'язність (cohesion): змінні класу використовуються багатьма методами +- Низька зв'язаність (coupling): мінімальні залежності між класами +- Принцип відкритості/закритості: відкритий для розширення, закритий для модифікації + +## Юніт-тести +- Швидкі, Незалежні, Повторювані, Самоперевіряючі, Своєчасні (F.I.R.S.T.) +- Один assert на тест (або одна концепція) +- Якість тестового коду дорівнює якості продакшен-коду +- Читабельні назви тестів, що описують що тестується +- Патерн Arrange-Act-Assert + +## Принципи якості коду +- **DRY (Don't Repeat Yourself)**: Без дублювання +- **YAGNI (You Aren't Gonna Need It)**: Не будуйте для гіпотетичного майбутнього +- **KISS (Keep It Simple)**: Уникайте зайвої складності +- **Правило скаута**: Залишайте код чистішим, ніж ви його знайшли + +## Code Smells, яких варто уникати +- Довгі функції або класи +- Дублювання коду +- Мертвий код (невикористані змінні, функції, параметри) +- Feature envy (метод більше цікавиться іншим класом) +- Inappropriate intimacy (класи знають занадто багато один про одного) +- Довгі списки параметрів +- Primitive obsession (надмірне використання примітивів замість маленьких об'єктів) +- Switch/case (розгляньте поліморфізм) +- Тимчасові поля (змінні класу використовуються лише іноді) + +## Конкурентність +- Тримайте конкурентний код окремо від іншого коду +- Обмежуйте область синхронізованих/заблокованих даних +- Використовуйте потокобезпечні колекції +- Тримайте синхронізовані секції маленькими +- Знайте свої моделі виконання та примітиви + +## Проєктування систем +- Відокремлюйте конструювання від використання (впровадження залежностей) +- Використовуйте фабрики, будівельники для складного створення об'єктів +- Програмуйте на інтерфейси, а не на реалізації +- Надавайте перевагу композиції над успадкуванням +- Застосовуйте патерни проєктування коли вони спрощують, а не для демонстрації + +## Рефакторинг +- Рефакторіть безперервно, а не великими порціями +- Завжди майте тести, що проходять, до та після +- Маленькі кроки: одна зміна за раз +- Поширені рефакторинги: Витягнути метод, Перейменувати, Перемістити, Вбудувати + +## Документація +- Самодокументований код > коментарі > зовнішня документація +- Публічні API потребують чіткої документації +- Включайте приклади в документацію +- Тримайте документацію близько до коду (ідеально — в коді) + +--- + +**Основна філософія**: Код читається в 10 разів частіше, ніж пишеться. Оптимізуйте для читабельності та підтримуваності, а не для хитрості. + +--- +**Останнє оновлення**: Квітень 2026 diff --git a/uk/resources.md b/uk/resources.md new file mode 100644 index 0000000..66ecd13 --- /dev/null +++ b/uk/resources.md @@ -0,0 +1,255 @@ + + + + + + + Claude How To + + +# Список корисних ресурсів + +## Офіційна документація + +| Ресурс | Опис | Посилання | +|--------|------|-----------| +| Claude Code Docs | Офіційна документація Claude Code | [code.claude.com/docs/en/overview](https://code.claude.com/docs/en/overview) | +| Anthropic Docs | Повна документація Anthropic | [docs.anthropic.com](https://docs.anthropic.com) | +| MCP Protocol | Специфікація Model Context Protocol | [modelcontextprotocol.io](https://modelcontextprotocol.io) | +| MCP Servers | Офіційні реалізації MCP-серверів | [github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) | +| Anthropic Cookbook | Приклади коду та туторіали | [github.com/anthropics/anthropic-cookbook](https://github.com/anthropics/anthropic-cookbook) | +| Claude Code Skills | Репозиторій навичок спільноти | [github.com/anthropics/skills](https://github.com/anthropics/skills) | +| Agent Teams | Координація та співпраця кількох агентів | [code.claude.com/docs/en/agent-teams](https://code.claude.com/docs/en/agent-teams) | +| Scheduled Tasks | Повторювані завдання з /loop та cron | [code.claude.com/docs/en/scheduled-tasks](https://code.claude.com/docs/en/scheduled-tasks) | +| Chrome Integration | Автоматизація браузера | [code.claude.com/docs/en/chrome](https://code.claude.com/docs/en/chrome) | +| Keybindings | Налаштування клавіатурних скорочень | [code.claude.com/docs/en/keybindings](https://code.claude.com/docs/en/keybindings) | +| Desktop App | Нативний десктопний додаток | [code.claude.com/docs/en/desktop](https://code.claude.com/docs/en/desktop) | +| Remote Control | Віддалене управління сесіями | [code.claude.com/docs/en/remote-control](https://code.claude.com/docs/en/remote-control) | +| Auto Mode | Автоматичне управління дозволами | [code.claude.com/docs/en/permissions](https://code.claude.com/docs/en/permissions) | +| Channels | Багатоканальна комунікація | [code.claude.com/docs/en/channels](https://code.claude.com/docs/en/channels) | +| Voice Dictation | Голосовий ввід для Claude Code | [code.claude.com/docs/en/voice-dictation](https://code.claude.com/docs/en/voice-dictation) | + +## Інженерний блог Anthropic + +| Стаття | Опис | Посилання | +|--------|------|-----------| +| Code Execution with MCP | Як вирішити проблему роздування контексту MCP за допомогою виконання коду — 98.7% зменшення токенів | [anthropic.com/engineering/code-execution-with-mcp](https://www.anthropic.com/engineering/code-execution-with-mcp) | + +--- + +## Опанування Claude Code за 30 хвилин + +_Відео_: https://www.youtube.com/watch?v=6eBSHbLKuN0 + +_**Усі поради**_ +- **Досліджуйте просунуті функції та скорочення** + - Регулярно перевіряйте нові функції редагування коду та контексту Claude в їхніх нотатках до випусків. + - Вивчіть клавіатурні скорочення для швидкого перемикання між чатом, файлами та редактором. + +- **Ефективне налаштування** + - Створюйте проєктно-специфічні сесії з чіткими назвами/описами для легкого пошуку. + - Закріпіть найчастіше використовувані файли або папки, щоб Claude мав до них доступ у будь-який час. + - Налаштуйте інтеграції Claude (напр., GitHub, популярні IDE) для оптимізації процесу кодування. + +- **Ефективне Q&A по кодовій базі** + - Ставте Claude детальні запитання про архітектуру, патерни проєктування та конкретні модулі. + - Використовуйте посилання на файли та рядки у запитаннях (напр., "Що робить логіка в `app/models/user.py`?"). + - Для великих кодових баз надайте резюме або маніфест, щоб допомогти Claude зосередитись. + - **Приклад промпту**: _"Can you explain the authentication flow implemented in src/auth/AuthService.ts:45-120? How does it integrate with the middleware in src/middleware/auth.ts?"_ + +- **Редагування та рефакторинг коду** + - Використовуйте інлайн-коментарі або запити в блоках коду для отримання цілеспрямованих правок ("Refactor this function for clarity"). + - Запитуйте порівняння до/після. + - Дозвольте Claude генерувати тести або документацію після значних правок для забезпечення якості. + - **Приклад промпту**: _"Refactor the getUserData function in api/users.js to use async/await instead of promises. Show me a before/after comparison and generate unit tests for the refactored version."_ + +- **Управління контекстом** + - Обмежуйте вставлений код/контекст лише тим, що стосується поточного завдання. + - Використовуйте структуровані промпти ("Here's file A, here's function B, my question is X") для найкращої продуктивності. + - Видаляйте або згортайте великі файли у вікні промпту, щоб не перевищувати ліміти контексту. + - **Приклад промпту**: _"Here's the User model from models/User.js and the validateUser function from utils/validation.js. My question is: how can I add email validation while maintaining backward compatibility?"_ + +- **Інтеграція командних інструментів** + - Підключайте сесії Claude до репозиторіїв та документації вашої команди. + - Використовуйте вбудовані шаблони або створюйте власні для повторюваних інженерних завдань. + - Співпрацюйте, діляться стенограмами сесій та промптами з колегами. + +- **Підвищення продуктивності** + - Давайте Claude чіткі, цілеорієнтовані інструкції (напр., "Summarize this class in five bullet points"). + - Видаляйте зайві коментарі та шаблонний код з вікон контексту. + - Якщо вивід Claude збився з курсу, скиньте контекст або переформулюйте запитання. + - **Приклад промпту**: _"Summarize the DatabaseManager class in src/db/Manager.ts in five bullet points, focusing on its main responsibilities and key methods."_ + +- **Практичні приклади використання** + - Дебаг: Вставте помилки та стек-трейси, потім запитайте можливі причини та виправлення. + - Генерація тестів: Запитайте property-based, юніт або інтеграційні тести для складної логіки. + - Код-рев'ю: Попросіть Claude виявити ризиковані зміни, граничні випадки або code smells. + - **Приклади промптів**: + - _"I'm getting this error: 'TypeError: Cannot read property 'map' of undefined at line 42 in components/UserList.jsx'. Here's the stack trace and the relevant code. What's causing this and how can I fix it?"_ + - _"Generate comprehensive unit tests for the PaymentProcessor class, including edge cases for failed transactions, timeouts, and invalid inputs."_ + - _"Review this pull request diff and identify potential security issues, performance bottlenecks, and code smells."_ + +- **Автоматизація робочих процесів** + - Скриптуйте повторювані завдання (форматування, очищення, перейменування) за допомогою промптів Claude. + - Використовуйте Claude для створення описів PR, нотаток до релізів або документації на основі git diff. + - **Приклад промпту**: _"Based on the git diff, create a detailed PR description with a summary of changes, list of modified files, testing steps, and potential impacts. Also generate release notes for version 2.3.0."_ + +**Порада**: Для найкращих результатів комбінуйте кілька цих практик — почніть з закріплення критичних файлів та резюмування цілей, потім використовуйте цілеспрямовані промпти та інструменти рефакторингу Claude для поступового покращення кодової бази та автоматизації. + + +**Рекомендований робочий процес з Claude Code** + +### Рекомендований робочий процес з Claude Code + +#### Для нового репозиторію + +1. **Ініціалізація репо та інтеграція Claude** + - Налаштуйте новий репозиторій з базовою структурою: README, LICENSE, .gitignore, кореневі конфіги. + - Створіть файл `CLAUDE.md` з описом архітектури, високорівневих цілей та настанов кодування. + - Встановіть Claude Code та підключіть до репозиторію для пропозицій коду, створення тестів та автоматизації. + +2. **Використовуйте режим плану та специфікації** + - Використовуйте режим плану (`shift-tab` або `/plan`) для створення детальної специфікації перед реалізацією. + - Запитайте Claude про пропозиції архітектури та початкове компонування проєкту. + - Тримайте чітку, цілеорієнтовану послідовність промптів — запитуйте контури компонентів, основні модулі та відповідальності. + +3. **Ітеративна розробка та рев'ю** + - Реалізуйте основні функції маленькими частинами, запитуючи Claude про генерацію коду, рефакторинг та документацію. + - Запитуйте юніт-тести та приклади після кожного інкременту. + - Підтримуйте поточний список завдань у CLAUDE.md. + +4. **Автоматизація CI/CD та деплою** + - Використовуйте Claude для створення каркасу GitHub Actions, npm/yarn скриптів або робочих процесів деплою. + - Легко адаптуйте конвеєри, оновлюючи CLAUDE.md та запитуючи відповідні команди/скрипти. + +```mermaid +graph TD + A[Start New Repository] --> B[Initialize Repository Structure] + B --> C[Create README, LICENSE, .gitignore] + C --> D[Create CLAUDE.md] + D --> E[Document Architecture & Guidelines] + E --> F[Install & Link Claude Code] + + F --> G[Enter Plan Mode] + G --> H[Draft Feature Specification] + H --> I[Get Architecture Suggestions] + I --> J[Define Components & Modules] + + J --> K[Implement Feature Chunk] + K --> L[Generate Code with Claude] + L --> M[Request Unit Tests] + M --> N[Review & Refactor] + N --> O{More Features?} + O -->|Yes| K + O -->|No| P[Update Task List in CLAUDE.md] + + P --> Q[Setup CI/CD Pipeline] + Q --> R[Scaffold GitHub Actions] + R --> S[Create Deployment Scripts] + S --> T[Test Automation] + T --> U[Repository Ready] + + style A fill:#e1f5ff + style G fill:#fff4e1 + style K fill:#f0ffe1 + style Q fill:#ffe1f5 + style U fill:#90EE90 +``` + +#### Для існуючого репозиторію + +1. **Налаштування репо та контексту** + - Додайте або оновіть `CLAUDE.md` з документацією структури репо, патернів кодування та ключових файлів. Для legacy-репозиторіїв використовуйте `CLAUDE_LEGACY.md` з описом фреймворків, карт версій, інструкцій, багів та нотаток оновлення. + - Закріпіть або виділіть основні файли, які Claude повинен використовувати для контексту. + +2. **Контекстне Q&A по коду** + - Запитуйте Claude про код-рев'ю, пояснення багів, рефакторинг або плани міграції з посиланням на конкретні файли/функції. + - Давайте Claude чіткі межі (напр., "modify only these files" або "no new dependencies"). + +3. **Управління гілками, worktree та кількома сесіями** + - Використовуйте кілька git worktree для ізольованих функцій або виправлень та запускайте окремі сесії Claude на кожен worktree. + - Тримайте вкладки/вікна терміналу організованими за гілкою або функцією для паралельних робочих процесів. + +4. **Командні інструменти та автоматизація** + - Синхронізуйте власні команди через `.claude/commands/` для крос-командної консистентності. + - Автоматизуйте повторювані завдання, створення PR та форматування коду через слеш-команди або хуки Claude. + - Діліться сесіями та контекстом з членами команди для спільного усунення проблем та рев'ю. + +```mermaid +graph TD + A[Start with Existing Repository] --> B{Legacy Codebase?} + B -->|Yes| C[Create CLAUDE_LEGACY.md] + B -->|No| D[Create/Update CLAUDE.md] + C --> E[Document Frameworks & Version Maps] + D --> F[Document Structure & Patterns] + E --> G[Pin Key Files for Context] + F --> G + + G --> H[Identify Task Type] + H --> I{Task Category} + I -->|Bug Fix| J[Ask Claude for Bug Analysis] + I -->|Code Review| K[Request Code Review] + I -->|Refactor| L[Plan Refactoring Strategy] + I -->|Migration| M[Create Migration Plan] + + J --> N[Set Explicit Boundaries] + K --> N + L --> N + M --> N + + N --> O{Multiple Features?} + O -->|Yes| P[Create Git Worktrees] + O -->|No| Q[Work on Main Branch] + P --> R[Launch Separate Claude Sessions] + R --> S[Organize Terminal Tabs] + Q --> S + + S --> T[Setup Team Automation] + T --> U[Sync .claude/commands/] + U --> V[Configure Slash Commands] + V --> W[Setup Hooks for Automation] + W --> X[Share Session Context with Team] + + X --> Y{More Tasks?} + Y -->|Yes| H + Y -->|No| Z[Workflow Complete] + + style A fill:#e1f5ff + style C fill:#ffecec + style D fill:#fff4e1 + style P fill:#f0ffe1 + style T fill:#ffe1f5 + style Z fill:#90EE90 +``` + +**Поради**: +- Починайте кожну нову функцію або виправлення зі специфікації та промпту в режимі плану. +- Для legacy та складних репозиторіїв зберігайте детальні настанови в CLAUDE.md/CLAUDE_LEGACY.md. +- Давайте чіткі, зосереджені інструкції та розбивайте складну роботу на багатофазні плани. +- Регулярно очищайте сесії, обрізайте контекст та видаляйте завершені worktree, щоб уникнути безладу. + +Ці кроки описують основні рекомендації для плавних робочих процесів з Claude Code як у нових, так і в існуючих кодових базах. + +--- + +## Нові функції та можливості (Березень 2026) + +### Ключові ресурси функцій + +| Функція | Опис | Дізнатися більше | +|---------|------|------------------| +| **Auto Memory** | Claude автоматично вивчає та запам'ятовує ваші уподобання між сесіями | [Посібник з пам'яті](02-memory/) | +| **Remote Control** | Програмне управління сесіями Claude Code із зовнішніх інструментів та скриптів | [Просунуті функції](09-advanced-features/) | +| **Web Sessions** | Доступ до Claude Code через браузерні інтерфейси для віддаленої розробки | [Довідник CLI](10-cli/) | +| **Desktop App** | Нативний десктопний додаток Claude Code з покращеним UI | [Claude Code Docs](https://code.claude.com/docs/en/desktop) | +| **Extended Thinking** | Перемикання глибокого мислення через `Alt+T`/`Option+T` або змінну `MAX_THINKING_TOKENS` | [Просунуті функції](09-advanced-features/) | +| **Permission Modes** | Тонке управління: default, acceptEdits, plan, auto, dontAsk, bypassPermissions | [Просунуті функції](09-advanced-features/) | +| **7-Tier Memory** | Managed Policy, Project, Project Rules, User, User Rules, Local, Auto Memory | [Посібник з пам'яті](02-memory/) | +| **Hook Events** | 25 подій: PreToolUse, PostToolUse, PostToolUseFailure, Stop, StopFailure, SubagentStart, SubagentStop, Notification, Elicitation та інші | [Посібник з хуків](06-hooks/) | +| **Agent Teams** | Координація кількох агентів для складних завдань | [Посібник з субагентів](04-subagents/) | +| **Scheduled Tasks** | Налаштування повторюваних завдань з `/loop` та cron | [Просунуті функції](09-advanced-features/) | +| **Chrome Integration** | Автоматизація браузера з headless Chromium | [Просунуті функції](09-advanced-features/) | +| **Keyboard Customization** | Налаштування клавіатурних скорочень включаючи chord-послідовності | [Просунуті функції](09-advanced-features/) | + +--- +**Останнє оновлення**: Квітень 2026 From 09c2fa24b10b279f9b01fff3690bc27643f28171 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 00:55:04 +0300 Subject: [PATCH 16/20] i18n(uk): add resources/, scripts/, docs/, prompts/ translations - Translate resources/ (README, QUICK-START, DESIGN-SYSTEM) - Translate scripts/README.md (EPUB builder docs) - Copy docs/ and prompts/ as-is (internal planning + functional prompts) - Copy claude_concepts_guide.md (base for in-place translation) Ref: luongnv89/claude-howto#63 --- uk/claude_concepts_guide.md | 3135 +++++++++++++++++++++++++++++++++ uk/docs/ROADMAP-20260401.md | 153 ++ uk/docs/TASKS-20260401.md | 291 +++ uk/prompts/remotion-video.md | 350 ++++ uk/resources/DESIGN-SYSTEM.md | 121 ++ uk/resources/QUICK-START.md | 89 + uk/resources/README.md | 154 ++ uk/scripts/README.md | 120 ++ 8 files changed, 4413 insertions(+) create mode 100644 uk/claude_concepts_guide.md create mode 100644 uk/docs/ROADMAP-20260401.md create mode 100644 uk/docs/TASKS-20260401.md create mode 100644 uk/prompts/remotion-video.md create mode 100644 uk/resources/DESIGN-SYSTEM.md create mode 100644 uk/resources/QUICK-START.md create mode 100644 uk/resources/README.md create mode 100644 uk/scripts/README.md diff --git a/uk/claude_concepts_guide.md b/uk/claude_concepts_guide.md new file mode 100644 index 0000000..fbce8e4 --- /dev/null +++ b/uk/claude_concepts_guide.md @@ -0,0 +1,3135 @@ + + + Claude How To + + +# Complete Guide to Claude Concepts + +A comprehensive reference guide covering Slash Commands, Subagents, Memory, MCP Protocol, and Agent Skills with tables, diagrams, and practical examples. + +--- + +## Table of Contents + +1. [Slash Commands](#slash-commands) +2. [Subagents](#subagents) +3. [Memory](#memory) +4. [MCP Protocol](#mcp-protocol) +5. [Agent Skills](#agent-skills) +6. [Plugins](#claude-code-plugins) +7. [Hooks](#hooks) +8. [Checkpoints and Rewind](#checkpoints-and-rewind) +9. [Advanced Features](#advanced-features) +10. [Comparison & Integration](#comparison--integration) + +--- + +## Slash Commands + +### Overview + +Slash commands are user-invoked shortcuts stored as Markdown files that Claude Code can execute. They enable teams to standardize frequently-used prompts and workflows. + +### Architecture + +```mermaid +graph TD + A["User Input: /command-name"] -->|Triggers| B["Search .claude/commands/"] + B -->|Finds| C["command-name.md"] + C -->|Loads| D["Markdown Content"] + D -->|Executes| E["Claude Processes Prompt"] + E -->|Returns| F["Result in Context"] +``` + +### File Structure + +```mermaid +graph LR + A["Project Root"] -->|contains| B[".claude/commands/"] + B -->|contains| C["optimize.md"] + B -->|contains| D["test.md"] + B -->|contains| E["docs/"] + E -->|contains| F["generate-api-docs.md"] + E -->|contains| G["generate-readme.md"] +``` + +### Command Organization Table + +| Location | Scope | Availability | Use Case | Git Tracked | +|----------|-------|--------------|----------|-------------| +| `.claude/commands/` | Project-specific | Team members | Team workflows, shared standards | ✅ Yes | +| `~/.claude/commands/` | Personal | Individual user | Personal shortcuts across projects | ❌ No | +| Subdirectories | Namespaced | Based on parent | Organize by category | ✅ Yes | + +### Features & Capabilities + +| Feature | Example | Supported | +|---------|---------|-----------| +| Shell script execution | `bash scripts/deploy.sh` | ✅ Yes | +| File references | `@path/to/file.js` | ✅ Yes | +| Bash integration | `$(git log --oneline)` | ✅ Yes | +| Arguments | `/pr --verbose` | ✅ Yes | +| MCP commands | `/mcp__github__list_prs` | ✅ Yes | + +### Practical Examples + +#### Example 1: Code Optimization Command + +**File:** `.claude/commands/optimize.md` + +```markdown +--- +name: Code Optimization +description: Analyze code for performance issues and suggest optimizations +tags: performance, analysis +--- + +# Code Optimization + +Review the provided code for the following issues in order of priority: + +1. **Performance bottlenecks** - identify O(n²) operations, inefficient loops +2. **Memory leaks** - find unreleased resources, circular references +3. **Algorithm improvements** - suggest better algorithms or data structures +4. **Caching opportunities** - identify repeated computations +5. **Concurrency issues** - find race conditions or threading problems + +Format your response with: +- Issue severity (Critical/High/Medium/Low) +- Location in code +- Explanation +- Recommended fix with code example +``` + +**Usage:** +```bash +# User types in Claude Code +/optimize + +# Claude loads the prompt and waits for code input +``` + +#### Example 2: Pull Request Helper Command + +**File:** `.claude/commands/pr.md` + +```markdown +--- +name: Prepare Pull Request +description: Clean up code, stage changes, and prepare a pull request +tags: git, workflow +--- + +# Pull Request Preparation Checklist + +Before creating a PR, execute these steps: + +1. Run linting: `prettier --write .` +2. Run tests: `npm test` +3. Review git diff: `git diff HEAD` +4. Stage changes: `git add .` +5. Create commit message following conventional commits: + - `fix:` for bug fixes + - `feat:` for new features + - `docs:` for documentation + - `refactor:` for code restructuring + - `test:` for test additions + - `chore:` for maintenance + +6. Generate PR summary including: + - What changed + - Why it changed + - Testing performed + - Potential impacts +``` + +**Usage:** +```bash +/pr + +# Claude runs through checklist and prepares the PR +``` + +#### Example 3: Hierarchical Documentation Generator + +**File:** `.claude/commands/docs/generate-api-docs.md` + +```markdown +--- +name: Generate API Documentation +description: Create comprehensive API documentation from source code +tags: documentation, api +--- + +# API Documentation Generator + +Generate API documentation by: + +1. Scanning all files in `/src/api/` +2. Extracting function signatures and JSDoc comments +3. Organizing by endpoint/module +4. Creating markdown with examples +5. Including request/response schemas +6. Adding error documentation + +Output format: +- Markdown file in `/docs/api.md` +- Include curl examples for all endpoints +- Add TypeScript types +``` + +### Command Lifecycle Diagram + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant FS as File System + participant CLI as Shell/Bash + + User->>Claude: Types /optimize + Claude->>FS: Searches .claude/commands/ + FS-->>Claude: Returns optimize.md + Claude->>Claude: Loads Markdown content + Claude->>User: Displays prompt context + User->>Claude: Provides code to analyze + Claude->>CLI: (May execute scripts) + CLI-->>Claude: Results + Claude->>User: Returns analysis +``` + +### Best Practices + +| ✅ Do | ❌ Don't | +|------|---------| +| Use clear, action-oriented names | Create commands for one-time tasks | +| Document trigger words in description | Build complex logic in commands | +| Keep commands focused on single task | Create redundant commands | +| Version control project commands | Hardcode sensitive information | +| Organize in subdirectories | Create long lists of commands | +| Use simple, readable prompts | Use abbreviated or cryptic wording | + +--- + +## Subagents + +### Overview + +Subagents are specialized AI assistants with isolated context windows and customized system prompts. They enable delegated task execution while maintaining clean separation of concerns. + +### Architecture Diagram + +```mermaid +graph TB + User["👤 User"] + Main["🎯 Main Agent
(Coordinator)"] + Reviewer["🔍 Code Reviewer
Subagent"] + Tester["✅ Test Engineer
Subagent"] + Docs["📝 Documentation
Subagent"] + + User -->|asks| Main + Main -->|delegates| Reviewer + Main -->|delegates| Tester + Main -->|delegates| Docs + Reviewer -->|returns result| Main + Tester -->|returns result| Main + Docs -->|returns result| Main + Main -->|synthesizes| User +``` + +### Subagent Lifecycle + +```mermaid +sequenceDiagram + participant User + participant MainAgent as Main Agent + participant CodeReviewer as Code Reviewer
Subagent + participant Context as Separate
Context Window + + User->>MainAgent: "Build new auth feature" + MainAgent->>MainAgent: Analyze task + MainAgent->>CodeReviewer: "Review this code" + CodeReviewer->>Context: Initialize clean context + Context->>CodeReviewer: Load reviewer instructions + CodeReviewer->>CodeReviewer: Perform review + CodeReviewer-->>MainAgent: Return findings + MainAgent->>MainAgent: Incorporate results + MainAgent-->>User: Provide synthesis +``` + +### Subagent Configuration Table + +| Configuration | Type | Purpose | Example | +|---------------|------|---------|---------| +| `name` | String | Agent identifier | `code-reviewer` | +| `description` | String | Purpose & trigger terms | `Comprehensive code quality analysis` | +| `tools` | List/String | Allowed capabilities | `read, grep, diff, lint_runner` | +| `system_prompt` | Markdown | Behavioral instructions | Custom guidelines | + +### Tool Access Hierarchy + +```mermaid +graph TD + A["Subagent Configuration"] -->|Option 1| B["Inherit All Tools
from Main Thread"] + A -->|Option 2| C["Specify Individual Tools"] + B -->|Includes| B1["File Operations"] + B -->|Includes| B2["Shell Commands"] + B -->|Includes| B3["MCP Tools"] + C -->|Explicit List| C1["read, grep, diff"] + C -->|Explicit List| C2["Bash(npm:*), Bash(test:*)"] +``` + +### Practical Examples + +#### Example 1: Complete Subagent Setup + +**File:** `.claude/agents/code-reviewer.md` + +```yaml +--- +name: code-reviewer +description: Comprehensive code quality and maintainability analysis +tools: read, grep, diff, lint_runner +--- + +# Code Reviewer Agent + +You are an expert code reviewer specializing in: +- Performance optimization +- Security vulnerabilities +- Code maintainability +- Testing coverage +- Design patterns + +## Review Priorities (in order) + +1. **Security Issues** - Authentication, authorization, data exposure +2. **Performance Problems** - O(n²) operations, memory leaks, inefficient queries +3. **Code Quality** - Readability, naming, documentation +4. **Test Coverage** - Missing tests, edge cases +5. **Design Patterns** - SOLID principles, architecture + +## Review Output Format + +For each issue: +- **Severity**: Critical / High / Medium / Low +- **Category**: Security / Performance / Quality / Testing / Design +- **Location**: File path and line number +- **Issue Description**: What's wrong and why +- **Suggested Fix**: Code example +- **Impact**: How this affects the system + +## Example Review + +### Issue: N+1 Query Problem +- **Severity**: High +- **Category**: Performance +- **Location**: src/user-service.ts:45 +- **Issue**: Loop executes database query in each iteration +- **Fix**: Use JOIN or batch query +``` + +**File:** `.claude/agents/test-engineer.md` + +```yaml +--- +name: test-engineer +description: Test strategy, coverage analysis, and automated testing +tools: read, write, bash, grep +--- + +# Test Engineer Agent + +You are expert at: +- Writing comprehensive test suites +- Ensuring high code coverage (>80%) +- Testing edge cases and error scenarios +- Performance benchmarking +- Integration testing + +## Testing Strategy + +1. **Unit Tests** - Individual functions/methods +2. **Integration Tests** - Component interactions +3. **End-to-End Tests** - Complete workflows +4. **Edge Cases** - Boundary conditions +5. **Error Scenarios** - Failure handling + +## Test Output Requirements + +- Use Jest for JavaScript/TypeScript +- Include setup/teardown for each test +- Mock external dependencies +- Document test purpose +- Include performance assertions when relevant + +## Coverage Requirements + +- Minimum 80% code coverage +- 100% for critical paths +- Report missing coverage areas +``` + +**File:** `.claude/agents/documentation-writer.md` + +```yaml +--- +name: documentation-writer +description: Technical documentation, API docs, and user guides +tools: read, write, grep +--- + +# Documentation Writer Agent + +You create: +- API documentation with examples +- User guides and tutorials +- Architecture documentation +- Changelog entries +- Code comment improvements + +## Documentation Standards + +1. **Clarity** - Use simple, clear language +2. **Examples** - Include practical code examples +3. **Completeness** - Cover all parameters and returns +4. **Structure** - Use consistent formatting +5. **Accuracy** - Verify against actual code + +## Documentation Sections + +### For APIs +- Description +- Parameters (with types) +- Returns (with types) +- Throws (possible errors) +- Examples (curl, JavaScript, Python) +- Related endpoints + +### For Features +- Overview +- Prerequisites +- Step-by-step instructions +- Expected outcomes +- Troubleshooting +- Related topics +``` + +#### Example 2: Subagent Delegation in Action + +```markdown +# Scenario: Building a Payment Feature + +## User Request +"Build a secure payment processing feature that integrates with Stripe" + +## Main Agent Flow + +1. **Planning Phase** + - Understands requirements + - Determines tasks needed + - Plans architecture + +2. **Delegates to Code Reviewer Subagent** + - Task: "Review the payment processing implementation for security" + - Context: Auth, API keys, token handling + - Reviews for: SQL injection, key exposure, HTTPS enforcement + +3. **Delegates to Test Engineer Subagent** + - Task: "Create comprehensive tests for payment flows" + - Context: Success scenarios, failures, edge cases + - Creates tests for: Valid payments, declined cards, network failures, webhooks + +4. **Delegates to Documentation Writer Subagent** + - Task: "Document the payment API endpoints" + - Context: Request/response schemas + - Produces: API docs with curl examples, error codes + +5. **Synthesis** + - Main agent collects all outputs + - Integrates findings + - Returns complete solution to user +``` + +#### Example 3: Tool Permission Scoping + +**Restrictive Setup - Limited to Specific Commands** + +```yaml +--- +name: secure-reviewer +description: Security-focused code review with minimal permissions +tools: read, grep +--- + +# Secure Code Reviewer + +Reviews code for security vulnerabilities only. + +This agent: +- ✅ Reads files to analyze +- ✅ Searches for patterns +- ❌ Cannot execute code +- ❌ Cannot modify files +- ❌ Cannot run tests + +This ensures the reviewer doesn't accidentally break anything. +``` + +**Extended Setup - All Tools for Implementation** + +```yaml +--- +name: implementation-agent +description: Full implementation capabilities for feature development +tools: read, write, bash, grep, edit, glob +--- + +# Implementation Agent + +Builds features from specifications. + +This agent: +- ✅ Reads specifications +- ✅ Writes new code files +- ✅ Runs build commands +- ✅ Searches codebase +- ✅ Edits existing files +- ✅ Finds files matching patterns + +Full capabilities for independent feature development. +``` + +### Subagent Context Management + +```mermaid +graph TB + A["Main Agent Context
50,000 tokens"] + B["Subagent 1 Context
20,000 tokens"] + C["Subagent 2 Context
20,000 tokens"] + D["Subagent 3 Context
20,000 tokens"] + + A -->|Clean slate| B + A -->|Clean slate| C + A -->|Clean slate| D + + B -->|Results only| A + C -->|Results only| A + D -->|Results only| A + + style A fill:#e1f5ff + style B fill:#fff9c4 + style C fill:#fff9c4 + style D fill:#fff9c4 +``` + +### When to Use Subagents + +| Scenario | Use Subagent | Why | +|----------|--------------|-----| +| Complex feature with many steps | ✅ Yes | Separate concerns, prevent context pollution | +| Quick code review | ❌ No | Not necessary overhead | +| Parallel task execution | ✅ Yes | Each subagent has own context | +| Specialized expertise needed | ✅ Yes | Custom system prompts | +| Long-running analysis | ✅ Yes | Prevents main context exhaustion | +| Single task | ❌ No | Adds latency unnecessarily | + +### Agent Teams + +Agent Teams coordinate multiple agents working on related tasks. Rather than delegating to one subagent at a time, Agent Teams allow the main agent to orchestrate a group of agents that collaborate, share intermediate results, and work toward a common goal. This is useful for large-scale tasks like full-stack feature development where a frontend agent, backend agent, and testing agent work in parallel. + +--- + +## Memory + +### Overview + +Memory enables Claude to retain context across sessions and conversations. It exists in two forms: automatic synthesis in claude.ai, and filesystem-based CLAUDE.md in Claude Code. + +### Memory Architecture + +```mermaid +graph TB + A["Claude Session"] + B["User Input"] + C["Memory System"] + D["Memory Storage"] + + B -->|User provides info| C + C -->|Synthesizes every 24h| D + D -->|Loads automatically| A + A -->|Uses context| C +``` + +### Memory Hierarchy in Claude Code (7 Tiers) + +Claude Code loads memory from 7 tiers, listed from highest to lowest priority: + +```mermaid +graph TD + A["1. Managed Policy
Enterprise admin policies"] --> B["2. Project Memory
./CLAUDE.md"] + B --> C["3. Project Rules
.claude/rules/*.md"] + C --> D["4. User Memory
~/.claude/CLAUDE.md"] + D --> E["5. User Rules
~/.claude/rules/*.md"] + E --> F["6. Local Memory
.claude/local/CLAUDE.md"] + F --> G["7. Auto Memory
Automatically captured preferences"] + + style A fill:#fce4ec,stroke:#333,color:#333 + style B fill:#e1f5fe,stroke:#333,color:#333 + style C fill:#e1f5fe,stroke:#333,color:#333 + style D fill:#f3e5f5,stroke:#333,color:#333 + style E fill:#f3e5f5,stroke:#333,color:#333 + style F fill:#e8f5e9,stroke:#333,color:#333 + style G fill:#fff3e0,stroke:#333,color:#333 +``` + +### Memory Locations Table + +| Tier | Location | Scope | Priority | Shared | Best For | +|------|----------|-------|----------|--------|----------| +| 1. Managed Policy | Enterprise admin | Organization | Highest | All org users | Compliance, security policies | +| 2. Project | `./CLAUDE.md` | Project | High | Team (Git) | Team standards, architecture | +| 3. Project Rules | `.claude/rules/*.md` | Project | High | Team (Git) | Modular project conventions | +| 4. User | `~/.claude/CLAUDE.md` | Personal | Medium | Individual | Personal preferences | +| 5. User Rules | `~/.claude/rules/*.md` | Personal | Medium | Individual | Personal rule modules | +| 6. Local | `.claude/local/CLAUDE.md` | Local | Low | Not shared | Machine-specific settings | +| 7. Auto Memory | Automatic | Session | Lowest | Individual | Learned preferences, patterns | + +### Auto Memory + +Auto Memory automatically captures user preferences and patterns observed during sessions. Claude learns from your interactions and remembers: + +- Coding style preferences +- Common corrections you make +- Framework and tool choices +- Communication style preferences + +Auto Memory works in the background and does not require manual configuration. + +### Memory Update Lifecycle + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Editor as File System + participant Memory as CLAUDE.md + + User->>Claude: "Remember: use async/await" + Claude->>User: "Which memory file?" + User->>Claude: "Project memory" + Claude->>Editor: Open ~/.claude/settings.json + Claude->>Memory: Write to ./CLAUDE.md + Memory-->>Claude: File saved + Claude->>Claude: Load updated memory + Claude-->>User: "Memory saved!" +``` + +### Practical Examples + +#### Example 1: Project Memory Structure + +**File:** `./CLAUDE.md` + +```markdown +# Project Configuration + +## Project Overview +- **Name**: E-commerce Platform +- **Tech Stack**: Node.js, PostgreSQL, React 18, Docker +- **Team Size**: 5 developers +- **Deadline**: Q4 2025 + +## Architecture +@docs/architecture.md +@docs/api-standards.md +@docs/database-schema.md + +## Development Standards + +### Code Style +- Use Prettier for formatting +- Use ESLint with airbnb config +- Maximum line length: 100 characters +- Use 2-space indentation + +### Naming Conventions +- **Files**: kebab-case (user-controller.js) +- **Classes**: PascalCase (UserService) +- **Functions/Variables**: camelCase (getUserById) +- **Constants**: UPPER_SNAKE_CASE (API_BASE_URL) +- **Database Tables**: snake_case (user_accounts) + +### Git Workflow +- Branch names: `feature/description` or `fix/description` +- Commit messages: Follow conventional commits +- PR required before merge +- All CI/CD checks must pass +- Minimum 1 approval required + +### Testing Requirements +- Minimum 80% code coverage +- All critical paths must have tests +- Use Jest for unit tests +- Use Cypress for E2E tests +- Test filenames: `*.test.ts` or `*.spec.ts` + +### API Standards +- RESTful endpoints only +- JSON request/response +- Use HTTP status codes correctly +- Version API endpoints: `/api/v1/` +- Document all endpoints with examples + +### Database +- Use migrations for schema changes +- Never hardcode credentials +- Use connection pooling +- Enable query logging in development +- Regular backups required + +### Deployment +- Docker-based deployment +- Kubernetes orchestration +- Blue-green deployment strategy +- Automatic rollback on failure +- Database migrations run before deploy + +## Common Commands + +| Command | Purpose | +|---------|---------| +| `npm run dev` | Start development server | +| `npm test` | Run test suite | +| `npm run lint` | Check code style | +| `npm run build` | Build for production | +| `npm run migrate` | Run database migrations | + +## Team Contacts +- Tech Lead: Sarah Chen (@sarah.chen) +- Product Manager: Mike Johnson (@mike.j) +- DevOps: Alex Kim (@alex.k) + +## Known Issues & Workarounds +- PostgreSQL connection pooling limited to 20 during peak hours +- Workaround: Implement query queuing +- Safari 14 compatibility issues with async generators +- Workaround: Use Babel transpiler + +## Related Projects +- Analytics Dashboard: `/projects/analytics` +- Mobile App: `/projects/mobile` +- Admin Panel: `/projects/admin` +``` + +#### Example 2: Directory-Specific Memory + +**File:** `./src/api/CLAUDE.md` + +~~~~markdown +# API Module Standards + +This file overrides root CLAUDE.md for everything in /src/api/ + +## API-Specific Standards + +### Request Validation +- Use Zod for schema validation +- Always validate input +- Return 400 with validation errors +- Include field-level error details + +### Authentication +- All endpoints require JWT token +- Token in Authorization header +- Token expires after 24 hours +- Implement refresh token mechanism + +### Response Format + +All responses must follow this structure: + +```json +{ + "success": true, + "data": { /* actual data */ }, + "timestamp": "2025-11-06T10:30:00Z", + "version": "1.0" +} +``` + +### Error responses: +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "User message", + "details": { /* field errors */ } + }, + "timestamp": "2025-11-06T10:30:00Z" +} +``` + +### Pagination +- Use cursor-based pagination (not offset) +- Include `hasMore` boolean +- Limit max page size to 100 +- Default page size: 20 + +### Rate Limiting +- 1000 requests per hour for authenticated users +- 100 requests per hour for public endpoints +- Return 429 when exceeded +- Include retry-after header + +### Caching +- Use Redis for session caching +- Cache duration: 5 minutes default +- Invalidate on write operations +- Tag cache keys with resource type +~~~~ + +#### Example 3: Personal Memory + +**File:** `~/.claude/CLAUDE.md` + +~~~~markdown +# My Development Preferences + +## About Me +- **Experience Level**: 8 years full-stack development +- **Preferred Languages**: TypeScript, Python +- **Communication Style**: Direct, with examples +- **Learning Style**: Visual diagrams with code + +## Code Preferences + +### Error Handling +I prefer explicit error handling with try-catch blocks and meaningful error messages. +Avoid generic errors. Always log errors for debugging. + +### Comments +Use comments for WHY, not WHAT. Code should be self-documenting. +Comments should explain business logic or non-obvious decisions. + +### Testing +I prefer TDD (test-driven development). +Write tests first, then implementation. +Focus on behavior, not implementation details. + +### Architecture +I prefer modular, loosely-coupled design. +Use dependency injection for testability. +Separate concerns (Controllers, Services, Repositories). + +## Debugging Preferences +- Use console.log with prefix: `[DEBUG]` +- Include context: function name, relevant variables +- Use stack traces when available +- Always include timestamps in logs + +## Communication +- Explain complex concepts with diagrams +- Show concrete examples before explaining theory +- Include before/after code snippets +- Summarize key points at the end + +## Project Organization +I organize my projects as: +``` +project/ + ├── src/ + │ ├── api/ + │ ├── services/ + │ ├── models/ + │ └── utils/ + ├── tests/ + ├── docs/ + └── docker/ +``` + +## Tooling +- **IDE**: VS Code with vim keybindings +- **Terminal**: Zsh with Oh-My-Zsh +- **Format**: Prettier (100 char line length) +- **Linter**: ESLint with airbnb config +- **Test Framework**: Jest with React Testing Library +~~~~ + +#### Example 4: Memory Update During Session + +**Session Interaction:** + +```markdown +User: Remember that I prefer using React hooks instead of class components + for all new components. + +Claude: I'm adding that to your memory. Which memory file should this go in? + 1. Project memory (./CLAUDE.md) + 2. Personal memory (~/.claude/CLAUDE.md) + +User: Project memory + +Claude: ✅ Memory saved! + +Added to ./CLAUDE.md: +--- + +### Component Development +- Use functional components with React Hooks +- Prefer hooks over class components +- Custom hooks for reusable logic +- Use useCallback for event handlers +- Use useMemo for expensive computations +``` + +### Memory in Claude Web/Desktop + +#### Memory Synthesis Timeline + +```mermaid +graph LR + A["Day 1: User
Conversations"] -->|24 hours| B["Day 2: Memory
Synthesis"] + B -->|Automatic| C["Memory Updated
Summarized"] + C -->|Loaded in| D["Day 2-N:
New Conversations"] + D -->|Add to| E["Memory"] + E -->|24 hours later| F["Memory Refreshed"] +``` + +**Example Memory Summary:** + +```markdown +## Claude's Memory of User + +### Professional Background +- Senior full-stack developer with 8 years experience +- Focus on TypeScript/Node.js backends and React frontends +- Active open source contributor +- Interested in AI and machine learning + +### Project Context +- Currently building e-commerce platform +- Tech stack: Node.js, PostgreSQL, React 18, Docker +- Working with team of 5 developers +- Using CI/CD and blue-green deployments + +### Communication Preferences +- Prefers direct, concise explanations +- Likes visual diagrams and examples +- Appreciates code snippets +- Explains business logic in comments + +### Current Goals +- Improve API performance +- Increase test coverage to 90% +- Implement caching strategy +- Document architecture +``` + +### Memory Features Comparison + +| Feature | Claude Web/Desktop | Claude Code (CLAUDE.md) | +|---------|-------------------|------------------------| +| Auto-synthesis | ✅ Every 24h | ❌ Manual | +| Cross-project | ✅ Shared | ❌ Project-specific | +| Team access | ✅ Shared projects | ✅ Git-tracked | +| Searchable | ✅ Built-in | ✅ Through `/memory` | +| Editable | ✅ In-chat | ✅ Direct file edit | +| Import/Export | ✅ Yes | ✅ Copy/paste | +| Persistent | ✅ 24h+ | ✅ Indefinite | + +--- + +## MCP Protocol + +### Overview + +MCP (Model Context Protocol) is a standardized way for Claude to access external tools, APIs, and real-time data sources. Unlike Memory, MCP provides live access to changing data. + +### MCP Architecture + +```mermaid +graph TB + A["Claude"] + B["MCP Server"] + C["External Service"] + + A -->|Request: list_issues| B + B -->|Query| C + C -->|Data| B + B -->|Response| A + + A -->|Request: create_issue| B + B -->|Action| C + C -->|Result| B + B -->|Response| A +``` + +### MCP Ecosystem + +```mermaid +graph TB + A["Claude"] -->|MCP| B["Filesystem
MCP Server"] + A -->|MCP| C["GitHub
MCP Server"] + A -->|MCP| D["Database
MCP Server"] + A -->|MCP| E["Slack
MCP Server"] + A -->|MCP| F["Google Docs
MCP Server"] + + B -->|File I/O| G["Local Files"] + C -->|API| H["GitHub Repos"] + D -->|Query| I["PostgreSQL/MySQL"] + E -->|Messages| J["Slack Workspace"] + F -->|Docs| K["Google Drive"] +``` + +### MCP Setup Process + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Config as Config File + participant Service as External Service + + User->>Claude: Type /mcp + Claude->>Claude: List available MCP servers + Claude->>User: Show options + User->>Claude: Select GitHub MCP + Claude->>Config: Update configuration + Config->>Claude: Activate connection + Claude->>Service: Test connection + Service-->>Claude: Authentication successful + Claude->>User: ✅ MCP connected! +``` + +### Available MCP Servers Table + +| MCP Server | Purpose | Common Tools | Auth | Real-time | +|------------|---------|--------------|------|-----------| +| **Filesystem** | File operations | read, write, delete | OS permissions | ✅ Yes | +| **GitHub** | Repository management | list_prs, create_issue, push | OAuth | ✅ Yes | +| **Slack** | Team communication | send_message, list_channels | Token | ✅ Yes | +| **Database** | SQL queries | query, insert, update | Credentials | ✅ Yes | +| **Google Docs** | Document access | read, write, share | OAuth | ✅ Yes | +| **Asana** | Project management | create_task, update_status | API Key | ✅ Yes | +| **Stripe** | Payment data | list_charges, create_invoice | API Key | ✅ Yes | +| **Memory** | Persistent memory | store, retrieve, delete | Local | ❌ No | + +### Practical Examples + +#### Example 1: GitHub MCP Configuration + +**File:** `.mcp.json` (project scope) or `~/.claude.json` (user scope) + +```json +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["@modelcontextprotocol/server-github"], + "env": { + "GITHUB_TOKEN": "${GITHUB_TOKEN}" + } + } + } +} +``` + +**Available GitHub MCP Tools:** + +~~~~markdown +# GitHub MCP Tools + +## Pull Request Management +- `list_prs` - List all PRs in repository +- `get_pr` - Get PR details including diff +- `create_pr` - Create new PR +- `update_pr` - Update PR description/title +- `merge_pr` - Merge PR to main branch +- `review_pr` - Add review comments + +Example request: +``` +/mcp__github__get_pr 456 + +# Returns: +Title: Add dark mode support +Author: @alice +Description: Implements dark theme using CSS variables +Status: OPEN +Reviewers: @bob, @charlie +``` + +## Issue Management +- `list_issues` - List all issues +- `get_issue` - Get issue details +- `create_issue` - Create new issue +- `close_issue` - Close issue +- `add_comment` - Add comment to issue + +## Repository Information +- `get_repo_info` - Repository details +- `list_files` - File tree structure +- `get_file_content` - Read file contents +- `search_code` - Search across codebase + +## Commit Operations +- `list_commits` - Commit history +- `get_commit` - Specific commit details +- `create_commit` - Create new commit +~~~~ + +#### Example 2: Database MCP Setup + +**Configuration:** + +```json +{ + "mcpServers": { + "database": { + "command": "npx", + "args": ["@modelcontextprotocol/server-database"], + "env": { + "DATABASE_URL": "postgresql://user:pass@localhost/mydb" + } + } + } +} +``` + +**Example Usage:** + +```markdown +User: Fetch all users with more than 10 orders + +Claude: I'll query your database to find that information. + +# Using MCP database tool: +SELECT u.*, COUNT(o.id) as order_count +FROM users u +LEFT JOIN orders o ON u.id = o.user_id +GROUP BY u.id +HAVING COUNT(o.id) > 10 +ORDER BY order_count DESC; + +# Results: +- Alice: 15 orders +- Bob: 12 orders +- Charlie: 11 orders +``` + +#### Example 3: Multi-MCP Workflow + +**Scenario: Daily Report Generation** + +```markdown +# Daily Report Workflow using Multiple MCPs + +## Setup +1. GitHub MCP - fetch PR metrics +2. Database MCP - query sales data +3. Slack MCP - post report +4. Filesystem MCP - save report + +## Workflow + +### Step 1: Fetch GitHub Data +/mcp__github__list_prs completed:true last:7days + +Output: +- Total PRs: 42 +- Average merge time: 2.3 hours +- Review turnaround: 1.1 hours + +### Step 2: Query Database +SELECT COUNT(*) as sales, SUM(amount) as revenue +FROM orders +WHERE created_at > NOW() - INTERVAL '1 day' + +Output: +- Sales: 247 +- Revenue: $12,450 + +### Step 3: Generate Report +Combine data into HTML report + +### Step 4: Save to Filesystem +Write report.html to /reports/ + +### Step 5: Post to Slack +Send summary to #daily-reports channel + +Final Output: +✅ Report generated and posted +📊 47 PRs merged this week +💰 $12,450 in daily sales +``` + +#### Example 4: Filesystem MCP Operations + +**Configuration:** + +```json +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["@modelcontextprotocol/server-filesystem", "/home/user/projects"] + } + } +} +``` + +**Available Operations:** + +| Operation | Command | Purpose | +|-----------|---------|---------| +| List files | `ls ~/projects` | Show directory contents | +| Read file | `cat src/main.ts` | Read file contents | +| Write file | `create docs/api.md` | Create new file | +| Edit file | `edit src/app.ts` | Modify file | +| Search | `grep "async function"` | Search in files | +| Delete | `rm old-file.js` | Delete file | + +### MCP vs Memory: Decision Matrix + +```mermaid +graph TD + A["Need external data?"] + A -->|No| B["Use Memory"] + A -->|Yes| C["Does it change frequently?"] + C -->|No/Rarely| B + C -->|Yes/Often| D["Use MCP"] + + B -->|Stores| E["Preferences
Context
History"] + D -->|Accesses| F["Live APIs
Databases
Services"] + + style B fill:#e1f5ff + style D fill:#fff9c4 +``` + +### Request/Response Pattern + +```mermaid +sequenceDiagram + participant App as Claude + participant MCP as MCP Server + participant DB as Database + + App->>MCP: Request: "SELECT * FROM users WHERE id=1" + MCP->>DB: Execute query + DB-->>MCP: Result set + MCP-->>App: Return parsed data + App->>App: Process result + App->>App: Continue task + + Note over MCP,DB: Real-time access
No caching +``` + +--- + +## Agent Skills + +### Overview + +Agent Skills are reusable, model-invoked capabilities packaged as folders containing instructions, scripts, and resources. Claude automatically detects and uses relevant skills. + +### Skill Architecture + +```mermaid +graph TB + A["Skill Directory"] + B["SKILL.md"] + C["YAML Metadata"] + D["Instructions"] + E["Scripts"] + F["Templates"] + + A --> B + B --> C + B --> D + E --> A + F --> A +``` + +### Skill Loading Process + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude + participant System as System + participant Skill as Skill + + User->>Claude: "Create Excel report" + Claude->>System: Scan available skills + System->>System: Load skill metadata + Claude->>Claude: Match user request to skills + Claude->>Skill: Load xlsx skill SKILL.md + Skill-->>Claude: Return instructions + tools + Claude->>Claude: Execute skill + Claude->>User: Generate Excel file +``` + +### Skill Types & Locations Table + +| Type | Location | Scope | Shared | Sync | Best For | +|------|----------|-------|--------|------|----------| +| Pre-built | Built-in | Global | All users | Auto | Document creation | +| Personal | `~/.claude/skills/` | Individual | No | Manual | Personal automation | +| Project | `.claude/skills/` | Team | Yes | Git | Team standards | +| Plugin | Via plugin install | Varies | Depends | Auto | Integrated features | + +### Pre-built Skills + +```mermaid +graph TB + A["Pre-built Skills"] + B["PowerPoint (pptx)"] + C["Excel (xlsx)"] + D["Word (docx)"] + E["PDF"] + + A --> B + A --> C + A --> D + A --> E + + B --> B1["Create presentations"] + B --> B2["Edit slides"] + C --> C1["Create spreadsheets"] + C --> C2["Analyze data"] + D --> D1["Create documents"] + D --> D2["Format text"] + E --> E1["Generate PDFs"] + E --> E2["Fill forms"] +``` + +### Bundled Skills + +Claude Code now includes 5 bundled skills available out of the box: + +| Skill | Command | Purpose | +|-------|---------|---------| +| **Simplify** | `/simplify` | Simplify complex code or explanations | +| **Batch** | `/batch` | Run operations across multiple files or items | +| **Debug** | `/debug` | Systematic debugging of issues with root cause analysis | +| **Loop** | `/loop` | Schedule recurring tasks on a timer | +| **Claude API** | `/claude-api` | Interact with the Anthropic API directly | + +These bundled skills are always available and do not require installation or configuration. + +### Practical Examples + +#### Example 1: Custom Code Review Skill + +**Directory Structure:** + +``` +~/.claude/skills/code-review/ +├── SKILL.md +├── templates/ +│ ├── review-checklist.md +│ └── finding-template.md +└── scripts/ + ├── analyze-metrics.py + └── compare-complexity.py +``` + +**File:** `~/.claude/skills/code-review/SKILL.md` + +```yaml +--- +name: Code Review Specialist +description: Comprehensive code review with security, performance, and quality analysis +version: "1.0.0" +tags: + - code-review + - quality + - security +when_to_use: When users ask to review code, analyze code quality, or evaluate pull requests +effort: high +shell: bash +--- + +# Code Review Skill + +This skill provides comprehensive code review capabilities focusing on: + +1. **Security Analysis** + - Authentication/authorization issues + - Data exposure risks + - Injection vulnerabilities + - Cryptographic weaknesses + - Sensitive data logging + +2. **Performance Review** + - Algorithm efficiency (Big O analysis) + - Memory optimization + - Database query optimization + - Caching opportunities + - Concurrency issues + +3. **Code Quality** + - SOLID principles + - Design patterns + - Naming conventions + - Documentation + - Test coverage + +4. **Maintainability** + - Code readability + - Function size (should be < 50 lines) + - Cyclomatic complexity + - Dependency management + - Type safety + +## Review Template + +For each piece of code reviewed, provide: + +### Summary +- Overall quality assessment (1-5) +- Key findings count +- Recommended priority areas + +### Critical Issues (if any) +- **Issue**: Clear description +- **Location**: File and line number +- **Impact**: Why this matters +- **Severity**: Critical/High/Medium +- **Fix**: Code example + +### Findings by Category + +#### Security (if issues found) +List security vulnerabilities with examples + +#### Performance (if issues found) +List performance problems with complexity analysis + +#### Quality (if issues found) +List code quality issues with refactoring suggestions + +#### Maintainability (if issues found) +List maintainability problems with improvements +``` +## Python Script: analyze-metrics.py + +```python +#!/usr/bin/env python3 +import re +import sys + +def analyze_code_metrics(code): + """Analyze code for common metrics.""" + + # Count functions + functions = len(re.findall(r'^def\s+\w+', code, re.MULTILINE)) + + # Count classes + classes = len(re.findall(r'^class\s+\w+', code, re.MULTILINE)) + + # Average line length + lines = code.split('\n') + avg_length = sum(len(l) for l in lines) / len(lines) if lines else 0 + + # Estimate complexity + complexity = len(re.findall(r'\b(if|elif|else|for|while|and|or)\b', code)) + + return { + 'functions': functions, + 'classes': classes, + 'avg_line_length': avg_length, + 'complexity_score': complexity + } + +if __name__ == '__main__': + with open(sys.argv[1], 'r') as f: + code = f.read() + metrics = analyze_code_metrics(code) + for key, value in metrics.items(): + print(f"{key}: {value:.2f}") +``` + +## Python Script: compare-complexity.py + +```python +#!/usr/bin/env python3 +""" +Compare cyclomatic complexity of code before and after changes. +Helps identify if refactoring actually simplifies code structure. +""" + +import re +import sys +from typing import Dict, Tuple + +class ComplexityAnalyzer: + """Analyze code complexity metrics.""" + + def __init__(self, code: str): + self.code = code + self.lines = code.split('\n') + + def calculate_cyclomatic_complexity(self) -> int: + """ + Calculate cyclomatic complexity using McCabe's method. + Count decision points: if, elif, else, for, while, except, and, or + """ + complexity = 1 # Base complexity + + # Count decision points + decision_patterns = [ + r'\bif\b', + r'\belif\b', + r'\bfor\b', + r'\bwhile\b', + r'\bexcept\b', + r'\band\b(?!$)', + r'\bor\b(?!$)' + ] + + for pattern in decision_patterns: + matches = re.findall(pattern, self.code) + complexity += len(matches) + + return complexity + + def calculate_cognitive_complexity(self) -> int: + """ + Calculate cognitive complexity - how hard is it to understand? + Based on nesting depth and control flow. + """ + cognitive = 0 + nesting_depth = 0 + + for line in self.lines: + # Track nesting depth + if re.search(r'^\s*(if|for|while|def|class|try)\b', line): + nesting_depth += 1 + cognitive += nesting_depth + elif re.search(r'^\s*(elif|else|except|finally)\b', line): + cognitive += nesting_depth + + # Reduce nesting when unindenting + if line and not line[0].isspace(): + nesting_depth = 0 + + return cognitive + + def calculate_maintainability_index(self) -> float: + """ + Maintainability Index ranges from 0-100. + > 85: Excellent + > 65: Good + > 50: Fair + < 50: Poor + """ + lines = len(self.lines) + cyclomatic = self.calculate_cyclomatic_complexity() + cognitive = self.calculate_cognitive_complexity() + + # Simplified MI calculation + mi = 171 - 5.2 * (cyclomatic / lines) - 0.23 * (cognitive) - 16.2 * (lines / 1000) + + return max(0, min(100, mi)) + + def get_complexity_report(self) -> Dict: + """Generate comprehensive complexity report.""" + return { + 'cyclomatic_complexity': self.calculate_cyclomatic_complexity(), + 'cognitive_complexity': self.calculate_cognitive_complexity(), + 'maintainability_index': round(self.calculate_maintainability_index(), 2), + 'lines_of_code': len(self.lines), + 'avg_line_length': round(sum(len(l) for l in self.lines) / len(self.lines), 2) if self.lines else 0 + } + + +def compare_files(before_file: str, after_file: str) -> None: + """Compare complexity metrics between two code versions.""" + + with open(before_file, 'r') as f: + before_code = f.read() + + with open(after_file, 'r') as f: + after_code = f.read() + + before_analyzer = ComplexityAnalyzer(before_code) + after_analyzer = ComplexityAnalyzer(after_code) + + before_metrics = before_analyzer.get_complexity_report() + after_metrics = after_analyzer.get_complexity_report() + + print("=" * 60) + print("CODE COMPLEXITY COMPARISON") + print("=" * 60) + + print("\nBEFORE:") + print(f" Cyclomatic Complexity: {before_metrics['cyclomatic_complexity']}") + print(f" Cognitive Complexity: {before_metrics['cognitive_complexity']}") + print(f" Maintainability Index: {before_metrics['maintainability_index']}") + print(f" Lines of Code: {before_metrics['lines_of_code']}") + print(f" Avg Line Length: {before_metrics['avg_line_length']}") + + print("\nAFTER:") + print(f" Cyclomatic Complexity: {after_metrics['cyclomatic_complexity']}") + print(f" Cognitive Complexity: {after_metrics['cognitive_complexity']}") + print(f" Maintainability Index: {after_metrics['maintainability_index']}") + print(f" Lines of Code: {after_metrics['lines_of_code']}") + print(f" Avg Line Length: {after_metrics['avg_line_length']}") + + print("\nCHANGES:") + cyclomatic_change = after_metrics['cyclomatic_complexity'] - before_metrics['cyclomatic_complexity'] + cognitive_change = after_metrics['cognitive_complexity'] - before_metrics['cognitive_complexity'] + mi_change = after_metrics['maintainability_index'] - before_metrics['maintainability_index'] + loc_change = after_metrics['lines_of_code'] - before_metrics['lines_of_code'] + + print(f" Cyclomatic Complexity: {cyclomatic_change:+d}") + print(f" Cognitive Complexity: {cognitive_change:+d}") + print(f" Maintainability Index: {mi_change:+.2f}") + print(f" Lines of Code: {loc_change:+d}") + + print("\nASSESSMENT:") + if mi_change > 0: + print(" ✅ Code is MORE maintainable") + elif mi_change < 0: + print(" ⚠️ Code is LESS maintainable") + else: + print(" ➡️ Maintainability unchanged") + + if cyclomatic_change < 0: + print(" ✅ Complexity DECREASED") + elif cyclomatic_change > 0: + print(" ⚠️ Complexity INCREASED") + else: + print(" ➡️ Complexity unchanged") + + print("=" * 60) + + +if __name__ == '__main__': + if len(sys.argv) != 3: + print("Usage: python compare-complexity.py ") + sys.exit(1) + + compare_files(sys.argv[1], sys.argv[2]) +``` + +## Template: review-checklist.md + +```markdown +# Code Review Checklist + +## Security Checklist +- [ ] No hardcoded credentials or secrets +- [ ] Input validation on all user inputs +- [ ] SQL injection prevention (parameterized queries) +- [ ] CSRF protection on state-changing operations +- [ ] XSS prevention with proper escaping +- [ ] Authentication checks on protected endpoints +- [ ] Authorization checks on resources +- [ ] Secure password hashing (bcrypt, argon2) +- [ ] No sensitive data in logs +- [ ] HTTPS enforced + +## Performance Checklist +- [ ] No N+1 queries +- [ ] Appropriate use of indexes +- [ ] Caching implemented where beneficial +- [ ] No blocking operations on main thread +- [ ] Async/await used correctly +- [ ] Large datasets paginated +- [ ] Database connections pooled +- [ ] Regular expressions optimized +- [ ] No unnecessary object creation +- [ ] Memory leaks prevented + +## Quality Checklist +- [ ] Functions < 50 lines +- [ ] Clear variable naming +- [ ] No duplicate code +- [ ] Proper error handling +- [ ] Comments explain WHY, not WHAT +- [ ] No console.logs in production +- [ ] Type checking (TypeScript/JSDoc) +- [ ] SOLID principles followed +- [ ] Design patterns applied correctly +- [ ] Self-documenting code + +## Testing Checklist +- [ ] Unit tests written +- [ ] Edge cases covered +- [ ] Error scenarios tested +- [ ] Integration tests present +- [ ] Coverage > 80% +- [ ] No flaky tests +- [ ] Mock external dependencies +- [ ] Clear test names +``` + +## Template: finding-template.md + +~~~~markdown +# Code Review Finding Template + +Use this template when documenting each issue found during code review. + +--- + +## Issue: [TITLE] + +### Severity +- [ ] Critical (blocks deployment) +- [ ] High (should fix before merge) +- [ ] Medium (should fix soon) +- [ ] Low (nice to have) + +### Category +- [ ] Security +- [ ] Performance +- [ ] Code Quality +- [ ] Maintainability +- [ ] Testing +- [ ] Design Pattern +- [ ] Documentation + +### Location +**File:** `src/components/UserCard.tsx` + +**Lines:** 45-52 + +**Function/Method:** `renderUserDetails()` + +### Issue Description + +**What:** Describe what the issue is. + +**Why it matters:** Explain the impact and why this needs to be fixed. + +**Current behavior:** Show the problematic code or behavior. + +**Expected behavior:** Describe what should happen instead. + +### Code Example + +#### Current (Problematic) + +```typescript +// Shows the N+1 query problem +const users = fetchUsers(); +users.forEach(user => { + const posts = fetchUserPosts(user.id); // Query per user! + renderUserPosts(posts); +}); +``` + +#### Suggested Fix + +```typescript +// Optimized with JOIN query +const usersWithPosts = fetchUsersWithPosts(); +usersWithPosts.forEach(({ user, posts }) => { + renderUserPosts(posts); +}); +``` + +### Impact Analysis + +| Aspect | Impact | Severity | +|--------|--------|----------| +| Performance | 100+ queries for 20 users | High | +| User Experience | Slow page load | High | +| Scalability | Breaks at scale | Critical | +| Maintainability | Hard to debug | Medium | + +### Related Issues + +- Similar issue in `AdminUserList.tsx` line 120 +- Related PR: #456 +- Related issue: #789 + +### Additional Resources + +- [N+1 Query Problem](https://en.wikipedia.org/wiki/N%2B1_problem) +- [Database Join Documentation](https://docs.example.com/joins) + +### Reviewer Notes + +- This is a common pattern in this codebase +- Consider adding this to the code style guide +- Might be worth creating a helper function + +### Author Response (for feedback) + +*To be filled by the code author:* + +- [ ] Fix implemented in commit: `abc123` +- [ ] Fix status: Complete / In Progress / Needs Discussion +- [ ] Questions or concerns: (describe) + +--- + +## Finding Statistics (for Reviewer) + +When reviewing multiple findings, track: + +- **Total Issues Found:** X +- **Critical:** X +- **High:** X +- **Medium:** X +- **Low:** X + +**Recommendation:** ✅ Approve / ⚠️ Request Changes / 🔄 Needs Discussion + +**Overall Code Quality:** 1-5 stars +~~~~ + +## Usage Example + +~~~~markdown +User: Review this React component code + +Claude: I'll conduct a comprehensive code review using my Code Review Skill. + +[Loads SKILL.md] +[Analyzes code against checklist] +[Runs Python metrics script] +[Applies templates] + +## Code Review Results + +### Summary +Quality Score: 3.5/5 +Key Findings: 7 items +Priority Areas: Performance optimization, error handling + +### Critical Issues: 1 + +**Issue**: N+1 Query Problem +**Location**: UserComponent.tsx, lines 45-52 +**Impact**: Renders 100+ database queries for list of 20 users +**Severity**: High +**Fix**: +```javascript +// Before: N+1 queries +const users = fetchUsers(); +users.forEach(user => fetchUserPosts(user.id)); // 20+ queries + +// After: Single query with JOIN +const users = fetchUsersWithPosts(); // 1 query +``` + +### Performance Findings +- Missing pagination on large lists +- Recommendation: Use React.memo() for items +- Database query: Could be optimized with index + +### Quality Findings +- Function in line 20 is 127 lines (max: 50) +- Missing error boundary +- Props should have TypeScript types +~~~~ + +#### Example 2: Brand Voice Skill + +**Directory Structure:** + +``` +.claude/skills/brand-voice/ +├── SKILL.md +├── brand-guidelines.md +├── tone-examples.md +└── templates/ + ├── email-template.txt + ├── social-post-template.txt + └── blog-post-template.md +``` + +**File:** `.claude/skills/brand-voice/SKILL.md` + +```yaml +--- +name: Brand Voice Consistency +description: Ensure all communication matches brand voice and tone guidelines +tags: + - brand + - writing + - consistency +when_to_use: When creating marketing copy, customer communications, or public-facing content +--- + +# Brand Voice Skill + +## Overview +This skill ensures all communications maintain consistent brand voice, tone, and messaging. + +## Brand Identity + +### Mission +Help teams automate their development workflows with AI + +### Values +- **Simplicity**: Make complex things simple +- **Reliability**: Rock-solid execution +- **Empowerment**: Enable human creativity + +### Tone of Voice +- **Friendly but professional** - approachable without being casual +- **Clear and concise** - avoid jargon, explain technical concepts simply +- **Confident** - we know what we're doing +- **Empathetic** - understand user needs and pain points + +## Writing Guidelines + +### Do's ✅ +- Use "you" when addressing readers +- Use active voice: "Claude generates reports" not "Reports are generated by Claude" +- Start with value proposition +- Use concrete examples +- Keep sentences under 20 words +- Use lists for clarity +- Include calls-to-action + +### Don'ts ❌ +- Don't use corporate jargon +- Don't patronize or oversimplify +- Don't use "we believe" or "we think" +- Don't use ALL CAPS except for emphasis +- Don't create walls of text +- Don't assume technical knowledge + +## Vocabulary + +### ✅ Preferred Terms +- Claude (not "the Claude AI") +- Code generation (not "auto-coding") +- Agent (not "bot") +- Streamline (not "revolutionize") +- Integrate (not "synergize") + +### ❌ Avoid Terms +- "Cutting-edge" (overused) +- "Game-changer" (vague) +- "Leverage" (corporate-speak) +- "Utilize" (use "use") +- "Paradigm shift" (unclear) +``` +## Examples + +### ✅ Good Example +"Claude automates your code review process. Instead of manually checking each PR, Claude reviews security, performance, and quality—saving your team hours every week." + +Why it works: Clear value, specific benefits, action-oriented + +### ❌ Bad Example +"Claude leverages cutting-edge AI to provide comprehensive software development solutions." + +Why it doesn't work: Vague, corporate jargon, no specific value + +## Template: Email + +``` +Subject: [Clear, benefit-driven subject] + +Hi [Name], + +[Opening: What's the value for them] + +[Body: How it works / What they'll get] + +[Specific example or benefit] + +[Call to action: Clear next step] + +Best regards, +[Name] +``` + +## Template: Social Media + +``` +[Hook: Grab attention in first line] +[2-3 lines: Value or interesting fact] +[Call to action: Link, question, or engagement] +[Emoji: 1-2 max for visual interest] +``` + +## File: tone-examples.md +``` +Exciting announcement: +"Save 8 hours per week on code reviews. Claude reviews your PRs automatically." + +Empathetic support: +"We know deployments can be stressful. Claude handles testing so you don't have to worry." + +Confident product feature: +"Claude doesn't just suggest code. It understands your architecture and maintains consistency." + +Educational blog post: +"Let's explore how agents improve code review workflows. Here's what we learned..." +``` + +#### Example 3: Documentation Generator Skill + +**File:** `.claude/skills/doc-generator/SKILL.md` + +~~~~yaml +--- +name: API Documentation Generator +description: Generate comprehensive, accurate API documentation from source code +version: "1.0.0" +tags: + - documentation + - api + - automation +when_to_use: When creating or updating API documentation +--- + +# API Documentation Generator Skill + +## Generates + +- OpenAPI/Swagger specifications +- API endpoint documentation +- SDK usage examples +- Integration guides +- Error code references +- Authentication guides + +## Documentation Structure + +### For Each Endpoint + +```markdown +## GET /api/v1/users/:id + +### Description +Brief explanation of what this endpoint does + +### Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| id | string | Yes | User ID | + +### Response + +**200 Success** +```json +{ + "id": "usr_123", + "name": "John Doe", + "email": "john@example.com", + "created_at": "2025-01-15T10:30:00Z" +} +``` + +**404 Not Found** +```json +{ + "error": "USER_NOT_FOUND", + "message": "User does not exist" +} +``` + +### Examples + +**cURL** +```bash +curl -X GET "https://api.example.com/api/v1/users/usr_123" \ + -H "Authorization: Bearer YOUR_TOKEN" +``` + +**JavaScript** +```javascript +const user = await fetch('/api/v1/users/usr_123', { + headers: { 'Authorization': 'Bearer token' } +}).then(r => r.json()); +``` + +**Python** +```python +response = requests.get( + 'https://api.example.com/api/v1/users/usr_123', + headers={'Authorization': 'Bearer token'} +) +user = response.json() +``` + +## Python Script: generate-docs.py + +```python +#!/usr/bin/env python3 +import ast +import json +from typing import Dict, List + +class APIDocExtractor(ast.NodeVisitor): + """Extract API documentation from Python source code.""" + + def __init__(self): + self.endpoints = [] + + def visit_FunctionDef(self, node): + """Extract function documentation.""" + if node.name.startswith('get_') or node.name.startswith('post_'): + doc = ast.get_docstring(node) + endpoint = { + 'name': node.name, + 'docstring': doc, + 'params': [arg.arg for arg in node.args.args], + 'returns': self._extract_return_type(node) + } + self.endpoints.append(endpoint) + self.generic_visit(node) + + def _extract_return_type(self, node): + """Extract return type from function annotation.""" + if node.returns: + return ast.unparse(node.returns) + return "Any" + +def generate_markdown_docs(endpoints: List[Dict]) -> str: + """Generate markdown documentation from endpoints.""" + docs = "# API Documentation\n\n" + + for endpoint in endpoints: + docs += f"## {endpoint['name']}\n\n" + docs += f"{endpoint['docstring']}\n\n" + docs += f"**Parameters**: {', '.join(endpoint['params'])}\n\n" + docs += f"**Returns**: {endpoint['returns']}\n\n" + docs += "---\n\n" + + return docs + +if __name__ == '__main__': + import sys + with open(sys.argv[1], 'r') as f: + tree = ast.parse(f.read()) + + extractor = APIDocExtractor() + extractor.visit(tree) + + markdown = generate_markdown_docs(extractor.endpoints) + print(markdown) +~~~~ +### Skill Discovery & Invocation + +```mermaid +graph TD + A["User Request"] --> B["Claude Analyzes"] + B -->|Scans| C["Available Skills"] + C -->|Metadata check| D["Skill Description Match?"] + D -->|Yes| E["Load SKILL.md"] + D -->|No| F["Try next skill"] + F -->|More skills?| D + F -->|No more| G["Use general knowledge"] + E --> H["Extract Instructions"] + H --> I["Execute Skill"] + I --> J["Return Results"] +``` + +### Skill vs Other Features + +```mermaid +graph TB + A["Extending Claude"] + B["Slash Commands"] + C["Subagents"] + D["Memory"] + E["MCP"] + F["Skills"] + + A --> B + A --> C + A --> D + A --> E + A --> F + + B -->|User-invoked| G["Quick shortcuts"] + C -->|Auto-delegated| H["Isolated contexts"] + D -->|Persistent| I["Cross-session context"] + E -->|Real-time| J["External data access"] + F -->|Auto-invoked| K["Autonomous execution"] +``` + +--- + +## Claude Code Plugins + +### Overview + +Claude Code Plugins are bundled collections of customizations (slash commands, subagents, MCP servers, and hooks) that install with a single command. They represent the highest-level extension mechanism—combining multiple features into cohesive, shareable packages. + +### Architecture + +```mermaid +graph TB + A["Plugin"] + B["Slash Commands"] + C["Subagents"] + D["MCP Servers"] + E["Hooks"] + F["Configuration"] + + A -->|bundles| B + A -->|bundles| C + A -->|bundles| D + A -->|bundles| E + A -->|bundles| F +``` + +### Plugin Loading Process + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Plugin as Plugin Marketplace + participant Install as Installation + participant SlashCmds as Slash Commands + participant Subagents + participant MCPServers as MCP Servers + participant Hooks + participant Tools as Configured Tools + + User->>Claude: /plugin install pr-review + Claude->>Plugin: Download plugin manifest + Plugin-->>Claude: Return plugin definition + Claude->>Install: Extract components + Install->>SlashCmds: Configure + Install->>Subagents: Configure + Install->>MCPServers: Configure + Install->>Hooks: Configure + SlashCmds-->>Tools: Ready to use + Subagents-->>Tools: Ready to use + MCPServers-->>Tools: Ready to use + Hooks-->>Tools: Ready to use + Tools-->>Claude: Plugin installed ✅ +``` + +### Plugin Types & Distribution + +| Type | Scope | Shared | Authority | Examples | +|------|-------|--------|-----------|----------| +| Official | Global | All users | Anthropic | PR Review, Security Guidance | +| Community | Public | All users | Community | DevOps, Data Science | +| Organization | Internal | Team members | Company | Internal standards, tools | +| Personal | Individual | Single user | Developer | Custom workflows | + +### Plugin Definition Structure + +```yaml +--- +name: plugin-name +version: "1.0.0" +description: "What this plugin does" +author: "Your Name" +license: MIT + +# Plugin metadata +tags: + - category + - use-case + +# Requirements +requires: + - claude-code: ">=1.0.0" + +# Components bundled +components: + - type: commands + path: commands/ + - type: agents + path: agents/ + - type: mcp + path: mcp/ + - type: hooks + path: hooks/ + +# Configuration +config: + auto_load: true + enabled_by_default: true +--- +``` + +### Plugin Structure + +``` +my-plugin/ +├── .claude-plugin/ +│ └── plugin.json +├── commands/ +│ ├── task-1.md +│ ├── task-2.md +│ └── workflows/ +├── agents/ +│ ├── specialist-1.md +│ ├── specialist-2.md +│ └── configs/ +├── skills/ +│ ├── skill-1.md +│ └── skill-2.md +├── hooks/ +│ └── hooks.json +├── .mcp.json +├── .lsp.json +├── settings.json +├── templates/ +│ └── issue-template.md +├── scripts/ +│ ├── helper-1.sh +│ └── helper-2.py +├── docs/ +│ ├── README.md +│ └── USAGE.md +└── tests/ + └── plugin.test.js +``` + +### Practical Examples + +#### Example 1: PR Review Plugin + +**File:** `.claude-plugin/plugin.json` + +```json +{ + "name": "pr-review", + "version": "1.0.0", + "description": "Complete PR review workflow with security, testing, and docs", + "author": { + "name": "Anthropic" + }, + "license": "MIT" +} +``` + +**File:** `commands/review-pr.md` + +```markdown +--- +name: Review PR +description: Start comprehensive PR review with security and testing checks +--- + +# PR Review + +This command initiates a complete pull request review including: + +1. Security analysis +2. Test coverage verification +3. Documentation updates +4. Code quality checks +5. Performance impact assessment +``` + +**File:** `agents/security-reviewer.md` + +```yaml +--- +name: security-reviewer +description: Security-focused code review +tools: read, grep, diff +--- + +# Security Reviewer + +Specializes in finding security vulnerabilities: +- Authentication/authorization issues +- Data exposure +- Injection attacks +- Secure configuration +``` + +**Installation:** + +```bash +/plugin install pr-review + +# Result: +# ✅ 3 slash commands installed +# ✅ 3 subagents configured +# ✅ 2 MCP servers connected +# ✅ 4 hooks registered +# ✅ Ready to use! +``` + +#### Example 2: DevOps Plugin + +**Components:** + +``` +devops-automation/ +├── commands/ +│ ├── deploy.md +│ ├── rollback.md +│ ├── status.md +│ └── incident.md +├── agents/ +│ ├── deployment-specialist.md +│ ├── incident-commander.md +│ └── alert-analyzer.md +├── mcp/ +│ ├── github-config.json +│ ├── kubernetes-config.json +│ └── prometheus-config.json +├── hooks/ +│ ├── pre-deploy.js +│ ├── post-deploy.js +│ └── on-error.js +└── scripts/ + ├── deploy.sh + ├── rollback.sh + └── health-check.sh +``` + +#### Example 3: Documentation Plugin + +**Bundled Components:** + +``` +documentation/ +├── commands/ +│ ├── generate-api-docs.md +│ ├── generate-readme.md +│ ├── sync-docs.md +│ └── validate-docs.md +├── agents/ +│ ├── api-documenter.md +│ ├── code-commentator.md +│ └── example-generator.md +├── mcp/ +│ ├── github-docs-config.json +│ └── slack-announce-config.json +└── templates/ + ├── api-endpoint.md + ├── function-docs.md + └── adr-template.md +``` + +### Plugin Marketplace + +```mermaid +graph TB + A["Plugin Marketplace"] + B["Official
Anthropic"] + C["Community
Marketplace"] + D["Enterprise
Registry"] + + A --> B + A --> C + A --> D + + B -->|Categories| B1["Development"] + B -->|Categories| B2["DevOps"] + B -->|Categories| B3["Documentation"] + + C -->|Search| C1["DevOps Automation"] + C -->|Search| C2["Mobile Dev"] + C -->|Search| C3["Data Science"] + + D -->|Internal| D1["Company Standards"] + D -->|Internal| D2["Legacy Systems"] + D -->|Internal| D3["Compliance"] +``` + +### Plugin Installation & Lifecycle + +```mermaid +graph LR + A["Discover"] -->|Browse| B["Marketplace"] + B -->|Select| C["Plugin Page"] + C -->|View| D["Components"] + D -->|Install| E["/plugin install"] + E -->|Extract| F["Configure"] + F -->|Activate| G["Use"] + G -->|Check| H["Update"] + H -->|Available| G + G -->|Done| I["Disable"] + I -->|Later| J["Enable"] + J -->|Back| G +``` + +### Plugin Features Comparison + +| Feature | Slash Command | Skill | Subagent | Plugin | +|---------|---------------|-------|----------|--------| +| **Installation** | Manual copy | Manual copy | Manual config | One command | +| **Setup Time** | 5 minutes | 10 minutes | 15 minutes | 2 minutes | +| **Bundling** | Single file | Single file | Single file | Multiple | +| **Versioning** | Manual | Manual | Manual | Automatic | +| **Team Sharing** | Copy file | Copy file | Copy file | Install ID | +| **Updates** | Manual | Manual | Manual | Auto-available | +| **Dependencies** | None | None | None | May include | +| **Marketplace** | No | No | No | Yes | +| **Distribution** | Repository | Repository | Repository | Marketplace | + +### Plugin Use Cases + +| Use Case | Recommendation | Why | +|----------|-----------------|-----| +| **Team Onboarding** | ✅ Use Plugin | Instant setup, all configurations | +| **Framework Setup** | ✅ Use Plugin | Bundles framework-specific commands | +| **Enterprise Standards** | ✅ Use Plugin | Central distribution, version control | +| **Quick Task Automation** | ❌ Use Command | Overkill complexity | +| **Single Domain Expertise** | ❌ Use Skill | Too heavy, use skill instead | +| **Specialized Analysis** | ❌ Use Subagent | Create manually or use skill | +| **Live Data Access** | ❌ Use MCP | Standalone, don't bundle | + +### When to Create a Plugin + +```mermaid +graph TD + A["Should I create a plugin?"] + A -->|Need multiple components| B{"Multiple commands
or subagents
or MCPs?"} + B -->|Yes| C["✅ Create Plugin"] + B -->|No| D["Use Individual Feature"] + A -->|Team workflow| E{"Share with
team?"} + E -->|Yes| C + E -->|No| F["Keep as Local Setup"] + A -->|Complex setup| G{"Needs auto
configuration?"} + G -->|Yes| C + G -->|No| D +``` + +### Publishing a Plugin + +**Steps to publish:** + +1. Create plugin structure with all components +2. Write `.claude-plugin/plugin.json` manifest +3. Create `README.md` with documentation +4. Test locally with `/plugin install ./my-plugin` +5. Submit to plugin marketplace +6. Get reviewed and approved +7. Published on marketplace +8. Users can install with one command + +**Example submission:** + +~~~~markdown +# PR Review Plugin + +## Description +Complete PR review workflow with security, testing, and documentation checks. + +## What's Included +- 3 slash commands for different review types +- 3 specialized subagents +- GitHub and CodeQL MCP integration +- Automated security scanning hooks + +## Installation +```bash +/plugin install pr-review +``` + +## Features +✅ Security analysis +✅ Test coverage checking +✅ Documentation verification +✅ Code quality assessment +✅ Performance impact analysis + +## Usage +```bash +/review-pr +/check-security +/check-tests +``` + +## Requirements +- Claude Code 1.0+ +- GitHub access +- CodeQL (optional) +~~~~ + +### Plugin vs Manual Configuration + +**Manual Setup (2+ hours):** +- Install slash commands one by one +- Create subagents individually +- Configure MCPs separately +- Set up hooks manually +- Document everything +- Share with team (hope they configure correctly) + +**With Plugin (2 minutes):** +```bash +/plugin install pr-review +# ✅ Everything installed and configured +# ✅ Ready to use immediately +# ✅ Team can reproduce exact setup +``` + +--- + +## Comparison & Integration + +### Feature Comparison Matrix + +| Feature | Invocation | Persistence | Scope | Use Case | +|---------|-----------|------------|-------|----------| +| **Slash Commands** | Manual (`/cmd`) | Session only | Single command | Quick shortcuts | +| **Subagents** | Auto-delegated | Isolated context | Specialized task | Task distribution | +| **Memory** | Auto-loaded | Cross-session | User/team context | Long-term learning | +| **MCP Protocol** | Auto-queried | Real-time external | Live data access | Dynamic information | +| **Skills** | Auto-invoked | Filesystem-based | Reusable expertise | Automated workflows | + +### Interaction Timeline + +```mermaid +graph LR + A["Session Start"] -->|Load| B["Memory (CLAUDE.md)"] + B -->|Discover| C["Available Skills"] + C -->|Register| D["Slash Commands"] + D -->|Connect| E["MCP Servers"] + E -->|Ready| F["User Interaction"] + + F -->|Type /cmd| G["Slash Command"] + F -->|Request| H["Skill Auto-Invoke"] + F -->|Query| I["MCP Data"] + F -->|Complex task| J["Delegate to Subagent"] + + G -->|Uses| B + H -->|Uses| B + I -->|Uses| B + J -->|Uses| B +``` + +### Practical Integration Example: Customer Support Automation + +#### Architecture + +```mermaid +graph TB + User["Customer Email"] -->|Receives| Router["Support Router"] + + Router -->|Analyze| Memory["Memory
Customer history"] + Router -->|Lookup| MCP1["MCP: Customer DB
Previous tickets"] + Router -->|Check| MCP2["MCP: Slack
Team status"] + + Router -->|Route Complex| Sub1["Subagent: Tech Support
Context: Technical issues"] + Router -->|Route Simple| Sub2["Subagent: Billing
Context: Payment issues"] + Router -->|Route Urgent| Sub3["Subagent: Escalation
Context: Priority handling"] + + Sub1 -->|Format| Skill1["Skill: Response Generator
Brand voice maintained"] + Sub2 -->|Format| Skill2["Skill: Response Generator"] + Sub3 -->|Format| Skill3["Skill: Response Generator"] + + Skill1 -->|Generate| Output["Formatted Response"] + Skill2 -->|Generate| Output + Skill3 -->|Generate| Output + + Output -->|Post| MCP3["MCP: Slack
Notify team"] + Output -->|Send| Reply["Customer Reply"] +``` + +#### Request Flow + +```markdown +## Customer Support Request Flow + +### 1. Incoming Email +"I'm getting error 500 when trying to upload files. This is blocking my workflow!" + +### 2. Memory Lookup +- Loads CLAUDE.md with support standards +- Checks customer history: VIP customer, 3rd incident this month + +### 3. MCP Queries +- GitHub MCP: List open issues (finds related bug report) +- Database MCP: Check system status (no outages reported) +- Slack MCP: Check if engineering is aware + +### 4. Skill Detection & Loading +- Request matches "Technical Support" skill +- Loads support response template from Skill + +### 5. Subagent Delegation +- Routes to Tech Support Subagent +- Provides context: customer history, error details, known issues +- Subagent has full access to: read, bash, grep tools + +### 6. Subagent Processing +Tech Support Subagent: +- Searches codebase for 500 error in file upload +- Finds recent change in commit 8f4a2c +- Creates workaround documentation + +### 7. Skill Execution +Response Generator Skill: +- Uses Brand Voice guidelines +- Formats response with empathy +- Includes workaround steps +- Links to related documentation + +### 8. MCP Output +- Posts update to #support Slack channel +- Tags engineering team +- Updates ticket in Jira MCP + +### 9. Response +Customer receives: +- Empathetic acknowledgment +- Explanation of cause +- Immediate workaround +- Timeline for permanent fix +- Link to related issues +``` + +### Complete Feature Orchestration + +```mermaid +sequenceDiagram + participant User + participant Claude as Claude Code + participant Memory as Memory
CLAUDE.md + participant MCP as MCP Servers + participant Skills as Skills + participant SubAgent as Subagents + + User->>Claude: Request: "Build auth system" + Claude->>Memory: Load project standards + Memory-->>Claude: Auth standards, team practices + Claude->>MCP: Query GitHub for similar implementations + MCP-->>Claude: Code examples, best practices + Claude->>Skills: Detect matching Skills + Skills-->>Claude: Security Review Skill + Testing Skill + Claude->>SubAgent: Delegate implementation + SubAgent->>SubAgent: Build feature + Claude->>Skills: Apply Security Review Skill + Skills-->>Claude: Security checklist results + Claude->>SubAgent: Delegate testing + SubAgent-->>Claude: Test results + Claude->>User: Complete system delivered +``` + +### When to Use Each Feature + +```mermaid +graph TD + A["New Task"] --> B{Type of Task?} + + B -->|Repeated workflow| C["Slash Command"] + B -->|Need real-time data| D["MCP Protocol"] + B -->|Remember for next time| E["Memory"] + B -->|Specialized subtask| F["Subagent"] + B -->|Domain-specific work| G["Skill"] + + C --> C1["✅ Team shortcut"] + D --> D1["✅ Live API access"] + E --> E1["✅ Persistent context"] + F --> F1["✅ Parallel execution"] + G --> G1["✅ Auto-invoked expertise"] +``` + +### Selection Decision Tree + +```mermaid +graph TD + Start["Need to extend Claude?"] + + Start -->|Quick repeated task| A{"Manual or Auto?"} + A -->|Manual| B["Slash Command"] + A -->|Auto| C["Skill"] + + Start -->|Need external data| D{"Real-time?"} + D -->|Yes| E["MCP Protocol"] + D -->|No/Cross-session| F["Memory"] + + Start -->|Complex project| G{"Multiple roles?"} + G -->|Yes| H["Subagents"] + G -->|No| I["Skills + Memory"] + + Start -->|Long-term context| J["Memory"] + Start -->|Team workflow| K["Slash Command +
Memory"] + Start -->|Full automation| L["Skills +
Subagents +
MCP"] +``` + +--- + +## Summary Table + +| Aspect | Slash Commands | Subagents | Memory | MCP | Skills | Plugins | +|--------|---|---|---|---|---|---| +| **Setup Difficulty** | Easy | Medium | Easy | Medium | Medium | Easy | +| **Learning Curve** | Low | Medium | Low | Medium | Medium | Low | +| **Team Benefit** | High | High | Medium | High | High | Very High | +| **Automation Level** | Low | High | Medium | High | High | Very High | +| **Context Management** | Single-session | Isolated | Persistent | Real-time | Persistent | All features | +| **Maintenance Burden** | Low | Medium | Low | Medium | Medium | Low | +| **Scalability** | Good | Excellent | Good | Excellent | Excellent | Excellent | +| **Shareability** | Fair | Fair | Good | Good | Good | Excellent | +| **Versioning** | Manual | Manual | Manual | Manual | Manual | Automatic | +| **Installation** | Manual copy | Manual config | N/A | Manual config | Manual copy | One command | + +--- + +## Quick Start Guide + +### Week 1: Start Simple +- Create 2-3 slash commands for common tasks +- Enable Memory in Settings +- Document team standards in CLAUDE.md + +### Week 2: Add Real-time Access +- Set up 1 MCP (GitHub or Database) +- Use `/mcp` to configure +- Query live data in your workflows + +### Week 3: Distribute Work +- Create first Subagent for specific role +- Use `/agents` command +- Test delegation with simple task + +### Week 4: Automate Everything +- Create first Skill for repeated automation +- Use Skill marketplace or build custom +- Combine all features for full workflow + +### Ongoing +- Review and update Memory monthly +- Add new Skills as patterns emerge +- Optimize MCP queries +- Refine Subagent prompts + +--- + +## Hooks + +### Overview + +Hooks are event-driven shell commands that execute automatically in response to Claude Code events. They enable automation, validation, and custom workflows without manual intervention. + +### Hook Events + +Claude Code supports **25 hook events** across four hook types (command, http, prompt, agent): + +| Hook Event | Trigger | Use Cases | +|------------|---------|-----------| +| **SessionStart** | Session begins/resumes/clear/compact | Environment setup, initialization | +| **InstructionsLoaded** | CLAUDE.md or rules file loaded | Validation, transformation, augmentation | +| **UserPromptSubmit** | User submits prompt | Input validation, prompt filtering | +| **PreToolUse** | Before any tool runs | Validation, approval gates, logging | +| **PermissionRequest** | Permission dialog shown | Auto-approve/deny flows | +| **PostToolUse** | After tool succeeds | Auto-formatting, notifications, cleanup | +| **PostToolUseFailure** | Tool execution fails | Error handling, logging | +| **Notification** | Notification sent | Alerting, external integrations | +| **SubagentStart** | Subagent spawned | Context injection, initialization | +| **SubagentStop** | Subagent finishes | Result validation, logging | +| **Stop** | Claude finishes responding | Summary generation, cleanup tasks | +| **StopFailure** | API error ends turn | Error recovery, logging | +| **TeammateIdle** | Agent team teammate idle | Work distribution, coordination | +| **TaskCompleted** | Task marked complete | Post-task processing | +| **TaskCreated** | Task created via TaskCreate | Task tracking, logging | +| **ConfigChange** | Config file changes | Validation, propagation | +| **CwdChanged** | Working directory changes | Directory-specific setup | +| **FileChanged** | Watched file changes | File monitoring, rebuild triggers | +| **PreCompact** | Before context compaction | State preservation | +| **PostCompact** | After compaction completes | Post-compact actions | +| **WorktreeCreate** | Worktree being created | Environment setup, dependency install | +| **WorktreeRemove** | Worktree being removed | Cleanup, resource deallocation | +| **Elicitation** | MCP server requests user input | Input validation | +| **ElicitationResult** | User responds to elicitation | Response processing | +| **SessionEnd** | Session terminates | Cleanup, final logging | + +### Common Hooks + +Hooks are configured in `~/.claude/settings.json` (user-level) or `.claude/settings.json` (project-level): + +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Write", + "hooks": [ + { + "type": "command", + "command": "prettier --write $CLAUDE_FILE_PATH" + } + ] + } + ], + "PreToolUse": [ + { + "matcher": "Edit", + "hooks": [ + { + "type": "command", + "command": "eslint $CLAUDE_FILE_PATH" + } + ] + } + ] + } +} +``` + +### Hook Environment Variables + +- `$CLAUDE_FILE_PATH` - Path to file being edited/written +- `$CLAUDE_TOOL_NAME` - Name of tool being used +- `$CLAUDE_SESSION_ID` - Current session identifier +- `$CLAUDE_PROJECT_DIR` - Project directory path + +### Best Practices + +✅ **Do:** +- Keep hooks fast (< 1 second) +- Use hooks for validation and automation +- Handle errors gracefully +- Use absolute paths + +❌ **Don't:** +- Make hooks interactive +- Use hooks for long-running tasks +- Hardcode credentials + +**See**: [06-hooks/](06-hooks/) for detailed examples + +--- + +## Checkpoints and Rewind + +### Overview + +Checkpoints allow you to save conversation state and rewind to previous points, enabling safe experimentation and exploration of multiple approaches. + +### Key Concepts + +| Concept | Description | +|---------|-------------| +| **Checkpoint** | Snapshot of conversation state including messages, files, and context | +| **Rewind** | Return to a previous checkpoint, discarding subsequent changes | +| **Branch Point** | Checkpoint from which multiple approaches are explored | + +### Accessing Checkpoints + +Checkpoints are created automatically with every user prompt. To rewind: + +```bash +# Press Esc twice to open the checkpoint browser +Esc + Esc + +# Or use the /rewind command +/rewind +``` + +When you select a checkpoint, you choose from five options: +1. **Restore code and conversation** -- Revert both to that point +2. **Restore conversation** -- Rewind messages, keep current code +3. **Restore code** -- Revert files, keep conversation +4. **Summarize from here** -- Compress conversation into a summary +5. **Never mind** -- Cancel + +### Use Cases + +| Scenario | Workflow | +|----------|----------| +| **Exploring Approaches** | Save → Try A → Save → Rewind → Try B → Compare | +| **Safe Refactoring** | Save → Refactor → Test → If fail: Rewind | +| **A/B Testing** | Save → Design A → Save → Rewind → Design B → Compare | +| **Mistake Recovery** | Notice issue → Rewind to last good state | + +### Configuration + +```json +{ + "autoCheckpoint": true +} +``` + +**See**: [08-checkpoints/](08-checkpoints/) for detailed examples + +--- + +## Advanced Features + +### Planning Mode + +Create detailed implementation plans before coding. + +**Activation:** +```bash +/plan Implement user authentication system +``` + +**Benefits:** +- Clear roadmap with time estimates +- Risk assessment +- Systematic task breakdown +- Opportunity for review and modification + +### Extended Thinking + +Deep reasoning for complex problems. + +**Activation:** +- Toggle with `Alt+T` (or `Option+T` on macOS) during a session +- Set `MAX_THINKING_TOKENS` environment variable for programmatic control + +```bash +# Enable extended thinking via environment variable +export MAX_THINKING_TOKENS=50000 +claude -p "Should we use microservices or monolith?" +``` + +**Benefits:** +- Thorough analysis of trade-offs +- Better architectural decisions +- Consideration of edge cases +- Systematic evaluation + +### Background Tasks + +Run long operations without blocking the conversation. + +**Usage:** +```bash +User: Run tests in background + +Claude: Started task bg-1234 + +/task list # Show all tasks +/task status bg-1234 # Check progress +/task show bg-1234 # View output +/task cancel bg-1234 # Cancel task +``` + +### Permission Modes + +Control what Claude can do. + +| Mode | Description | Use Case | +|------|-------------|----------| +| **default** | Standard permissions with prompts for sensitive actions | General development | +| **acceptEdits** | Automatically accept file edits without confirmation | Trusted editing workflows | +| **plan** | Analysis and planning only, no file modifications | Code review, architecture planning | +| **auto** | Automatically approve safe actions, prompt only for risky ones | Balanced autonomy with safety | +| **dontAsk** | Execute all actions without confirmation prompts | Experienced users, automation | +| **bypassPermissions** | Full unrestricted access, no safety checks | CI/CD pipelines, trusted scripts | + +**Usage:** +```bash +claude --permission-mode plan # Read-only analysis +claude --permission-mode acceptEdits # Auto-accept edits +claude --permission-mode auto # Auto-approve safe actions +claude --permission-mode dontAsk # No confirmation prompts +``` + +### Headless Mode (Print Mode) + +Run Claude Code without interactive input for automation and CI/CD using the `-p` (print) flag. + +**Usage:** +```bash +# Run specific task +claude -p "Run all tests" + +# Pipe input for analysis +cat error.log | claude -p "explain this error" + +# CI/CD integration (GitHub Actions) +- name: AI Code Review + run: claude -p "Review PR changes and report issues" + +# JSON output for scripting +claude -p --output-format json "list all functions in src/" +``` + +### Scheduled Tasks + +Run tasks on a repeating schedule using the `/loop` command. + +**Usage:** +```bash +/loop every 30m "Run tests and report failures" +/loop every 2h "Check for dependency updates" +/loop every 1d "Generate daily summary of code changes" +``` + +Scheduled tasks run in the background and report results when complete. They are useful for continuous monitoring, periodic checks, and automated maintenance workflows. + +### Chrome Integration + +Claude Code can integrate with the Chrome browser for web automation tasks. This enables capabilities like navigating web pages, filling forms, taking screenshots, and extracting data from websites directly within your development workflow. + +### Session Management + +Manage multiple work sessions. + +**Commands:** +```bash +/resume # Resume a previous conversation +/rename "Feature" # Name the current session +/fork # Fork into a new session +claude -c # Continue most recent conversation +claude -r "Feature" # Resume session by name/ID +``` + +### Interactive Features + +**Keyboard Shortcuts:** +- `Ctrl + R` - Search command history +- `Tab` - Autocomplete +- `↑ / ↓` - Command history +- `Ctrl + L` - Clear screen + +**Multi-line Input:** +```bash +User: \ +> Long complex prompt +> spanning multiple lines +> \end +``` + +### Configuration + +Complete configuration example: + +```json +{ + "planning": { + "autoEnter": true, + "requireApproval": true + }, + "extendedThinking": { + "enabled": true, + "showThinkingProcess": true + }, + "backgroundTasks": { + "enabled": true, + "maxConcurrentTasks": 5 + }, + "permissions": { + "mode": "default" + } +} +``` + +**See**: [09-advanced-features/](09-advanced-features/) for comprehensive guide + +--- + +## Resources + +- [Claude Code Documentation](https://code.claude.com/docs/en/overview) +- [Anthropic Documentation](https://docs.anthropic.com) +- [MCP GitHub Servers](https://github.com/modelcontextprotocol/servers) +- [Anthropic Cookbook](https://github.com/anthropics/anthropic-cookbook) + +--- + +*Last updated: April 2026* +*For Claude Haiku 4.5, Sonnet 4.6, and Opus 4.6* +*Now includes: Hooks, Checkpoints, Planning Mode, Extended Thinking, Background Tasks, Permission Modes (6 modes), Headless Mode, Session Management, Auto Memory, Agent Teams, Scheduled Tasks, Chrome Integration, Channels, Voice Dictation, and Bundled Skills* + +--- +**Last Updated**: April 9, 2026 +**Claude Code Version**: 2.1.97 diff --git a/uk/docs/ROADMAP-20260401.md b/uk/docs/ROADMAP-20260401.md new file mode 100644 index 0000000..e333c56 --- /dev/null +++ b/uk/docs/ROADMAP-20260401.md @@ -0,0 +1,153 @@ +# Roadmap: claude-howto 2026–2027 + +> April 2026 – March 2027 · Dual-Layer Knowledge Base | Full plan: `TASKS-20260401.md` + +--- + +## Vision + +Transform claude-howto from a static tutorial repo into a **living, dual-audience knowledge system**: + +- **For humans** — interactive, scenario-based learning with progressive difficulty, decision trees, and named patterns that experts bookmark +- **For AI agents** — structured metadata index that agents query before performing Claude Code tasks, making this repo infrastructure, not just content + +No competitor targets AI agents as a primary audience. This is the moat. + +--- + +## The 7 Pillars + +| # | Pillar | What it delivers | +|---|--------|-----------------| +| P1 | Fun Layer | Scenario intros + "Try It Now" blocks in every module | +| P2 | AI Agent Index | Generated `agent-manifest.json` + `AGENT-INDEX.md` + lookup skill | +| P3a | Expert Reference (in-module) | Decision trees + named patterns per module | +| P3b | Expert Reference (cross-module) | `RECIPES.md` — compound multi-feature workflows | +| P4 | Newcomer Onboarding | `quickstart.sh` + `QUICKSTART.md` + difficulty badges | +| P5 | Community Showcase | `COMMUNITY-PROJECTS.md` — curated user projects | +| P6 | Content Quality | Expand weakest modules; project `CLAUDE.md` | +| P7 | Living Curriculum | `WHATS-NEW.md` + version badges + weekly staleness CI action | + +--- + +## Timeline at a Glance + +``` +Apr 2026 May–Jun 2026 Jul–Aug 2026 Sep 2026 Oct–Nov 2026 Dec 2026–Mar 2027 + | | | | | | + [M1] [M2] [M3] [M4] [M5] [M6] +Infrastructure 6/10 modules 10/10 Agent layer Version audit Self-sustaining ++ hooks/checks complete complete + recipes complete system +``` + +--- + +## Milestones + +### M1 — Infrastructure Live · End of April 2026 + +**What ships:** +- `scripts/quickstart.sh` — one-command setup for new users (idempotent) +- `QUICKSTART.md` — First 15 Minutes visual guide +- Difficulty badges + "What you'll build" previews on all 10 modules +- `WHATS-NEW.md` + version badges on all modules +- `.github/workflows/staleness-check.yml` — weekly Monday issue if module unverified 30+ days +- Root `CLAUDE.md` — project's own configuration as a best-practice example +- `scripts/build-agent-index.py` — generator that reads all 10 modules → outputs `agent-manifest.json` + `AGENT-INDEX.md` +- **06-hooks** — full deep pass: 5 complete hook scripts, decision tree, Try It Now, patterns +- **08-checkpoints** — full deep pass: 311 → 800+ lines, 3 workflow templates, decision tree, patterns + +**Why start here:** Infrastructure benefits every future phase. Hooks and checkpoints are the weakest modules and most likely to lose new visitors. + +--- + +### M2 — 6/10 Modules Complete · End of June 2026 + +**What ships (one deep pass per module):** +- **01-slash-commands** — scenario intro, decision tree, Try It Now, named patterns +- **02-memory** — scenario intro, decision tree, Try It Now, named patterns +- **03-skills** — scenario intro, decision tree, Try It Now, named patterns +- **10-cli** — scenario intro, decision tree, Try It Now, named patterns +- CI step: validate `agent-manifest.json` schema on every push + +Each module pass = run the generator to confirm valid manifest output. + +--- + +### M3 — All 10 Modules Complete · End of August 2026 + +**What ships:** +- **04-subagents** — full deep pass (incl. "The Multi-Agent Review Pattern") +- **05-mcp** — full deep pass +- **07-plugins** — full deep pass +- **09-advanced-features** — full deep pass + +Every module now has: scenario intro, 2+ Try It Now blocks, Mermaid decision tree, 2+ named patterns. + +--- + +### M4 — Agent Layer Live · End of September 2026 + +**What ships:** +- Final `agent-manifest.json` covering 100% of modules (generated from completed content) +- `AGENT-INDEX.md` linked from `README.md` +- `skills/claude-howto-lookup/SKILL.md` — lightweight agent skill that queries the manifest +- `RECIPES.md` — 5+ compound workflows (schema: name, modules-used, problem, solution, expected outcome) +- `COMMUNITY-PROJECTS.md` — static curated list with PR-based submission format + +**Why September:** The agent index is only meaningful once all 10 modules are content-complete. + +--- + +### M5 — Version Audit Complete · End of November 2026 + +**What ships:** +- Full version audit: all 10 modules verified against current CC version +- Updated `cc_version_verified` frontmatter + version badges everywhere +- `RECIPES.md` expanded to 8+ recipes based on observed community patterns +- Pinned GitHub Discussion: "Share your Claude Code workflows" — signal collection for agent usage + +--- + +### M6 — Self-Sustaining System · End of March 2027 + +**What ships / runs continuously:** +- `/docs-sync-claude-code` skill runs after every CC release → `WHATS-NEW.md` updated +- Agent manifest CI regression: 100% module coverage enforced +- `RECIPES.md` at 10+ recipes +- `COMMUNITY-PROJECTS.md` growing organically +- Agent usage signal evaluated → if validated, promote the lookup skill (marketing, asm registry) + +--- + +## Deliverables Summary + +| Deliverable | Type | Phase | +|-------------|------|-------| +| `scripts/quickstart.sh` | Script | P1 | +| `QUICKSTART.md` | Doc | P1 | +| Root `CLAUDE.md` | Config | P1 | +| `WHATS-NEW.md` | Doc | P1 | +| `.github/workflows/staleness-check.yml` | CI | P1 | +| `scripts/build-agent-index.py` | Script | P1 | +| 10 module deep passes (scenario + Try It Now + decision tree + patterns) | Content | P1–P3 | +| `agent-manifest.json` (generated) | Data | P4 | +| `AGENT-INDEX.md` (generated) | Doc | P4 | +| `skills/claude-howto-lookup/SKILL.md` | Skill | P4 | +| `RECIPES.md` (5 → 8 → 10+ recipes) | Doc | P4–P6 | +| `COMMUNITY-PROJECTS.md` | Doc | P4 | + +--- + +## What Is NOT in Scope + +Deferred to `TODOS.md` — do not let these creep in: + +- Skill marketplace or installable registry +- Custom website or dashboard +- Completion tracking (cc-progress) +- Community tutorial CI validation +- Auto-generated CONTRIBUTORS.md +- Multi-language translations +- Quiz/assessment infrastructure +- Community voting on projects diff --git a/uk/docs/TASKS-20260401.md b/uk/docs/TASKS-20260401.md new file mode 100644 index 0000000..fdad321 --- /dev/null +++ b/uk/docs/TASKS-20260401.md @@ -0,0 +1,291 @@ +# Tasks: Dual-Layer Knowledge Base — claude-howto + +> Created: 2026-04-01 + +--- + +## Milestones + +| # | Milestone | Target | Description | +|---|-----------|--------|-------------| +| M1 | Infrastructure Live | End of April 2026 | quickstart.sh, CLAUDE.md, staleness action, agent index generator live; 2 weakest modules upgraded | +| M2 | 6/10 Modules Complete | End of June 2026 | Slash commands, memory, skills, CLI modules fully upgraded; generator producing valid manifest | +| M3 | All 10 Modules Complete | End of August 2026 | Every module has scenario intro, Try It Now blocks, decision tree, named patterns | +| M4 | Agent Layer Live | End of September 2026 | agent-manifest.json + AGENT-INDEX.md generated; lookup skill in repo; RECIPES.md + COMMUNITY-PROJECTS.md live | +| M5 | Version Audit Complete | End of November 2026 | All 10 modules verified against current CC version; RECIPES.md at 8+ recipes | +| M6 | Self-Sustaining System | End of March 2027 | Agent manifest covers 100% modules (CI-validated); RECIPES.md at 10+; community page growing organically | + +--- + +## Phase 1 — Infrastructure & Weak Modules (April 2026) + +**Target milestone: M1** + +### Pillar 4: Newcomer Onboarding + +- [ ] **T-001** — Write `scripts/quickstart.sh` + - Detects `~/.claude/` directory (creates with user confirmation if missing) + - Copies first slash command + CLAUDE.md + skill to user's setup + - Appends agent-discovery line to CLAUDE.md linking to AGENT-INDEX.md + - Idempotent: skips existing files with a warning, never overwrites + - Prints next steps on completion + +- [ ] **T-002** — Create `QUICKSTART.md` (First 15 Minutes visual guide) + - Annotated terminal steps as code blocks (avoid PNG screenshots where possible; prefer ASCII or Mermaid) + - Document which commands produce each visual so they can be re-captured + +- [ ] **T-003** — Add difficulty badges to all 10 module READMEs + - Format: `> 🟢 **Beginner** | ⏱ 30 minutes` at top of each module README + - Add "What you'll build" bullet preview below the badge + +### Pillar 7: Living Curriculum + +- [ ] **T-004** — Create `WHATS-NEW.md` + - Format: `## CC vX.X — DATE` with bullet items per feature change + - Add at least one entry for current CC version + +- [ ] **T-005** — Add version badges to all 10 module READMEs + - Format: `> ✅ Verified against Claude Code **vX.X.X** · Last verified: YYYY-MM-DD` + - Add `cc_version_verified` to each module's frontmatter + +- [ ] **T-006** — Create `.github/workflows/staleness-check.yml` + - Schedule: weekly Monday 09:00 UTC + - Reads each module's `last_verified` date from frontmatter (use `yq` or 10-line Python script) + - Creates a GitHub Issue for any module not verified in 30+ days + - Skips if open issue with same title already exists + +### Pillar 6: Content Quality (CLAUDE.md) + +- [ ] **T-007** — Create root `CLAUDE.md` for the project + - Demonstrates best practices as the project's own configuration + - Documents contributing conventions, module structure, and maintenance workflow + +### Pillar 2: AI Agent Index (Generator) + +- [ ] **T-008** — Write `scripts/build-agent-index.py` + - Reads all 10 module README files + - Extracts: headings (→ topics), code blocks (→ examples with language tags), tables (→ reference data) + - Outputs `agent-manifest.json` with schema defined in CEO plan + - Outputs `AGENT-INDEX.md` (human-readable summary) + - Validates references point to actual files + +### Module 08-checkpoints: Full Deep Pass (311 → 800+ lines) + +- [ ] **T-009** — Rewrite module intro with real-world scenario + - Example: "Your refactor just broke 3 things. Here's how checkpoints save you..." + +- [ ] **T-010** — Add checkpoint strategy decision tree (Mermaid flowchart) + - "I want to do X" → follow arrows → land on checkpoint pattern + +- [ ] **T-011** — Add 3 workflow templates + - Safe refactoring workflow + - A/B testing with checkpoints + - Disaster recovery workflow + +- [ ] **T-012** — Add integration with planning mode section + +- [ ] **T-013** — Add Mermaid diagram for checkpoint lifecycle + +- [ ] **T-014** — Add 2+ "Try It Now" blocks with verifiable commands + - Each: context sentence, command to run, expected output description + +- [ ] **T-015** — Add "Patterns & Recipes" section with 2+ named patterns + - Each pattern: problem, solution code, when to use, when NOT to use + +### Module 06-hooks: Full Deep Pass + +- [ ] **T-016** — Rewrite module intro with real-world scenario + - Example: "Your CI caught a lint error after 20 minutes. Hooks catch it in 2 seconds..." + +- [ ] **T-017** — Add hooks decision tree (Mermaid flowchart) + - "I want to trigger X when Y happens" → follow arrows → land on hook type + +- [ ] **T-018** — Add 5 complete hook examples with full scripts (~80 lines each) + 1. Auto-format on write (prettier/black) + 2. Security scan on commit (trufflehog/bandit) + 3. Test runner on file change + 4. Notification on session end + 5. Prompt validation (block dangerous patterns) + +- [ ] **T-019** — Add 2+ "Try It Now" blocks with verifiable commands + +- [ ] **T-020** — Add "Patterns & Recipes" section with 2+ named patterns + +**M1 Checkpoint: infrastructure live, 2 weakest modules fully upgraded** + +--- + +## Phase 2 — Deep Pass: Strong Modules Batch 1 (May–June 2026) + +**Target milestone: M2** + +### Module 01-slash-commands: Full Deep Pass + +- [ ] **T-021** — Rewrite intro with scenario ("Your teammate just pushed 47 files...") +- [ ] **T-022** — Add decision tree (Mermaid) +- [ ] **T-023** — Add 2+ "Try It Now" blocks +- [ ] **T-024** — Add "Patterns & Recipes" section with 2+ named patterns + +### Module 02-memory: Full Deep Pass + +- [ ] **T-025** — Rewrite intro with real-world scenario +- [ ] **T-026** — Add decision tree (Mermaid) +- [ ] **T-027** — Add 2+ "Try It Now" blocks +- [ ] **T-028** — Add "Patterns & Recipes" section with 2+ named patterns + +### Module 03-skills: Full Deep Pass + +- [ ] **T-029** — Rewrite intro with real-world scenario +- [ ] **T-030** — Add decision tree (Mermaid) +- [ ] **T-031** — Add 2+ "Try It Now" blocks +- [ ] **T-032** — Add "Patterns & Recipes" section with 2+ named patterns + +### Module 10-cli: Full Deep Pass + +- [ ] **T-033** — Rewrite intro with real-world scenario +- [ ] **T-034** — Add decision tree (Mermaid) +- [ ] **T-035** — Add 2+ "Try It Now" blocks +- [ ] **T-036** — Add "Patterns & Recipes" section with 2+ named patterns + +### Generator Validation + +- [ ] **T-037** — Run `scripts/build-agent-index.py` after each module upgrade; confirm valid manifest output +- [ ] **T-038** — Add CI step: validate agent-manifest.json schema on every push + +**M2 Checkpoint: 6/10 modules complete, generator producing valid manifest** + +--- + +## Phase 3 — Deep Pass: Strong Modules Batch 2 (July–August 2026) + +**Target milestone: M3** + +### Module 04-subagents: Full Deep Pass + +- [ ] **T-039** — Rewrite intro with real-world scenario +- [ ] **T-040** — Add decision tree (Mermaid) +- [ ] **T-041** — Add 2+ "Try It Now" blocks +- [ ] **T-042** — Add "Patterns & Recipes" section (e.g., "The Multi-Agent Review Pattern") + +### Module 05-mcp: Full Deep Pass + +- [ ] **T-043** — Rewrite intro with real-world scenario +- [ ] **T-044** — Add decision tree (Mermaid) +- [ ] **T-045** — Add 2+ "Try It Now" blocks +- [ ] **T-046** — Add "Patterns & Recipes" section with 2+ named patterns + +### Module 07-plugins: Full Deep Pass + +- [ ] **T-047** — Rewrite intro with real-world scenario +- [ ] **T-048** — Add decision tree (Mermaid) +- [ ] **T-049** — Add 2+ "Try It Now" blocks +- [ ] **T-050** — Add "Patterns & Recipes" section with 2+ named patterns + +### Module 09-advanced-features: Full Deep Pass + +- [ ] **T-051** — Rewrite intro with real-world scenario +- [ ] **T-052** — Add decision tree (Mermaid) +- [ ] **T-053** — Add 2+ "Try It Now" blocks +- [ ] **T-054** — Add "Patterns & Recipes" section with 2+ named patterns + +**M3 Checkpoint: all 10 modules complete and consistent** + +--- + +## Phase 4 — Agent Layer & Cross-Module (September 2026) + +**Target milestone: M4** + +### Pillar 2: Finalize AI Agent Index + +- [ ] **T-055** — Run `scripts/build-agent-index.py` against all 10 completed modules + - Produce final `agent-manifest.json` with 100% module coverage + - Produce `AGENT-INDEX.md` and link from README.md + +- [ ] **T-056** — Create `skills/claude-howto-lookup/SKILL.md` + - Reads `agent-manifest.json` to find relevant modules + - Uses `Read` to load the section + - Installation: `cp -r claude-howto/skills/claude-howto-lookup ~/.claude/skills/` + +- [ ] **T-057** — Mention lookup skill in quickstart.sh and QUICKSTART.md as optional feature + +### Pillar 3b: Cross-Module RECIPES.md + +- [ ] **T-058** — Create `RECIPES.md` with 5+ compound workflows + - Schema per recipe: name, modules-used, problem, solution code block, expected outcome + - Example: skill + hook + subagent = automated review pipeline + - Ensure HTML anchors on all major headings for deep-linking + +### Pillar 5: Community Showcase + +- [ ] **T-059** — Create `COMMUNITY-PROJECTS.md` + - Static Markdown page with submission format: name, description, link, features used + - Template entry included + - PR-based submission instructions + +**M4 Checkpoint: agent index live, recipes live, community page live** + +--- + +## Phase 5 — Version Audit & Recipe Expansion (October–November 2026) + +**Target milestone: M5** + +- [ ] **T-060** — Run full version audit: verify all 10 modules against current CC version + - Update `cc_version_verified` frontmatter in each module + - Update version badges + +- [ ] **T-061** — Expand `RECIPES.md` to 8+ recipes based on observed community patterns + +- [ ] **T-062** — Iterate agent manifest schema if new patterns emerge from completed modules + +- [ ] **T-063** — Open pinned GitHub Discussion: "Share your Claude Code workflows" + - Collect signal on real agent usage to inform future recipe expansion + +**M5 Checkpoint: all modules verified current, recipes growing** + +--- + +## Phase 6 — Compound & Sustain (December 2026 – March 2027) + +**Target milestone: M6** + +- [ ] **T-064** — Run `/docs-sync-claude-code` skill after every CC release; update `WHATS-NEW.md` + +- [ ] **T-065** — Ensure agent manifest covers 100% of modules (CI regression test) + +- [ ] **T-066** — Grow `RECIPES.md` to 10+ recipes + +- [ ] **T-067** — Monitor `COMMUNITY-PROJECTS.md` for organic growth; curate new entries + +- [ ] **T-068** — Evaluate agent usage signal from GitHub Discussions; if validated, invest in promoting the lookup skill (marketing, asm registry) + +**M6 Checkpoint: the system is self-sustaining** + +--- + +## Deferred (TODOS.md) + +These items are out of scope for this plan. Record here to avoid scope creep: + +- Skill marketplace / installable registry +- Custom website or dashboard +- Completion tracking infrastructure (cc-progress) +- Community tutorial template with CI validation +- Auto-generated CONTRIBUTORS.md +- Multi-language translations +- Quiz/assessment infrastructure upgrades +- Community voting/review mechanism for COMMUNITY-PROJECTS.md + +--- + +## Task Summary by Phase + +| Phase | Tasks | Period | Modules Touched | +|-------|-------|--------|-----------------| +| 1 — Infrastructure & Weak Modules | T-001 to T-020 | April 2026 | 06-hooks, 08-checkpoints + infra | +| 2 — Batch 1 Deep Pass | T-021 to T-038 | May–June 2026 | 01, 02, 03, 10 | +| 3 — Batch 2 Deep Pass | T-039 to T-054 | July–August 2026 | 04, 05, 07, 09 | +| 4 — Agent Layer & Cross-Module | T-055 to T-059 | September 2026 | All (manifest) + new files | +| 5 — Version Audit & Recipes | T-060 to T-063 | October–November 2026 | All (audit) | +| 6 — Sustain | T-064 to T-068 | December 2026–March 2027 | Ongoing | diff --git a/uk/prompts/remotion-video.md b/uk/prompts/remotion-video.md new file mode 100644 index 0000000..700023d --- /dev/null +++ b/uk/prompts/remotion-video.md @@ -0,0 +1,350 @@ +You are an expert Motion Designer and Senior React Engineer specializing in **Remotion**. Your goal is to take a product description and turn it into a high-energy, professionally animated video using React code. + +**START BY EXPLORING AUTONOMOUSLY:** Immediately begin exploring the codebase to gather product information. Only ask the user questions if critical information is missing or unclear after your exploration. + +Follow a 7-phase workflow, making smart decisions at each step based on the information you gather. + +--- + +# 🔄 AUTOMATED WORKFLOW + +**KEY PRINCIPLES:** + +- **Explore First:** Always begin by automatically exploring the codebase to gather product information. Do NOT start with questions about the product. +- **Ask Before Planning:** After exploration, present findings and ask user for video preferences (size, style, duration, customizations) BEFORE creating the plan. +- **Product URL First:** When a product URL is found or provided, it serves as the PRIMARY source of truth. Information from the product page takes precedence over codebase findings. +- **Value Over Tech:** Focus on value propositions, customer benefits, and features (what users gain) rather than technical specifications or implementation details. +- **Customer-Centric:** Emphasize how the product solves problems, improves lives, or delivers benefits to users. +- **Autonomous Execution:** After user confirms preferences, proceed autonomously through planning and implementation without further approval requests. + +## 📋 Phase 1: Autonomous Resource Discovery + +**OBJECTIVE:** Automatically explore the codebase and gather all available product information without asking the user. + +**ACTIONS:** + +1. **Automatically explore the codebase first:** + - Search for `README.md` for product description and value proposition + - Check `package.json` for product name, description, homepage URL + - Look for brand assets in `/assets`, `/public`, `/static`, `/images` directories + - Extract color schemes from CSS/Tailwind config files + - Find any existing marketing copy or documentation + - Look for any product URLs in config files, environment variables, or documentation + +2. **If product URL found, fetch it immediately:** + - Use WebFetch to extract information from the product page + - Product page information takes precedence over codebase findings + - Extract all value propositions, features, and branding + +3. **Synthesize all gathered information:** + - Product name and description + - Value proposition + - Key features and benefits + - Brand colors and style + - Target audience (inferred from tone) + - Any existing assets or media + +4. **Apply smart defaults for missing information:** + - **Video Format:** Landscape 1920x1080 (YouTube/web optimized) + - **Duration:** 30 seconds (ideal for most platforms) + - **Style:** Modern, clean, professional (based on brand) + - **Brand Colors:** Use extracted colors or complementary modern palette + +5. **Only ask user IF (after exploration):** + - Cannot determine product name or find any product information + - Cannot find or access product URL + - Critical ambiguity exists (e.g., B2B vs B2C drastically changes messaging) + - Conflicting information needs clarification + +**IMPORTANT:** Complete this entire exploration silently and autonomously. Do NOT ask "What I need to get started" or list requirements. Only interrupt the user if truly necessary. + +**OUTPUT:** Proceed immediately to Phase 2 with all gathered information. + +--- + +## 🔍 Phase 2: Information Analysis & Deep Dive + +**OBJECTIVE:** Analyze gathered information and extract key insights for video creation. + +**ACTIONS:** + +1. **Review all information collected in Phase 1:** + - Product page content (if URL was found and fetched) + - Codebase findings (README, package.json, assets, etc.) + - Any brand guidelines or marketing materials + +2. **Extract and prioritize (FOCUS ON VALUE, NOT TECH):** + - **Value Proposition** (primary focus) - The main benefit to customers + - **Customer Benefits** (what users gain) - How it improves their lives + - **Key Features** (described as benefits, not technical specs) + - **Unique Selling Points** - What makes it different/better + - **Use Cases** - Real-world applications + - **Brand identity** (colors, fonts, style, tone) + - **Target audience insights** (who this is for) + - **Emotional appeal** and messaging (why people care) + +3. **Silently fill gaps with intelligent inferences:** + - If value prop is not explicit, infer from features and target audience + - If target audience is unclear, infer from product type and messaging tone + - If brand colors are missing, create a complementary modern palette + - Avoid technical implementation details unless user-facing + +4. **Only ask for clarification IF:** + - Multiple conflicting value propositions exist + - Cannot determine if product is B2B or B2C (drastically affects messaging) + - Genuinely ambiguous target audience + +**OUTPUT:** Clear understanding of product value, benefits, and brand for video creation. + +--- + +## ✅ Phase 3: Present Findings & Gather User Preferences + +**OBJECTIVE:** Share what you discovered and get user input on video preferences before planning. + +**ACTIONS:** + +1. **Present a summary of discovered information:** + + ```text + 📊 DISCOVERED INFORMATION + + Product: [Name] + Value Proposition: [Main benefit to customers] + Key Features: [2-3 main benefits] + Brand Colors: [Extracted or suggested colors] + Target Audience: [Who this is for] + ``` + +2. **Ask user for preferences (REQUIRED BEFORE PROCEEDING):** + + Use a clear, concise format: + + ```text + Before I create your video, please let me know your preferences: + + 1. **Video Size/Format:** + - Landscape (1920x1080) - YouTube, website + - Portrait (1080x1920) - TikTok, Instagram Reels + - Square (1080x1080) - Instagram feed + + 2. **Video Duration:** + - 15 seconds - Quick social media ad + - 30 seconds - Standard promotional video + - 60 seconds - Detailed feature showcase + - Custom duration + + 3. **Video Style:** + - Modern & Minimal - Clean, Apple-style aesthetics + - Energetic & Bold - Fast-paced, social media style + - Professional & Corporate - Business-focused + - Custom style (describe your vision) + + 4. **Anything else to highlight or customize?** + (Specific features, messaging, colors, etc.) + ``` + +3. **Wait for user response** before proceeding to Phase 4. + +4. **Acknowledge preferences and confirm:** + - Summarize user's choices + - Apply any custom requirements + - Proceed to structure design with confirmed direction + +**OUTPUT:** User-confirmed video specifications ready for planning phase. + +--- + +## 📐 Phase 4: Structure Design (Post-Confirmation) + +**OBJECTIVE:** Create a compelling video structure using the 3-act format based on user preferences. + +**ACTIONS:** + +1. **Design video structure with user's confirmed preferences:** + + ```text + 🎬 VIDEO STRUCTURE + + Act 1: The Hook (0-5 seconds) + - [Attention-grabbing visual concept] + - [Bold animation entrance] + - [Compelling headline/question] + + Act 2: Value Demonstration (middle section) + - [Show key benefits in action] + - [Visual storytelling of customer value] + - [2-3 feature highlights as benefits] + + Act 3: Call to Action (final section) + - [Clear CTA with brand reinforcement] + - [Memorable closing visual] + - [Smooth exit animation] + ``` + +2. **Apply user preferences:** + - Use specified video size/format + - Match chosen style (minimal/energetic/professional) + - Adapt timing to specified duration + - Incorporate any custom requirements + +3. **Make creative decisions based on:** + - Product value proposition (what makes it compelling) + - Target audience (what resonates with them) + - User's style preferences + - Brand personality (visual and tonal consistency) + +4. **Present the structure briefly** then automatically proceed to Phase 5. + +**OUTPUT:** Complete video structure ready for implementation planning. + +--- + +## 🛠️ Phase 5: Technical Architecture + +**OBJECTIVE:** Design implementation architecture and proceed directly to building. + +**ACTIONS:** + +1. **Silently design** the component architecture: + - Utility functions (easing, animation helpers, color utilities) + - Reusable components (AnimatedTitle, FeatureHighlight, etc.) + - Scene components (Hook, Demo, CTA scenes) + - Main composition structure (Video.tsx, Root.tsx) + +2. **Plan technical details:** + - Animation timing and easing curves + - Color palette implementation + - Typography hierarchy + - Icon and asset strategy + - Sequence timing breakdown + +3. **Proceed directly to Phase 6** implementation without requesting approval. + +**OUTPUT:** Internal technical blueprint ready for immediate implementation. + +--- + +## 💻 Phase 6: Implementation + +**OBJECTIVE:** Build the complete Remotion video project autonomously. + +**CONSTRAINTS & TECH STACK:** + +1. **Framework:** Remotion (React) +2. **Styling:** Tailwind CSS (via `className` or standard style objects) +3. **Animation:** Use `spring`, `interpolate`, and `useCurrentFrame` for smooth motion +4. **Code Style:** Modular components. Do not dump everything in `Root.tsx` +5. **Best Practices:** + - Nothing should be static. Everything must have an entrance (opacity/scale/slide) and exit + - Use Lucide-React for icons if needed + - Use standard fonts but style them heavily (bold, tracking-tight) + - Do not use external images unless they are placeholders (e.g., `https://placehold.co/600x400`) or user-provided assets + +**ACTIONS:** + +1. **Build complete project structure** in this order: + - Utility functions (easing, animation helpers, color utilities) + - Reusable components (AnimatedTitle, FeatureHighlight, transitions) + - Scene components (HookScene, DemoScene, CTAScene) + - Main composition (Video.tsx with sequencing) + - Root configuration (Root.tsx with proper registration) + +2. **Work silently and efficiently:** + - Create all files without narrating every step + - Make design decisions based on gathered information + - Use professional animation principles + - Ensure smooth transitions between scenes + +3. **Automatically proceed to Phase 7** when implementation is complete. + +**OUTPUT:** Complete, production-ready Remotion project code. + +--- + +## 🎥 Phase 7: Delivery & Next Steps + +**OBJECTIVE:** Provide rendering instructions and mark project complete. + +**ACTIONS:** + +1. **Provide rendering instructions:** + + ```bash + # Preview the video in browser + npm run dev + + # Render the final video + npm run build + npx remotion render Video out/video.mp4 + + # For specific codec/settings + npx remotion render Video out/video.mp4 --codec h264 + ``` + +2. **Deliver summary:** + - Brief description of what was created + - Key features of the video + - Video specifications (duration, format, dimensions) + - Any notable design decisions + +3. **User can request changes if needed:** + - Timing adjustments + - Animation modifications + - Content updates + - Style tweaks + +**OUTPUT:** Complete Remotion project with clear rendering instructions, ready to use. + +--- + +# 🎯 QUALITY STANDARDS + +Throughout all phases, maintain these standards: + +**Visual Quality:** +- Professional-grade animations (smooth, purposeful, on-brand) +- Consistent spacing and alignment +- Readable typography with proper contrast +- Cohesive color usage + +**Technical Quality:** +- Clean, modular code architecture +- Performance-optimized (smooth 30fps playback) +- Proper use of Remotion APIs (spring, interpolate, Sequence) +- Type-safe (if using TypeScript) + +**Creative Quality:** +- Clear narrative structure +- Attention-grabbing opening +- Strong call-to-action +- Memorable visual moments + +--- + +# 🚀 Getting Started + +I'll create a professional Remotion video project for your product. Here's my workflow: + +## Phase 1-2: Autonomous Exploration (I do this automatically) + +1. Explore your codebase for product details, brand assets, and colors +2. Fetch and analyze product page (if URL found) +3. Extract value propositions and key benefits + +## Phase 3: Your Input (I'll ask you) + +1. Present what I discovered +2. Ask for your video preferences: + - Video size/format (landscape/portrait/square) + - Duration (15s/30s/60s) + - Style (minimal/energetic/professional) + - Any customizations + +## Phase 4-7: Autonomous Execution (I do this automatically) + +1. Design video structure based on your preferences +2. Build complete Remotion project with professional animations +3. Deliver production-ready code with rendering instructions + +Let's create something amazing! diff --git a/uk/resources/DESIGN-SYSTEM.md b/uk/resources/DESIGN-SYSTEM.md new file mode 100644 index 0000000..1b5e1f0 --- /dev/null +++ b/uk/resources/DESIGN-SYSTEM.md @@ -0,0 +1,121 @@ +# Claude How To — Дизайн-система + +## Візуальна ідентичність + +### Концепція дизайну іконки: Компас з кодовою дужкою + +Іконка Claude How To використовує **компас з кодовою дужкою `>`** для представлення направленої навігації кодом: + +``` + N (green) + ▲ + │ +W ───>─── E Compass = Guidance/Direction + │ > Bracket = Code/Terminal/CLI + ▼ + S (black) +``` + +Це створює: +- **Візуальна ясність**: Одразу комунікує "гайд з навігації кодом" +- **Символічне значення**: Компас = пошук шляху; `>` = код/термінал +- **Масштабованість**: Працює при будь-якому розмірі від 16px до 512px +- **Відповідність бренду**: Відповідає естетиці інструменту розробника з мінімальною палітрою + +--- + +## Кольорова система + +### Палітра + +| Колір | Hex | RGB | Використання | +|-------|-----|-----|-------------| +| Чорний (основний) | `#000000` | 0, 0, 0 | Основні обведення, текст, південна стрілка | +| Білий (фон) | `#FFFFFF` | 255, 255, 255 | Світлі фони | +| Сірий (вторинний) | `#6B7280` | 107, 114, 128 | Малі позначки, вторинний текст | +| Яскраво-зелений (акцент) | `#22C55E` | 34, 197, 94 | Північна стрілка, центральна точка, акцентні лінії | +| Майже чорний (темний фон) | `#0A0A0A` | 10, 10, 10 | Фони dark mode | + +### Коефіцієнти контрасту (WCAG) + +- Чорний на білому: **21:1** AAA +- Сірий на білому: **4.6:1** AA +- Зелений на білому: **3.2:1** (тільки декоративний, не для тексту) +- Білий на темному: **19.5:1** AAA + +### Правило акцентного кольору + +**Яскраво-зелений (#22C55E) зарезервований тільки для виділень:** +- Північна стрілка компасу +- Центральна точка +- Акцентні підкреслення/рамки +- Ніколи як фон +- Ніколи для основного тексту + +--- + +## Типографіка + +### Шрифт логотипу +- **Сімейство**: Inter, SF Pro Display, -apple-system, Segoe UI, sans-serif +- **"Claude"**: 42px, weight 700 (bold), Чорний +- **"How-To"**: 32px, weight 500 (medium), Сірий (#6B7280) +- **Підзаголовок**: 10px, weight 500, Сірий, letter-spacing 1.5px, uppercase + +--- + +## Деталі іконки + +### Специфікації компасу + +``` +Element | Stroke/Fill | Color +--------------------|----------------|------------------ +Outer ring | 3px stroke | Black / White (dark mode) +North tick | 2.5px stroke | Black / White (dark mode) +Other cardinal ticks| 2px stroke | Gray / White 50% (dark mode) +Intercardinal ticks | 1.5px stroke | Gray / White 40% (dark mode) +North needle | filled polygon | #22C55E (always green) +South needle | filled polygon | Black / White (dark mode) +> bracket | 3px stroke | Black / White (dark mode) +Center dot | filled circle | #22C55E (always green) +``` + +### Прогресія розмірів + +``` +16px → Кільце + стрілки + шеврон (мінімально) +32px → Додаються кардинальні позначки +64px → Додаються інтеркардинальні позначки +128px → Повна деталізація, всі елементи чіткі +256px → Максимальна деталізація, товсті обведення +``` + +--- + +## Настанови з розмірів + +### Розміри логотипу +- **Мінімум**: 200px ширина (для веб) +- **Рекомендовано**: 520px (нативний розмір) +- **Максимум**: Необмежено (векторний формат) +- **Пропорції**: ~4.3:1 (ширина:висота) + +### Розміри іконки +- **Мінімум**: 16px (фавікон) +- **Рекомендовано**: 64-256px (додатки, аватари) +- **Максимум**: Необмежено (векторний формат) +- **Пропорції**: 1:1 (квадрат) + +--- + +## Доступність + +- Усі тексти відповідають WCAG AA (мінімум 4.5:1) +- Зелений акцент — декоративний, не інформаційний +- Без залежності від червоно-зеленого розрізнення + +--- + +**Останнє оновлення**: Лютий 2026 +**Версія дизайн-системи**: 3.0 diff --git a/uk/resources/QUICK-START.md b/uk/resources/QUICK-START.md new file mode 100644 index 0000000..a7c446e --- /dev/null +++ b/uk/resources/QUICK-START.md @@ -0,0 +1,89 @@ +# Швидкий старт — Брендові ресурси + +## Копіювання ресурсів у ваш проєкт + +```bash +# Copy all resources to your web project +cp -r resources/ /path/to/your/website/ + +# Or just the favicons for web +cp resources/favicons/* /path/to/your/website/public/ +``` + +## Додавання в HTML (копіювання та вставка) + +```html + + + + + + +``` + +## Використання в Markdown/документації + +```markdown +# Claude How To + +![Claude How To Logo](resources/logos/claude-howto-logo.svg) + +![Icon](resources/icons/claude-howto-icon.svg) +``` + +## Рекомендовані розміри + +| Призначення | Розмір | Файл | +|-------------|--------|------| +| Заголовок сайту | 520×120 | `logos/claude-howto-logo.svg` | +| Іконка додатку | 256×256 | `icons/claude-howto-icon.svg` | +| Вкладка браузера | 32×32 | `favicons/favicon-32.svg` | +| Домашній екран мобільного | 128×128 | `favicons/favicon-128.svg` | +| Десктопний додаток | 256×256 | `favicons/favicon-256.svg` | +| Малий аватар | 64×64 | `favicons/favicon-64.svg` | + +## Значення кольорів + +```css +/* Use these in your CSS */ +--color-primary: #000000; +--color-secondary: #6B7280; +--color-accent: #22C55E; +--color-bg-light: #FFFFFF; +--color-bg-dark: #0A0A0A; +``` + +## Значення дизайну іконки + +**Компас з кодовою дужкою**: +- Кільце компасу = Навігація, структурований навчальний шлях +- Зелена північна стрілка = Напрямок, прогрес, керівництво +- Чорна південна стрілка = Основа, міцний фундамент +- Дужка `>` = Промпт терміналу, код, контекст CLI +- Позначки = Точність, структуровані кроки + +Це символізує "пошук шляху через код з чітким керівництвом". + +## Що і де використовувати + +### Сайт +- **Заголовок**: Логотип (`logos/claude-howto-logo.svg`) +- **Фавікон**: 32px (`favicons/favicon-32.svg`) +- **Соціальний превʼю**: Іконка (`icons/claude-howto-icon.svg`) + +### GitHub +- **Бейдж README**: Іконка 64-128px +- **Аватар репозиторію**: Іконка + +### Соціальні мережі +- **Аватар**: Іконка 256×256px +- **Банер**: Логотип 520×120px +- **Мініатюра**: Іконка 256×256px + +### Документація +- **Заголовки розділів**: Логотип або іконка (масштабовані) +- **Іконки навігації**: Фавікон 32-64px + +--- + +Див. [README.md](README.md) для повної документації. diff --git a/uk/resources/README.md b/uk/resources/README.md new file mode 100644 index 0000000..e54ed45 --- /dev/null +++ b/uk/resources/README.md @@ -0,0 +1,154 @@ + + + Claude How To + + +# Claude How To — Брендові ресурси + +Повна колекція логотипів, іконок та фавіконів для проєкту Claude How To. Усі ресурси використовують дизайн V3.0: компас з символом кодової дужки (`>`), що представляє направлену навігацію кодом — з палітрою Чорний/Білий/Сірий та акцентом Яскраво-зелений (#22C55E). + +## Структура каталогів + +``` +resources/ +├── logos/ +│ ├── claude-howto-logo.svg # Основний логотип - Light mode (520×120px) +│ └── claude-howto-logo-dark.svg # Основний логотип - Dark mode (520×120px) +├── icons/ +│ ├── claude-howto-icon.svg # Іконка додатку - Light mode (256×256px) +│ └── claude-howto-icon-dark.svg # Іконка додатку - Dark mode (256×256px) +└── favicons/ + ├── favicon-16.svg # Фавікон - 16×16px + ├── favicon-32.svg # Фавікон - 32×32px (основний) + ├── favicon-64.svg # Фавікон - 64×64px + ├── favicon-128.svg # Фавікон - 128×128px + └── favicon-256.svg # Фавікон - 256×256px +``` + +Додаткові ресурси в `assets/logo/`: +``` +assets/logo/ +├── logo-full.svg # Знак + текст (горизонтально) +├── logo-mark.svg # Тільки символ компасу (120×120px) +├── logo-wordmark.svg # Тільки текст +├── logo-icon.svg # Іконка додатку (512×512, округлена) +├── favicon.svg # 16×16 оптимізований +├── logo-white.svg # Біла версія для темних фонів +└── logo-black.svg # Чорна монохромна версія +``` + +## Огляд ресурсів + +### Концепція дизайну (V3.0) + +**Компас з кодовою дужкою** — навігація зустрічає код: +- **Кільце компасу** = Навігація, пошук шляху +- **Північна стрілка (зелена)** = Напрямок, прогрес на навчальному шляху +- **Південна стрілка (чорна)** = Основа, міцний фундамент +- **Дужка `>`** = Промпт терміналу, код, контекст CLI +- **Позначки** = Точність, структуроване навчання + +### Логотипи + +**Файли**: +- `logos/claude-howto-logo.svg` (Light mode) +- `logos/claude-howto-logo-dark.svg` (Dark mode) + +**Специфікації**: +- **Розмір**: 520×120 px +- **Призначення**: Основний логотип заголовку/брендингу з текстом +- **Використання**: Заголовки сайтів, бейджі README, маркетингові матеріали, друковані матеріали +- **Формат**: SVG (повністю масштабований) +- **Режими**: Light (білий фон) та Dark (фон #0A0A0A) + +### Іконки + +**Файли**: +- `icons/claude-howto-icon.svg` (Light mode) +- `icons/claude-howto-icon-dark.svg` (Dark mode) + +**Специфікації**: +- **Розмір**: 256×256 px +- **Призначення**: Іконка додатку, аватари, мініатюри +- **Формат**: SVG (повністю масштабований) + +### Фавікони + +Оптимізовані версії різних розмірів для веб-використання: + +| Файл | Розмір | DPI | Використання | +|------|--------|-----|-------------| +| `favicon-16.svg` | 16×16 px | 1x | Вкладки браузера (старі браузери) | +| `favicon-32.svg` | 32×32 px | 1x | Стандартний фавікон | +| `favicon-64.svg` | 64×64 px | 1x-2x | Дисплеї High-DPI | +| `favicon-128.svg` | 128×128 px | 2x | Apple touch icon, закладки | +| `favicon-256.svg` | 256×256 px | 4x | Сучасні браузери, іконки PWA | + +## Інтеграція HTML + +### Базове налаштування фавіконів + +```html + + + + + + + + + +``` + +## Палітра кольорів + +### Основні кольори +- **Чорний**: `#000000` (Основний текст, обведення, південна стрілка) +- **Білий**: `#FFFFFF` (Світлі фони) +- **Сірий**: `#6B7280` (Вторинний текст, малі позначки) + +### Акцентний колір +- **Яскраво-зелений**: `#22C55E` (Північна стрілка, центральна точка, акцентні лінії — тільки для виділень, ніколи як фон) + +### Dark mode +- **Фон**: `#0A0A0A` (Майже чорний) + +### CSS-змінні +```css +--color-primary: #000000; +--color-secondary: #6B7280; +--color-accent: #22C55E; +--color-bg-light: #FFFFFF; +--color-bg-dark: #0A0A0A; +``` + +## Настанови з дизайну + +### Використання логотипу +- Використовуйте на білому або темному (#0A0A0A) фоні +- Масштабуйте пропорційно +- Залишайте вільний простір навколо (мінімум: висота логотипу / 2) +- Використовуйте надані light/dark варіанти для відповідних фонів + +### Доступність +- Високі коефіцієнти контрасту (WCAG AA — мінімум 4.5:1) +- Чисті геометричні форми, розпізнавані при будь-якому розмірі +- Масштабований векторний формат +- Без тексту в іконках (текст додається окремо) +- Без залежності від червоно-зеленого розрізнення кольорів + +## Атрибуція + +Ці ресурси є частиною проєкту Claude How To. + +**Ліцензія**: MIT (див. файл LICENSE проєкту) + +## Історія версій + +- **v3.0** (Лютий 2026): Дизайн компас-дужка з палітрою Чорний/Білий/Сірий + Зелений акцент +- **v2.0** (Січень 2026): Дизайн 12-променевого зоряного спалаху в стилі Claude з смарагдовою палітрою +- **v1.0** (Січень 2026): Оригінальний дизайн іконки прогресії на основі шестикутника + +--- +**Останнє оновлення**: Лютий 2026 +**Поточна версія**: 3.0 (Компас-дужка) diff --git a/uk/scripts/README.md b/uk/scripts/README.md new file mode 100644 index 0000000..d43c273 --- /dev/null +++ b/uk/scripts/README.md @@ -0,0 +1,120 @@ + + + Claude How To + + +# Скрипт збірки EPUB + +Збірка EPUB-книги з markdown-файлів Claude How-To. + +## Функції + +- Організує розділи за структурою каталогів (01-slash-commands, 02-memory тощо) +- Рендерить Mermaid-діаграми як PNG-зображення через Kroki.io API +- Асинхронне паралельне завантаження — рендерить усі діаграми одночасно +- Генерує обкладинку з логотипу проєкту +- Конвертує внутрішні markdown-посилання у посилання на розділи EPUB +- Суворий режим помилок — падає, якщо діаграма не може бути відрендерена + +## Вимоги + +- Python 3.10+ +- [uv](https://github.com/astral-sh/uv) +- Інтернет-з'єднання для рендерингу Mermaid-діаграм + +## Швидкий старт + +```bash +# Simplest way - uv handles everything +uv run scripts/build_epub.py +``` + +## Налаштування розробки + +```bash +# Create virtual environment +uv venv + +# Activate and install dependencies +source .venv/bin/activate +uv pip install -r requirements-dev.txt + +# Run tests +pytest scripts/tests/ -v + +# Run the script +python scripts/build_epub.py +``` + +## Параметри командного рядка + +``` +usage: build_epub.py [-h] [--root ROOT] [--output OUTPUT] [--verbose] + [--timeout TIMEOUT] [--max-concurrent MAX_CONCURRENT] + +options: + -h, --help show this help message and exit + --root, -r ROOT Root directory (default: repo root) + --output, -o OUTPUT Output path (default: claude-howto-guide.epub) + --verbose, -v Enable verbose logging + --timeout TIMEOUT API timeout in seconds (default: 30) + --max-concurrent N Max concurrent requests (default: 10) +``` + +## Приклади + +```bash +# Build with verbose output +uv run scripts/build_epub.py --verbose + +# Custom output location +uv run scripts/build_epub.py --output ~/Desktop/claude-guide.epub + +# Limit concurrent requests (if rate-limited) +uv run scripts/build_epub.py --max-concurrent 5 +``` + +## Вивід + +Створює `claude-howto-guide.epub` у кореневому каталозі репозиторію. + +EPUB включає: +- Обкладинку з логотипом проєкту +- Зміст з вкладеними секціями +- Весь markdown-контент, конвертований у EPUB-сумісний HTML +- Mermaid-діаграми, відрендерені як PNG-зображення + +## Запуск тестів + +```bash +# With virtual environment +source .venv/bin/activate +pytest scripts/tests/ -v + +# Or with uv directly +uv run --with pytest --with pytest-asyncio \ + --with ebooklib --with markdown --with beautifulsoup4 \ + --with httpx --with pillow --with tenacity \ + pytest scripts/tests/ -v +``` + +## Залежності + +Керуються через PEP 723 inline script metadata: + +| Пакет | Призначення | +|-------|-------------| +| `ebooklib` | Генерація EPUB | +| `markdown` | Конвертація Markdown → HTML | +| `beautifulsoup4` | Парсинг HTML | +| `httpx` | Асинхронний HTTP-клієнт | +| `pillow` | Генерація обкладинки | +| `tenacity` | Логіка повторних спроб | + +## Усунення проблем + +**Збірка падає з мережевою помилкою**: Перевірте інтернет-з'єднання та стан Kroki.io. Спробуйте `--timeout 60`. + +**Обмеження частоти**: Зменште паралельні запити з `--max-concurrent 3`. + +**Відсутній логотип**: Скрипт генерує текстову обкладинку, якщо `claude-howto-logo.png` не знайдено. From 1dcd8d370cd95673bc649a4f0212b9a8caf6f949 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 02:18:15 +0300 Subject: [PATCH 17/20] i18n(uk): complete translation of claude_concepts_guide.md Full Ukrainian translation of the comprehensive concepts guide (87KB, 3135 lines). All code blocks, Mermaid diagrams, and JSON configs preserved as-is. Ref: luongnv89/claude-howto#63 --- uk/claude_concepts_guide.md | 846 ++++++++++++++++++------------------ 1 file changed, 423 insertions(+), 423 deletions(-) diff --git a/uk/claude_concepts_guide.md b/uk/claude_concepts_guide.md index fbce8e4..3b996a9 100644 --- a/uk/claude_concepts_guide.md +++ b/uk/claude_concepts_guide.md @@ -3,13 +3,13 @@ Claude How To -# Complete Guide to Claude Concepts +# Повний довідник концепцій Claude -A comprehensive reference guide covering Slash Commands, Subagents, Memory, MCP Protocol, and Agent Skills with tables, diagrams, and practical examples. +Комплексний довідник, що охоплює слеш-команди, субагентів, пам'ять, протокол MCP та навички агентів з таблицями, діаграмами та практичними прикладами. --- -## Table of Contents +## Зміст 1. [Slash Commands](#slash-commands) 2. [Subagents](#subagents) @@ -24,13 +24,13 @@ A comprehensive reference guide covering Slash Commands, Subagents, Memory, MCP --- -## Slash Commands +## Слеш-команди -### Overview +### Огляд -Slash commands are user-invoked shortcuts stored as Markdown files that Claude Code can execute. They enable teams to standardize frequently-used prompts and workflows. +Слеш-команди — це ярлики, ініційовані користувачем, що зберігаються як Markdown-файли, які Claude Code може виконувати. Вони дозволяють командам стандартизувати часто використовувані промпти та робочі процеси. -### Architecture +### Архітектура ```mermaid graph TD @@ -41,7 +41,7 @@ graph TD E -->|Returns| F["Result in Context"] ``` -### File Structure +### Структура файлів ```mermaid graph LR @@ -53,7 +53,7 @@ graph LR E -->|contains| G["generate-readme.md"] ``` -### Command Organization Table +### Таблиця організації команд | Location | Scope | Availability | Use Case | Git Tracked | |----------|-------|--------------|----------|-------------| @@ -61,7 +61,7 @@ graph LR | `~/.claude/commands/` | Personal | Individual user | Personal shortcuts across projects | ❌ No | | Subdirectories | Namespaced | Based on parent | Organize by category | ✅ Yes | -### Features & Capabilities +### Функції та можливості | Feature | Example | Supported | |---------|---------|-----------| @@ -71,11 +71,11 @@ graph LR | Arguments | `/pr --verbose` | ✅ Yes | | MCP commands | `/mcp__github__list_prs` | ✅ Yes | -### Practical Examples +### Практичні приклади -#### Example 1: Code Optimization Command +#### Приклад 1: Команда оптимізації коду -**File:** `.claude/commands/optimize.md` +**Файл:** `.claude/commands/optimize.md` ```markdown --- @@ -101,7 +101,7 @@ Format your response with: - Recommended fix with code example ``` -**Usage:** +**Використання:** ```bash # User types in Claude Code /optimize @@ -109,9 +109,9 @@ Format your response with: # Claude loads the prompt and waits for code input ``` -#### Example 2: Pull Request Helper Command +#### Приклад 2: Команда-помічник для Pull Request -**File:** `.claude/commands/pr.md` +**Файл:** `.claude/commands/pr.md` ```markdown --- @@ -143,16 +143,16 @@ Before creating a PR, execute these steps: - Potential impacts ``` -**Usage:** +**Використання:** ```bash /pr # Claude runs through checklist and prepares the PR ``` -#### Example 3: Hierarchical Documentation Generator +#### Приклад 3: Ієрархічний генератор документації -**File:** `.claude/commands/docs/generate-api-docs.md` +**Файл:** `.claude/commands/docs/generate-api-docs.md` ```markdown --- @@ -178,7 +178,7 @@ Output format: - Add TypeScript types ``` -### Command Lifecycle Diagram +### Діаграма життєвого циклу команди ```mermaid sequenceDiagram @@ -198,26 +198,26 @@ sequenceDiagram Claude->>User: Returns analysis ``` -### Best Practices +### Найкращі практики -| ✅ Do | ❌ Don't | +| ✅ Рекомендовано | ❌ Не рекомендовано | |------|---------| -| Use clear, action-oriented names | Create commands for one-time tasks | -| Document trigger words in description | Build complex logic in commands | -| Keep commands focused on single task | Create redundant commands | -| Version control project commands | Hardcode sensitive information | -| Organize in subdirectories | Create long lists of commands | -| Use simple, readable prompts | Use abbreviated or cryptic wording | +| Використовуйте зрозумілі, орієнтовані на дію назви | Створювати команди для одноразових завдань | +| Документуйте ключові слова в описі | Будувати складну логіку в командах | +| Зосередьте команду на одному завданні | Створювати дублюючі команди | +| Контролюйте версії проєктних команд | Жорстко прописувати конфіденційну інформацію | +| Організовуйте у підкаталогах | Створювати довгі списки команд | +| Використовуйте прості, зрозумілі промпти | Використовувати скорочені або незрозумілі формулювання | --- -## Subagents +## Субагенти -### Overview +### Огляд -Subagents are specialized AI assistants with isolated context windows and customized system prompts. They enable delegated task execution while maintaining clean separation of concerns. +Субагенти — це спеціалізовані AI-асистенти з ізольованими контекстними вікнами та налаштованими системними промптами. Вони забезпечують делеговане виконання завдань, зберігаючи чітке розділення відповідальностей. -### Architecture Diagram +### Діаграма архітектури ```mermaid graph TB @@ -237,7 +237,7 @@ graph TB Main -->|synthesizes| User ``` -### Subagent Lifecycle +### Життєвий цикл субагента ```mermaid sequenceDiagram @@ -257,16 +257,16 @@ sequenceDiagram MainAgent-->>User: Provide synthesis ``` -### Subagent Configuration Table +### Таблиця конфігурації субагента -| Configuration | Type | Purpose | Example | +| Конфігурація | Тип | Призначення | Приклад | |---------------|------|---------|---------| -| `name` | String | Agent identifier | `code-reviewer` | -| `description` | String | Purpose & trigger terms | `Comprehensive code quality analysis` | -| `tools` | List/String | Allowed capabilities | `read, grep, diff, lint_runner` | -| `system_prompt` | Markdown | Behavioral instructions | Custom guidelines | +| `name` | String | Ідентифікатор агента | `code-reviewer` | +| `description` | String | Призначення та ключові слова | `Comprehensive code quality analysis` | +| `tools` | List/String | Дозволені можливості | `read, grep, diff, lint_runner` | +| `system_prompt` | Markdown | Поведінкові інструкції | Користувацькі настанови | -### Tool Access Hierarchy +### Ієрархія доступу до інструментів ```mermaid graph TD @@ -279,11 +279,11 @@ graph TD C -->|Explicit List| C2["Bash(npm:*), Bash(test:*)"] ``` -### Practical Examples +### Практичні приклади -#### Example 1: Complete Subagent Setup +#### Приклад 1: Повне налаштування субагента -**File:** `.claude/agents/code-reviewer.md` +**Файл:** `.claude/agents/code-reviewer.md` ```yaml --- @@ -329,7 +329,7 @@ For each issue: - **Fix**: Use JOIN or batch query ``` -**File:** `.claude/agents/test-engineer.md` +**Файл:** `.claude/agents/test-engineer.md` ```yaml --- @@ -370,7 +370,7 @@ You are expert at: - Report missing coverage areas ``` -**File:** `.claude/agents/documentation-writer.md` +**Файл:** `.claude/agents/documentation-writer.md` ```yaml --- @@ -415,7 +415,7 @@ You create: - Related topics ``` -#### Example 2: Subagent Delegation in Action +#### Приклад 2: Делегування субагентам у дії ```markdown # Scenario: Building a Payment Feature @@ -451,9 +451,9 @@ You create: - Returns complete solution to user ``` -#### Example 3: Tool Permission Scoping +#### Приклад 3: Обмеження доступу до інструментів -**Restrictive Setup - Limited to Specific Commands** +**Обмежене налаштування — лише конкретні команди** ```yaml --- @@ -476,7 +476,7 @@ This agent: This ensures the reviewer doesn't accidentally break anything. ``` -**Extended Setup - All Tools for Implementation** +**Розширене налаштування — усі інструменти для реалізації** ```yaml --- @@ -500,7 +500,7 @@ This agent: Full capabilities for independent feature development. ``` -### Subagent Context Management +### Управління контекстом субагента ```mermaid graph TB @@ -523,30 +523,30 @@ graph TB style D fill:#fff9c4 ``` -### When to Use Subagents +### Коли використовувати субагентів -| Scenario | Use Subagent | Why | +| Сценарій | Використовувати субагента | Чому | |----------|--------------|-----| -| Complex feature with many steps | ✅ Yes | Separate concerns, prevent context pollution | -| Quick code review | ❌ No | Not necessary overhead | -| Parallel task execution | ✅ Yes | Each subagent has own context | -| Specialized expertise needed | ✅ Yes | Custom system prompts | -| Long-running analysis | ✅ Yes | Prevents main context exhaustion | -| Single task | ❌ No | Adds latency unnecessarily | +| Складна функція з багатьма кроками | ✅ Так | Розділення відповідальностей, запобігання засміченню контексту | +| Швидкий код-рев'ю | ❌ Ні | Непотрібні накладні витрати | +| Паралельне виконання завдань | ✅ Так | Кожен субагент має власний контекст | +| Потрібна спеціалізована експертиза | ✅ Так | Налаштовані системні промпти | +| Тривалий аналіз | ✅ Так | Запобігає вичерпанню основного контексту | +| Одне завдання | ❌ Ні | Додає затримку без необхідності | -### Agent Teams +### Команди агентів -Agent Teams coordinate multiple agents working on related tasks. Rather than delegating to one subagent at a time, Agent Teams allow the main agent to orchestrate a group of agents that collaborate, share intermediate results, and work toward a common goal. This is useful for large-scale tasks like full-stack feature development where a frontend agent, backend agent, and testing agent work in parallel. +Команди агентів координують кількох агентів, що працюють над пов'язаними завданнями. Замість делегування одному субагенту за раз, команди агентів дозволяють основному агенту оркеструвати групу агентів, які співпрацюють, обмінюються проміжними результатами та працюють над спільною метою. Це корисно для масштабних завдань, таких як повноцінна розробка фічі, де фронтенд-агент, бекенд-агент та агент тестування працюють паралельно. --- -## Memory +## Пам'ять -### Overview +### Огляд -Memory enables Claude to retain context across sessions and conversations. It exists in two forms: automatic synthesis in claude.ai, and filesystem-based CLAUDE.md in Claude Code. +Пам'ять дозволяє Claude зберігати контекст між сесіями та розмовами. Вона існує у двох формах: автоматичний синтез у claude.ai та файлова система CLAUDE.md у Claude Code. -### Memory Architecture +### Архітектура пам'яті ```mermaid graph TB @@ -561,9 +561,9 @@ graph TB A -->|Uses context| C ``` -### Memory Hierarchy in Claude Code (7 Tiers) +### Ієрархія пам'яті в Claude Code (7 рівнів) -Claude Code loads memory from 7 tiers, listed from highest to lowest priority: +Claude Code завантажує пам'ять із 7 рівнів, від найвищого до найнижчого пріоритету: ```mermaid graph TD @@ -583,30 +583,30 @@ graph TD style G fill:#fff3e0,stroke:#333,color:#333 ``` -### Memory Locations Table +### Таблиця розташування пам'яті -| Tier | Location | Scope | Priority | Shared | Best For | +| Рівень | Розташування | Область | Пріоритет | Спільний | Найкраще для | |------|----------|-------|----------|--------|----------| -| 1. Managed Policy | Enterprise admin | Organization | Highest | All org users | Compliance, security policies | -| 2. Project | `./CLAUDE.md` | Project | High | Team (Git) | Team standards, architecture | -| 3. Project Rules | `.claude/rules/*.md` | Project | High | Team (Git) | Modular project conventions | -| 4. User | `~/.claude/CLAUDE.md` | Personal | Medium | Individual | Personal preferences | -| 5. User Rules | `~/.claude/rules/*.md` | Personal | Medium | Individual | Personal rule modules | -| 6. Local | `.claude/local/CLAUDE.md` | Local | Low | Not shared | Machine-specific settings | -| 7. Auto Memory | Automatic | Session | Lowest | Individual | Learned preferences, patterns | +| 1. Керована політика | Адмін підприємства | Організація | Найвищий | Усі користувачі орг. | Відповідність, політики безпеки | +| 2. Проєкт | `./CLAUDE.md` | Проєкт | Високий | Команда (Git) | Стандарти команди, архітектура | +| 3. Правила проєкту | `.claude/rules/*.md` | Проєкт | Високий | Команда (Git) | Модульні конвенції проєкту | +| 4. Користувач | `~/.claude/CLAUDE.md` | Персональний | Середній | Індивідуальний | Особисті налаштування | +| 5. Правила користувача | `~/.claude/rules/*.md` | Персональний | Середній | Індивідуальний | Персональні модулі правил | +| 6. Локальний | `.claude/local/CLAUDE.md` | Локальний | Низький | Не спільний | Налаштування конкретної машини | +| 7. Авто-пам'ять | Автоматичний | Сесія | Найнижчий | Індивідуальний | Засвоєні вподобання, патерни | -### Auto Memory +### Авто-пам'ять -Auto Memory automatically captures user preferences and patterns observed during sessions. Claude learns from your interactions and remembers: +Авто-пам'ять автоматично фіксує вподобання користувача та патерни, виявлені під час сесій. Claude навчається з ваших взаємодій і запам'ятовує: -- Coding style preferences -- Common corrections you make -- Framework and tool choices -- Communication style preferences +- Вподобання стилю кодування +- Типові виправлення, які ви робите +- Вибір фреймворків та інструментів +- Вподобання стилю комунікації -Auto Memory works in the background and does not require manual configuration. +Авто-пам'ять працює у фоновому режимі і не потребує ручного налаштування. -### Memory Update Lifecycle +### Життєвий цикл оновлення пам'яті ```mermaid sequenceDiagram @@ -625,11 +625,11 @@ sequenceDiagram Claude-->>User: "Memory saved!" ``` -### Practical Examples +### Практичні приклади -#### Example 1: Project Memory Structure +#### Приклад 1: Структура пам'яті проєкту -**File:** `./CLAUDE.md` +**Файл:** `./CLAUDE.md` ```markdown # Project Configuration @@ -722,9 +722,9 @@ sequenceDiagram - Admin Panel: `/projects/admin` ``` -#### Example 2: Directory-Specific Memory +#### Приклад 2: Пам'ять для конкретного каталогу -**File:** `./src/api/CLAUDE.md` +**Файл:** `./src/api/CLAUDE.md` ~~~~markdown # API Module Standards @@ -790,9 +790,9 @@ All responses must follow this structure: - Tag cache keys with resource type ~~~~ -#### Example 3: Personal Memory +#### Приклад 3: Персональна пам'ять -**File:** `~/.claude/CLAUDE.md` +**Файл:** `~/.claude/CLAUDE.md` ~~~~markdown # My Development Preferences @@ -857,9 +857,9 @@ project/ - **Test Framework**: Jest with React Testing Library ~~~~ -#### Example 4: Memory Update During Session +#### Приклад 4: Оновлення пам'яті під час сесії -**Session Interaction:** +**Взаємодія в сесії:** ```markdown User: Remember that I prefer using React hooks instead of class components @@ -884,9 +884,9 @@ Added to ./CLAUDE.md: - Use useMemo for expensive computations ``` -### Memory in Claude Web/Desktop +### Пам'ять у Claude Web/Desktop -#### Memory Synthesis Timeline +#### Хронологія синтезу пам'яті ```mermaid graph LR @@ -897,7 +897,7 @@ graph LR E -->|24 hours later| F["Memory Refreshed"] ``` -**Example Memory Summary:** +**Приклад підсумку пам'яті:** ```markdown ## Claude's Memory of User @@ -927,27 +927,27 @@ graph LR - Document architecture ``` -### Memory Features Comparison +### Порівняння функцій пам'яті -| Feature | Claude Web/Desktop | Claude Code (CLAUDE.md) | +| Функція | Claude Web/Desktop | Claude Code (CLAUDE.md) | |---------|-------------------|------------------------| -| Auto-synthesis | ✅ Every 24h | ❌ Manual | -| Cross-project | ✅ Shared | ❌ Project-specific | -| Team access | ✅ Shared projects | ✅ Git-tracked | -| Searchable | ✅ Built-in | ✅ Through `/memory` | -| Editable | ✅ In-chat | ✅ Direct file edit | -| Import/Export | ✅ Yes | ✅ Copy/paste | -| Persistent | ✅ 24h+ | ✅ Indefinite | +| Авто-синтез | ✅ Кожні 24 год | ❌ Вручну | +| Між проєктами | ✅ Спільний | ❌ Специфічний для проєкту | +| Доступ команди | ✅ Спільні проєкти | ✅ Через Git | +| Пошук | ✅ Вбудований | ✅ Через `/memory` | +| Редагування | ✅ У чаті | ✅ Пряме редагування файлу | +| Імпорт/Експорт | ✅ Так | ✅ Копіювання/вставка | +| Постійність | ✅ 24 год+ | ✅ Необмежено | --- -## MCP Protocol +## Протокол MCP -### Overview +### Огляд -MCP (Model Context Protocol) is a standardized way for Claude to access external tools, APIs, and real-time data sources. Unlike Memory, MCP provides live access to changing data. +MCP (Model Context Protocol) — це стандартизований спосіб доступу Claude до зовнішніх інструментів, API та джерел даних у реальному часі. На відміну від пам'яті, MCP забезпечує живий доступ до змінюваних даних. -### MCP Architecture +### Архітектура MCP ```mermaid graph TB @@ -966,7 +966,7 @@ graph TB B -->|Response| A ``` -### MCP Ecosystem +### Екосистема MCP ```mermaid graph TB @@ -983,7 +983,7 @@ graph TB F -->|Docs| K["Google Drive"] ``` -### MCP Setup Process +### Процес налаштування MCP ```mermaid sequenceDiagram @@ -1003,24 +1003,24 @@ sequenceDiagram Claude->>User: ✅ MCP connected! ``` -### Available MCP Servers Table +### Таблиця доступних MCP-серверів -| MCP Server | Purpose | Common Tools | Auth | Real-time | +| MCP-сервер | Призначення | Основні інструменти | Авторизація | Реальний час | |------------|---------|--------------|------|-----------| -| **Filesystem** | File operations | read, write, delete | OS permissions | ✅ Yes | -| **GitHub** | Repository management | list_prs, create_issue, push | OAuth | ✅ Yes | -| **Slack** | Team communication | send_message, list_channels | Token | ✅ Yes | -| **Database** | SQL queries | query, insert, update | Credentials | ✅ Yes | -| **Google Docs** | Document access | read, write, share | OAuth | ✅ Yes | -| **Asana** | Project management | create_task, update_status | API Key | ✅ Yes | -| **Stripe** | Payment data | list_charges, create_invoice | API Key | ✅ Yes | -| **Memory** | Persistent memory | store, retrieve, delete | Local | ❌ No | +| **Filesystem** | Файлові операції | read, write, delete | Права ОС | ✅ Так | +| **GitHub** | Управління репозиторіями | list_prs, create_issue, push | OAuth | ✅ Так | +| **Slack** | Командна комунікація | send_message, list_channels | Token | ✅ Так | +| **Database** | SQL-запити | query, insert, update | Облікові дані | ✅ Так | +| **Google Docs** | Доступ до документів | read, write, share | OAuth | ✅ Так | +| **Asana** | Управління проєктами | create_task, update_status | API Key | ✅ Так | +| **Stripe** | Платіжні дані | list_charges, create_invoice | API Key | ✅ Так | +| **Memory** | Постійна пам'ять | store, retrieve, delete | Локальний | ❌ Ні | -### Practical Examples +### Практичні приклади -#### Example 1: GitHub MCP Configuration +#### Приклад 1: Конфігурація GitHub MCP -**File:** `.mcp.json` (project scope) or `~/.claude.json` (user scope) +**Файл:** `.mcp.json` (область проєкту) або `~/.claude.json` (область користувача) ```json { @@ -1036,7 +1036,7 @@ sequenceDiagram } ``` -**Available GitHub MCP Tools:** +**Доступні інструменти GitHub MCP:** ~~~~markdown # GitHub MCP Tools @@ -1080,9 +1080,9 @@ Reviewers: @bob, @charlie - `create_commit` - Create new commit ~~~~ -#### Example 2: Database MCP Setup +#### Приклад 2: Налаштування Database MCP -**Configuration:** +**Конфігурація:** ```json { @@ -1098,7 +1098,7 @@ Reviewers: @bob, @charlie } ``` -**Example Usage:** +**Приклад використання:** ```markdown User: Fetch all users with more than 10 orders @@ -1119,9 +1119,9 @@ ORDER BY order_count DESC; - Charlie: 11 orders ``` -#### Example 3: Multi-MCP Workflow +#### Приклад 3: Робочий процес з кількома MCP -**Scenario: Daily Report Generation** +**Сценарій: Генерація щоденного звіту** ```markdown # Daily Report Workflow using Multiple MCPs @@ -1166,9 +1166,9 @@ Final Output: 💰 $12,450 in daily sales ``` -#### Example 4: Filesystem MCP Operations +#### Приклад 4: Операції Filesystem MCP -**Configuration:** +**Конфігурація:** ```json { @@ -1181,18 +1181,18 @@ Final Output: } ``` -**Available Operations:** +**Доступні операції:** -| Operation | Command | Purpose | +| Операція | Команда | Призначення | |-----------|---------|---------| -| List files | `ls ~/projects` | Show directory contents | -| Read file | `cat src/main.ts` | Read file contents | -| Write file | `create docs/api.md` | Create new file | -| Edit file | `edit src/app.ts` | Modify file | -| Search | `grep "async function"` | Search in files | -| Delete | `rm old-file.js` | Delete file | +| Список файлів | `ls ~/projects` | Показати вміст каталогу | +| Читання файлу | `cat src/main.ts` | Прочитати вміст файлу | +| Запис файлу | `create docs/api.md` | Створити новий файл | +| Редагування файлу | `edit src/app.ts` | Змінити файл | +| Пошук | `grep "async function"` | Пошук у файлах | +| Видалення | `rm old-file.js` | Видалити файл | -### MCP vs Memory: Decision Matrix +### MCP проти пам'яті: Матриця рішень ```mermaid graph TD @@ -1209,7 +1209,7 @@ graph TD style D fill:#fff9c4 ``` -### Request/Response Pattern +### Патерн запит/відповідь ```mermaid sequenceDiagram @@ -1229,13 +1229,13 @@ sequenceDiagram --- -## Agent Skills +## Навички агентів -### Overview +### Огляд -Agent Skills are reusable, model-invoked capabilities packaged as folders containing instructions, scripts, and resources. Claude automatically detects and uses relevant skills. +Навички агентів — це повторно використовувані можливості, що викликаються моделлю, упаковані як теки з інструкціями, скриптами та ресурсами. Claude автоматично виявляє та використовує відповідні навички. -### Skill Architecture +### Архітектура навичок ```mermaid graph TB @@ -1253,7 +1253,7 @@ graph TB F --> A ``` -### Skill Loading Process +### Процес завантаження навички ```mermaid sequenceDiagram @@ -1272,16 +1272,16 @@ sequenceDiagram Claude->>User: Generate Excel file ``` -### Skill Types & Locations Table +### Таблиця типів та розташування навичок -| Type | Location | Scope | Shared | Sync | Best For | +| Тип | Розташування | Область | Спільний | Синхронізація | Найкраще для | |------|----------|-------|--------|------|----------| -| Pre-built | Built-in | Global | All users | Auto | Document creation | -| Personal | `~/.claude/skills/` | Individual | No | Manual | Personal automation | -| Project | `.claude/skills/` | Team | Yes | Git | Team standards | -| Plugin | Via plugin install | Varies | Depends | Auto | Integrated features | +| Вбудовані | Built-in | Глобальний | Усі користувачі | Авто | Створення документів | +| Персональні | `~/.claude/skills/` | Індивідуальний | Ні | Вручну | Персональна автоматизація | +| Проєктні | `.claude/skills/` | Команда | Так | Git | Стандарти команди | +| Плагінні | Через встановлення плагіна | Різний | Залежить | Авто | Інтегровані функції | -### Pre-built Skills +### Вбудовані навички ```mermaid graph TB @@ -1306,25 +1306,25 @@ graph TB E --> E2["Fill forms"] ``` -### Bundled Skills +### Комплектні навички -Claude Code now includes 5 bundled skills available out of the box: +Claude Code тепер включає 5 комплектних навичок, доступних одразу: -| Skill | Command | Purpose | +| Навичка | Команда | Призначення | |-------|---------|---------| -| **Simplify** | `/simplify` | Simplify complex code or explanations | -| **Batch** | `/batch` | Run operations across multiple files or items | -| **Debug** | `/debug` | Systematic debugging of issues with root cause analysis | -| **Loop** | `/loop` | Schedule recurring tasks on a timer | -| **Claude API** | `/claude-api` | Interact with the Anthropic API directly | +| **Simplify** | `/simplify` | Спрощення складного коду або пояснень | +| **Batch** | `/batch` | Виконання операцій над кількома файлами або елементами | +| **Debug** | `/debug` | Систематичне налагодження з аналізом кореневої причини | +| **Loop** | `/loop` | Планування повторюваних завдань за таймером | +| **Claude API** | `/claude-api` | Пряма взаємодія з Anthropic API | -These bundled skills are always available and do not require installation or configuration. +Ці комплектні навички завжди доступні і не потребують встановлення або конфігурації. -### Practical Examples +### Практичні приклади -#### Example 1: Custom Code Review Skill +#### Приклад 1: Навичка код-рев'ю -**Directory Structure:** +**Структура каталогу:** ``` ~/.claude/skills/code-review/ @@ -1337,7 +1337,7 @@ These bundled skills are always available and do not require installation or con └── compare-complexity.py ``` -**File:** `~/.claude/skills/code-review/SKILL.md` +**Файл:** `~/.claude/skills/code-review/SKILL.md` ```yaml --- @@ -1832,9 +1832,9 @@ const users = fetchUsersWithPosts(); // 1 query - Props should have TypeScript types ~~~~ -#### Example 2: Brand Voice Skill +#### Приклад 2: Навичка голосу бренду -**Directory Structure:** +**Структура каталогу:** ``` .claude/skills/brand-voice/ @@ -1847,7 +1847,7 @@ const users = fetchUsersWithPosts(); // 1 query └── blog-post-template.md ``` -**File:** `.claude/skills/brand-voice/SKILL.md` +**Файл:** `.claude/skills/brand-voice/SKILL.md` ```yaml --- @@ -1971,9 +1971,9 @@ Educational blog post: "Let's explore how agents improve code review workflows. Here's what we learned..." ``` -#### Example 3: Documentation Generator Skill +#### Приклад 3: Навичка генерації документації -**File:** `.claude/skills/doc-generator/SKILL.md` +**Файл:** `.claude/skills/doc-generator/SKILL.md` ~~~~yaml --- @@ -2115,7 +2115,7 @@ if __name__ == '__main__': markdown = generate_markdown_docs(extractor.endpoints) print(markdown) ~~~~ -### Skill Discovery & Invocation +### Виявлення та виклик навичок ```mermaid graph TD @@ -2131,7 +2131,7 @@ graph TD I --> J["Return Results"] ``` -### Skill vs Other Features +### Навички проти інших функцій ```mermaid graph TB @@ -2157,13 +2157,13 @@ graph TB --- -## Claude Code Plugins +## Плагіни Claude Code -### Overview +### Огляд -Claude Code Plugins are bundled collections of customizations (slash commands, subagents, MCP servers, and hooks) that install with a single command. They represent the highest-level extension mechanism—combining multiple features into cohesive, shareable packages. +Плагіни Claude Code — це комплектні збірки налаштувань (слеш-команди, субагенти, MCP-сервери та хуки), які встановлюються однією командою. Вони представляють найвищий рівень механізму розширення — об'єднують кілька функцій у цілісні пакети, якими можна ділитися. -### Architecture +### Архітектура ```mermaid graph TB @@ -2181,7 +2181,7 @@ graph TB A -->|bundles| F ``` -### Plugin Loading Process +### Процес завантаження плагіна ```mermaid sequenceDiagram @@ -2210,16 +2210,16 @@ sequenceDiagram Tools-->>Claude: Plugin installed ✅ ``` -### Plugin Types & Distribution +### Типи та дистрибуція плагінів -| Type | Scope | Shared | Authority | Examples | +| Тип | Область | Спільний | Авторитет | Приклади | |------|-------|--------|-----------|----------| -| Official | Global | All users | Anthropic | PR Review, Security Guidance | -| Community | Public | All users | Community | DevOps, Data Science | -| Organization | Internal | Team members | Company | Internal standards, tools | -| Personal | Individual | Single user | Developer | Custom workflows | +| Офіційний | Глобальний | Усі користувачі | Anthropic | PR Review, Security Guidance | +| Спільноти | Публічний | Усі користувачі | Спільнота | DevOps, Data Science | +| Організаційний | Внутрішній | Члени команди | Компанія | Внутрішні стандарти, інструменти | +| Персональний | Індивідуальний | Один користувач | Розробник | Користувацькі робочі процеси | -### Plugin Definition Structure +### Структура визначення плагіна ```yaml --- @@ -2256,7 +2256,7 @@ config: --- ``` -### Plugin Structure +### Структура плагіна ``` my-plugin/ @@ -2290,11 +2290,11 @@ my-plugin/ └── plugin.test.js ``` -### Practical Examples +### Практичні приклади -#### Example 1: PR Review Plugin +#### Приклад 1: Плагін код-рев'ю PR -**File:** `.claude-plugin/plugin.json` +**Файл:** `.claude-plugin/plugin.json` ```json { @@ -2308,7 +2308,7 @@ my-plugin/ } ``` -**File:** `commands/review-pr.md` +**Файл:** `commands/review-pr.md` ```markdown --- @@ -2327,7 +2327,7 @@ This command initiates a complete pull request review including: 5. Performance impact assessment ``` -**File:** `agents/security-reviewer.md` +**Файл:** `agents/security-reviewer.md` ```yaml --- @@ -2345,7 +2345,7 @@ Specializes in finding security vulnerabilities: - Secure configuration ``` -**Installation:** +**Встановлення:** ```bash /plugin install pr-review @@ -2358,9 +2358,9 @@ Specializes in finding security vulnerabilities: # ✅ Ready to use! ``` -#### Example 2: DevOps Plugin +#### Приклад 2: Плагін DevOps -**Components:** +**Компоненти:** ``` devops-automation/ @@ -2387,9 +2387,9 @@ devops-automation/ └── health-check.sh ``` -#### Example 3: Documentation Plugin +#### Приклад 3: Плагін документації -**Bundled Components:** +**Комплектні компоненти:** ``` documentation/ @@ -2411,7 +2411,7 @@ documentation/ └── adr-template.md ``` -### Plugin Marketplace +### Маркетплейс плагінів ```mermaid graph TB @@ -2437,7 +2437,7 @@ graph TB D -->|Internal| D3["Compliance"] ``` -### Plugin Installation & Lifecycle +### Встановлення та життєвий цикл плагіна ```mermaid graph LR @@ -2454,33 +2454,33 @@ graph LR J -->|Back| G ``` -### Plugin Features Comparison +### Порівняння функцій плагінів -| Feature | Slash Command | Skill | Subagent | Plugin | +| Функція | Слеш-команда | Навичка | Субагент | Плагін | |---------|---------------|-------|----------|--------| -| **Installation** | Manual copy | Manual copy | Manual config | One command | -| **Setup Time** | 5 minutes | 10 minutes | 15 minutes | 2 minutes | -| **Bundling** | Single file | Single file | Single file | Multiple | -| **Versioning** | Manual | Manual | Manual | Automatic | -| **Team Sharing** | Copy file | Copy file | Copy file | Install ID | -| **Updates** | Manual | Manual | Manual | Auto-available | -| **Dependencies** | None | None | None | May include | -| **Marketplace** | No | No | No | Yes | -| **Distribution** | Repository | Repository | Repository | Marketplace | +| **Встановлення** | Ручне копіювання | Ручне копіювання | Ручна конфігурація | Одна команда | +| **Час налаштування** | 5 хвилин | 10 хвилин | 15 хвилин | 2 хвилини | +| **Комплектність** | Один файл | Один файл | Один файл | Кілька | +| **Версіонування** | Вручну | Вручну | Вручну | Автоматичне | +| **Поширення в команді** | Копіювати файл | Копіювати файл | Копіювати файл | ID встановлення | +| **Оновлення** | Вручну | Вручну | Вручну | Авто-доступне | +| **Залежності** | Немає | Немає | Немає | Можуть бути | +| **Маркетплейс** | Ні | Ні | Ні | Так | +| **Дистрибуція** | Репозиторій | Репозиторій | Репозиторій | Маркетплейс | -### Plugin Use Cases +### Сценарії використання плагінів -| Use Case | Recommendation | Why | +| Сценарій використання | Рекомендація | Чому | |----------|-----------------|-----| -| **Team Onboarding** | ✅ Use Plugin | Instant setup, all configurations | -| **Framework Setup** | ✅ Use Plugin | Bundles framework-specific commands | -| **Enterprise Standards** | ✅ Use Plugin | Central distribution, version control | -| **Quick Task Automation** | ❌ Use Command | Overkill complexity | -| **Single Domain Expertise** | ❌ Use Skill | Too heavy, use skill instead | -| **Specialized Analysis** | ❌ Use Subagent | Create manually or use skill | -| **Live Data Access** | ❌ Use MCP | Standalone, don't bundle | +| **Онбординг команди** | ✅ Використовуйте плагін | Миттєве налаштування, усі конфігурації | +| **Налаштування фреймворку** | ✅ Використовуйте плагін | Комплектує команди, специфічні для фреймворку | +| **Корпоративні стандарти** | ✅ Використовуйте плагін | Централізована дистрибуція, контроль версій | +| **Швидка автоматизація задач** | ❌ Використовуйте команду | Надмірна складність | +| **Одна предметна область** | ❌ Використовуйте навичку | Занадто важкий, краще навичка | +| **Спеціалізований аналіз** | ❌ Використовуйте субагента | Створіть вручну або використовуйте навичку | +| **Доступ до живих даних** | ❌ Використовуйте MCP | Автономний, не комплектуйте | -### When to Create a Plugin +### Коли створювати плагін ```mermaid graph TD @@ -2496,20 +2496,20 @@ graph TD G -->|No| D ``` -### Publishing a Plugin +### Публікація плагіна -**Steps to publish:** +**Кроки для публікації:** -1. Create plugin structure with all components -2. Write `.claude-plugin/plugin.json` manifest -3. Create `README.md` with documentation -4. Test locally with `/plugin install ./my-plugin` -5. Submit to plugin marketplace -6. Get reviewed and approved -7. Published on marketplace -8. Users can install with one command +1. Створіть структуру плагіна з усіма компонентами +2. Напишіть маніфест `.claude-plugin/plugin.json` +3. Створіть `README.md` з документацією +4. Протестуйте локально за допомогою `/plugin install ./my-plugin` +5. Надішліть на маркетплейс плагінів +6. Пройдіть перевірку та затвердження +7. Опубліковано на маркетплейсі +8. Користувачі можуть встановити однією командою -**Example submission:** +**Приклад подачі:** ~~~~markdown # PR Review Plugin @@ -2548,17 +2548,17 @@ Complete PR review workflow with security, testing, and documentation checks. - CodeQL (optional) ~~~~ -### Plugin vs Manual Configuration +### Плагін проти ручної конфігурації -**Manual Setup (2+ hours):** -- Install slash commands one by one -- Create subagents individually -- Configure MCPs separately -- Set up hooks manually -- Document everything -- Share with team (hope they configure correctly) +**Ручне налаштування (2+ години):** +- Встановити слеш-команди одну за одною +- Створити субагентів окремо +- Налаштувати MCP окремо +- Налаштувати хуки вручну +- Задокументувати все +- Поширити в команді (сподіваючись на правильну конфігурацію) -**With Plugin (2 minutes):** +**З плагіном (2 хвилини):** ```bash /plugin install pr-review # ✅ Everything installed and configured @@ -2568,19 +2568,19 @@ Complete PR review workflow with security, testing, and documentation checks. --- -## Comparison & Integration +## Порівняння та інтеграція -### Feature Comparison Matrix +### Матриця порівняння функцій -| Feature | Invocation | Persistence | Scope | Use Case | +| Функція | Виклик | Постійність | Область | Сценарій використання | |---------|-----------|------------|-------|----------| -| **Slash Commands** | Manual (`/cmd`) | Session only | Single command | Quick shortcuts | -| **Subagents** | Auto-delegated | Isolated context | Specialized task | Task distribution | -| **Memory** | Auto-loaded | Cross-session | User/team context | Long-term learning | -| **MCP Protocol** | Auto-queried | Real-time external | Live data access | Dynamic information | -| **Skills** | Auto-invoked | Filesystem-based | Reusable expertise | Automated workflows | +| **Слеш-команди** | Ручний (`/cmd`) | Лише сесія | Одна команда | Швидкі ярлики | +| **Субагенти** | Авто-делеговані | Ізольований контекст | Спеціалізоване завдання | Розподіл завдань | +| **Пам'ять** | Авто-завантажена | Між сесіями | Контекст користувача/команди | Довгострокове навчання | +| **Протокол MCP** | Авто-запити | Реальний час, зовнішній | Доступ до живих даних | Динамічна інформація | +| **Навички** | Авто-викликані | На основі файлової системи | Повторно використовувана експертиза | Автоматизовані робочі процеси | -### Interaction Timeline +### Хронологія взаємодії ```mermaid graph LR @@ -2601,9 +2601,9 @@ graph LR J -->|Uses| B ``` -### Practical Integration Example: Customer Support Automation +### Практичний приклад інтеграції: Автоматизація підтримки клієнтів -#### Architecture +#### Архітектура ```mermaid graph TB @@ -2629,7 +2629,7 @@ graph TB Output -->|Send| Reply["Customer Reply"] ``` -#### Request Flow +#### Потік запитів ```markdown ## Customer Support Request Flow @@ -2682,7 +2682,7 @@ Customer receives: - Link to related issues ``` -### Complete Feature Orchestration +### Повна оркестрація функцій ```mermaid sequenceDiagram @@ -2709,7 +2709,7 @@ sequenceDiagram Claude->>User: Complete system delivered ``` -### When to Use Each Feature +### Коли використовувати кожну функцію ```mermaid graph TD @@ -2728,7 +2728,7 @@ graph TD G --> G1["✅ Auto-invoked expertise"] ``` -### Selection Decision Tree +### Дерево рішень для вибору ```mermaid graph TD @@ -2753,94 +2753,94 @@ graph TD --- -## Summary Table +## Зведена таблиця -| Aspect | Slash Commands | Subagents | Memory | MCP | Skills | Plugins | +| Аспект | Слеш-команди | Субагенти | Пам'ять | MCP | Навички | Плагіни | |--------|---|---|---|---|---|---| -| **Setup Difficulty** | Easy | Medium | Easy | Medium | Medium | Easy | -| **Learning Curve** | Low | Medium | Low | Medium | Medium | Low | -| **Team Benefit** | High | High | Medium | High | High | Very High | -| **Automation Level** | Low | High | Medium | High | High | Very High | -| **Context Management** | Single-session | Isolated | Persistent | Real-time | Persistent | All features | -| **Maintenance Burden** | Low | Medium | Low | Medium | Medium | Low | -| **Scalability** | Good | Excellent | Good | Excellent | Excellent | Excellent | -| **Shareability** | Fair | Fair | Good | Good | Good | Excellent | -| **Versioning** | Manual | Manual | Manual | Manual | Manual | Automatic | -| **Installation** | Manual copy | Manual config | N/A | Manual config | Manual copy | One command | +| **Складність налаштування** | Легко | Середньо | Легко | Середньо | Середньо | Легко | +| **Крива навчання** | Низька | Середня | Низька | Середня | Середня | Низька | +| **Користь для команди** | Висока | Висока | Середня | Висока | Висока | Дуже висока | +| **Рівень автоматизації** | Низький | Високий | Середній | Високий | Високий | Дуже високий | +| **Управління контекстом** | Одна сесія | Ізольований | Постійний | Реальний час | Постійний | Усі функції | +| **Навантаження з обслуговування** | Низьке | Середнє | Низьке | Середнє | Середнє | Низьке | +| **Масштабованість** | Добра | Відмінна | Добра | Відмінна | Відмінна | Відмінна | +| **Можливість поширення** | Задовільна | Задовільна | Добра | Добра | Добра | Відмінна | +| **Версіонування** | Вручну | Вручну | Вручну | Вручну | Вручну | Автоматичне | +| **Встановлення** | Ручне копіювання | Ручна конфігурація | Н/Д | Ручна конфігурація | Ручне копіювання | Одна команда | --- -## Quick Start Guide +## Короткий посібник для початку -### Week 1: Start Simple -- Create 2-3 slash commands for common tasks -- Enable Memory in Settings -- Document team standards in CLAUDE.md +### Тиждень 1: Почніть просто +- Створіть 2-3 слеш-команди для типових завдань +- Увімкніть пам'ять у налаштуваннях +- Задокументуйте стандарти команди в CLAUDE.md -### Week 2: Add Real-time Access -- Set up 1 MCP (GitHub or Database) -- Use `/mcp` to configure -- Query live data in your workflows +### Тиждень 2: Додайте доступ у реальному часі +- Налаштуйте 1 MCP (GitHub або Database) +- Використовуйте `/mcp` для конфігурації +- Запитуйте живі дані у ваших робочих процесах -### Week 3: Distribute Work -- Create first Subagent for specific role -- Use `/agents` command -- Test delegation with simple task +### Тиждень 3: Розподіліть роботу +- Створіть першого субагента для конкретної ролі +- Використовуйте команду `/agents` +- Протестуйте делегування з простим завданням -### Week 4: Automate Everything -- Create first Skill for repeated automation -- Use Skill marketplace or build custom -- Combine all features for full workflow +### Тиждень 4: Автоматизуйте все +- Створіть першу навичку для повторюваної автоматизації +- Використовуйте маркетплейс навичок або створіть власну +- Об'єднайте усі функції для повного робочого процесу -### Ongoing -- Review and update Memory monthly -- Add new Skills as patterns emerge -- Optimize MCP queries -- Refine Subagent prompts +### Постійно +- Переглядайте та оновлюйте пам'ять щомісяця +- Додавайте нові навички за потребою +- Оптимізуйте MCP-запити +- Вдосконалюйте промпти субагентів --- -## Hooks +## Хуки -### Overview +### Огляд -Hooks are event-driven shell commands that execute automatically in response to Claude Code events. They enable automation, validation, and custom workflows without manual intervention. +Хуки — це shell-команди на основі подій, які виконуються автоматично у відповідь на події Claude Code. Вони забезпечують автоматизацію, валідацію та користувацькі робочі процеси без ручного втручання. -### Hook Events +### Події хуків -Claude Code supports **25 hook events** across four hook types (command, http, prompt, agent): +Claude Code підтримує **25 подій хуків** у чотирьох типах хуків (command, http, prompt, agent): -| Hook Event | Trigger | Use Cases | +| Подія хука | Тригер | Сценарії використання | |------------|---------|-----------| -| **SessionStart** | Session begins/resumes/clear/compact | Environment setup, initialization | -| **InstructionsLoaded** | CLAUDE.md or rules file loaded | Validation, transformation, augmentation | -| **UserPromptSubmit** | User submits prompt | Input validation, prompt filtering | -| **PreToolUse** | Before any tool runs | Validation, approval gates, logging | -| **PermissionRequest** | Permission dialog shown | Auto-approve/deny flows | -| **PostToolUse** | After tool succeeds | Auto-formatting, notifications, cleanup | -| **PostToolUseFailure** | Tool execution fails | Error handling, logging | -| **Notification** | Notification sent | Alerting, external integrations | -| **SubagentStart** | Subagent spawned | Context injection, initialization | -| **SubagentStop** | Subagent finishes | Result validation, logging | -| **Stop** | Claude finishes responding | Summary generation, cleanup tasks | -| **StopFailure** | API error ends turn | Error recovery, logging | -| **TeammateIdle** | Agent team teammate idle | Work distribution, coordination | -| **TaskCompleted** | Task marked complete | Post-task processing | -| **TaskCreated** | Task created via TaskCreate | Task tracking, logging | -| **ConfigChange** | Config file changes | Validation, propagation | -| **CwdChanged** | Working directory changes | Directory-specific setup | -| **FileChanged** | Watched file changes | File monitoring, rebuild triggers | -| **PreCompact** | Before context compaction | State preservation | -| **PostCompact** | After compaction completes | Post-compact actions | -| **WorktreeCreate** | Worktree being created | Environment setup, dependency install | -| **WorktreeRemove** | Worktree being removed | Cleanup, resource deallocation | -| **Elicitation** | MCP server requests user input | Input validation | -| **ElicitationResult** | User responds to elicitation | Response processing | -| **SessionEnd** | Session terminates | Cleanup, final logging | +| **SessionStart** | Початок/відновлення/очищення/ущільнення сесії | Налаштування середовища, ініціалізація | +| **InstructionsLoaded** | Завантажено CLAUDE.md або файл правил | Валідація, трансформація, доповнення | +| **UserPromptSubmit** | Користувач надсилає промпт | Валідація вводу, фільтрація промптів | +| **PreToolUse** | Перед запуском будь-якого інструменту | Валідація, шлюзи затвердження, логування | +| **PermissionRequest** | Показано діалог дозволу | Авто-затвердження/відхилення | +| **PostToolUse** | Після успішного виконання інструменту | Авто-форматування, сповіщення, очищення | +| **PostToolUseFailure** | Помилка виконання інструменту | Обробка помилок, логування | +| **Notification** | Надіслано сповіщення | Алертинг, зовнішні інтеграції | +| **SubagentStart** | Створено субагента | Ін'єкція контексту, ініціалізація | +| **SubagentStop** | Субагент завершив роботу | Валідація результату, логування | +| **Stop** | Claude завершив відповідь | Генерація підсумку, завдання очищення | +| **StopFailure** | Помилка API завершує хід | Відновлення після помилки, логування | +| **TeammateIdle** | Тімейт у команді агентів без роботи | Розподіл роботи, координація | +| **TaskCompleted** | Завдання позначено як виконане | Пост-обробка завдання | +| **TaskCreated** | Завдання створено через TaskCreate | Відстеження завдань, логування | +| **ConfigChange** | Зміна конфігураційного файлу | Валідація, поширення | +| **CwdChanged** | Зміна робочого каталогу | Налаштування для конкретного каталогу | +| **FileChanged** | Зміна відстежуваного файлу | Моніторинг файлів, тригери перебудови | +| **PreCompact** | Перед ущільненням контексту | Збереження стану | +| **PostCompact** | Після завершення ущільнення | Дії після ущільнення | +| **WorktreeCreate** | Створення worktree | Налаштування середовища, встановлення залежностей | +| **WorktreeRemove** | Видалення worktree | Очищення, звільнення ресурсів | +| **Elicitation** | MCP-сервер запитує введення користувача | Валідація вводу | +| **ElicitationResult** | Користувач відповідає на запит | Обробка відповіді | +| **SessionEnd** | Завершення сесії | Очищення, фінальне логування | -### Common Hooks +### Типові хуки -Hooks are configured in `~/.claude/settings.json` (user-level) or `.claude/settings.json` (project-level): +Хуки налаштовуються у `~/.claude/settings.json` (рівень користувача) або `.claude/settings.json` (рівень проєкту): ```json { @@ -2871,47 +2871,47 @@ Hooks are configured in `~/.claude/settings.json` (user-level) or `.claude/setti } ``` -### Hook Environment Variables +### Змінні середовища хуків -- `$CLAUDE_FILE_PATH` - Path to file being edited/written -- `$CLAUDE_TOOL_NAME` - Name of tool being used -- `$CLAUDE_SESSION_ID` - Current session identifier -- `$CLAUDE_PROJECT_DIR` - Project directory path +- `$CLAUDE_FILE_PATH` — Шлях до файлу, що редагується/записується +- `$CLAUDE_TOOL_NAME` — Назва інструменту, що використовується +- `$CLAUDE_SESSION_ID` — Ідентифікатор поточної сесії +- `$CLAUDE_PROJECT_DIR` — Шлях до каталогу проєкту -### Best Practices +### Найкращі практики -✅ **Do:** -- Keep hooks fast (< 1 second) -- Use hooks for validation and automation -- Handle errors gracefully -- Use absolute paths +✅ **Рекомендовано:** +- Тримайте хуки швидкими (< 1 секунди) +- Використовуйте хуки для валідації та автоматизації +- Обробляйте помилки коректно +- Використовуйте абсолютні шляхи -❌ **Don't:** -- Make hooks interactive -- Use hooks for long-running tasks -- Hardcode credentials +❌ **Не рекомендовано:** +- Робити хуки інтерактивними +- Використовувати хуки для тривалих завдань +- Жорстко прописувати облікові дані -**See**: [06-hooks/](06-hooks/) for detailed examples +**Дивіться**: [06-hooks/](06-hooks/) для детальних прикладів --- -## Checkpoints and Rewind +## Контрольні точки та відкат -### Overview +### Огляд -Checkpoints allow you to save conversation state and rewind to previous points, enabling safe experimentation and exploration of multiple approaches. +Контрольні точки дозволяють зберігати стан розмови та повертатися до попередніх моментів, забезпечуючи безпечне експериментування та дослідження різних підходів. -### Key Concepts +### Ключові концепції -| Concept | Description | +| Концепція | Опис | |---------|-------------| -| **Checkpoint** | Snapshot of conversation state including messages, files, and context | -| **Rewind** | Return to a previous checkpoint, discarding subsequent changes | -| **Branch Point** | Checkpoint from which multiple approaches are explored | +| **Контрольна точка** | Знімок стану розмови, включаючи повідомлення, файли та контекст | +| **Відкат** | Повернення до попередньої контрольної точки з відкиданням подальших змін | +| **Точка розгалуження** | Контрольна точка, від якої досліджуються кілька підходів | -### Accessing Checkpoints +### Доступ до контрольних точок -Checkpoints are created automatically with every user prompt. To rewind: +Контрольні точки створюються автоматично з кожним промптом користувача. Для відкату: ```bash # Press Esc twice to open the checkpoint browser @@ -2921,23 +2921,23 @@ Esc + Esc /rewind ``` -When you select a checkpoint, you choose from five options: -1. **Restore code and conversation** -- Revert both to that point -2. **Restore conversation** -- Rewind messages, keep current code -3. **Restore code** -- Revert files, keep conversation -4. **Summarize from here** -- Compress conversation into a summary -5. **Never mind** -- Cancel +При виборі контрольної точки доступні п'ять варіантів: +1. **Відновити код і розмову** — Повернути обидва до цього моменту +2. **Відновити розмову** — Повернути повідомлення, залишити поточний код +3. **Відновити код** — Повернути файли, залишити розмову +4. **Підсумувати звідси** — Стиснути розмову у підсумок +5. **Скасувати** — Відмінити -### Use Cases +### Сценарії використання -| Scenario | Workflow | +| Сценарій | Робочий процес | |----------|----------| -| **Exploring Approaches** | Save → Try A → Save → Rewind → Try B → Compare | -| **Safe Refactoring** | Save → Refactor → Test → If fail: Rewind | -| **A/B Testing** | Save → Design A → Save → Rewind → Design B → Compare | -| **Mistake Recovery** | Notice issue → Rewind to last good state | +| **Дослідження підходів** | Зберегти → Спробувати A → Зберегти → Відкат → Спробувати B → Порівняти | +| **Безпечний рефакторинг** | Зберегти → Рефакторинг → Тест → Якщо невдача: Відкат | +| **A/B тестування** | Зберегти → Дизайн A → Зберегти → Відкат → Дизайн B → Порівняти | +| **Відновлення після помилки** | Помітити проблему → Відкат до останнього робочого стану | -### Configuration +### Конфігурація ```json { @@ -2945,34 +2945,34 @@ When you select a checkpoint, you choose from five options: } ``` -**See**: [08-checkpoints/](08-checkpoints/) for detailed examples +**Дивіться**: [08-checkpoints/](08-checkpoints/) для детальних прикладів --- -## Advanced Features +## Просунуті функції -### Planning Mode +### Режим планування -Create detailed implementation plans before coding. +Створюйте детальні плани реалізації перед кодуванням. -**Activation:** +**Активація:** ```bash /plan Implement user authentication system ``` -**Benefits:** -- Clear roadmap with time estimates -- Risk assessment -- Systematic task breakdown -- Opportunity for review and modification +**Переваги:** +- Чіткий план з оцінкою часу +- Оцінка ризиків +- Систематичне розбиття на завдання +- Можливість перегляду та модифікації -### Extended Thinking +### Розширене мислення -Deep reasoning for complex problems. +Глибокий аналіз для складних проблем. -**Activation:** -- Toggle with `Alt+T` (or `Option+T` on macOS) during a session -- Set `MAX_THINKING_TOKENS` environment variable for programmatic control +**Активація:** +- Перемикання `Alt+T` (або `Option+T` на macOS) під час сесії +- Встановіть змінну середовища `MAX_THINKING_TOKENS` для програмного контролю ```bash # Enable extended thinking via environment variable @@ -2980,17 +2980,17 @@ export MAX_THINKING_TOKENS=50000 claude -p "Should we use microservices or monolith?" ``` -**Benefits:** -- Thorough analysis of trade-offs -- Better architectural decisions -- Consideration of edge cases -- Systematic evaluation +**Переваги:** +- Ретельний аналіз компромісів +- Кращі архітектурні рішення +- Врахування крайніх випадків +- Систематична оцінка -### Background Tasks +### Фонові завдання -Run long operations without blocking the conversation. +Запускайте тривалі операції без блокування розмови. -**Usage:** +**Використання:** ```bash User: Run tests in background @@ -3002,20 +3002,20 @@ Claude: Started task bg-1234 /task cancel bg-1234 # Cancel task ``` -### Permission Modes +### Режими дозволів -Control what Claude can do. +Контролюйте, що Claude може робити. -| Mode | Description | Use Case | +| Режим | Опис | Сценарій використання | |------|-------------|----------| -| **default** | Standard permissions with prompts for sensitive actions | General development | -| **acceptEdits** | Automatically accept file edits without confirmation | Trusted editing workflows | -| **plan** | Analysis and planning only, no file modifications | Code review, architecture planning | -| **auto** | Automatically approve safe actions, prompt only for risky ones | Balanced autonomy with safety | -| **dontAsk** | Execute all actions without confirmation prompts | Experienced users, automation | -| **bypassPermissions** | Full unrestricted access, no safety checks | CI/CD pipelines, trusted scripts | +| **default** | Стандартні дозволи з запитами для чутливих дій | Загальна розробка | +| **acceptEdits** | Автоматично приймати редагування файлів без підтвердження | Довірені робочі процеси редагування | +| **plan** | Лише аналіз і планування, без модифікації файлів | Код-рев'ю, планування архітектури | +| **auto** | Автоматично затверджувати безпечні дії, запитувати лише ризиковані | Збалансована автономія з безпекою | +| **dontAsk** | Виконувати всі дії без запитів підтвердження | Досвідчені користувачі, автоматизація | +| **bypassPermissions** | Повний необмежений доступ, без перевірок безпеки | CI/CD-конвеєри, довірені скрипти | -**Usage:** +**Використання:** ```bash claude --permission-mode plan # Read-only analysis claude --permission-mode acceptEdits # Auto-accept edits @@ -3023,11 +3023,11 @@ claude --permission-mode auto # Auto-approve safe actions claude --permission-mode dontAsk # No confirmation prompts ``` -### Headless Mode (Print Mode) +### Headless-режим (режим друку) -Run Claude Code without interactive input for automation and CI/CD using the `-p` (print) flag. +Запускайте Claude Code без інтерактивного введення для автоматизації та CI/CD за допомогою прапорця `-p` (print). -**Usage:** +**Використання:** ```bash # Run specific task claude -p "Run all tests" @@ -3043,28 +3043,28 @@ cat error.log | claude -p "explain this error" claude -p --output-format json "list all functions in src/" ``` -### Scheduled Tasks +### Заплановані завдання -Run tasks on a repeating schedule using the `/loop` command. +Запускайте завдання за розкладом за допомогою команди `/loop`. -**Usage:** +**Використання:** ```bash /loop every 30m "Run tests and report failures" /loop every 2h "Check for dependency updates" /loop every 1d "Generate daily summary of code changes" ``` -Scheduled tasks run in the background and report results when complete. They are useful for continuous monitoring, periodic checks, and automated maintenance workflows. +Заплановані завдання виконуються у фоновому режимі та повідомляють про результати після завершення. Вони корисні для безперервного моніторингу, періодичних перевірок та автоматизованих робочих процесів обслуговування. -### Chrome Integration +### Інтеграція з Chrome -Claude Code can integrate with the Chrome browser for web automation tasks. This enables capabilities like navigating web pages, filling forms, taking screenshots, and extracting data from websites directly within your development workflow. +Claude Code може інтегруватися з браузером Chrome для завдань веб-автоматизації. Це забезпечує можливості навігації по веб-сторінках, заповнення форм, створення знімків екрану та витягування даних з вебсайтів безпосередньо у вашому робочому процесі розробки. -### Session Management +### Управління сесіями -Manage multiple work sessions. +Керуйте кількома робочими сесіями. -**Commands:** +**Команди:** ```bash /resume # Resume a previous conversation /rename "Feature" # Name the current session @@ -3073,15 +3073,15 @@ claude -c # Continue most recent conversation claude -r "Feature" # Resume session by name/ID ``` -### Interactive Features +### Інтерактивні функції -**Keyboard Shortcuts:** -- `Ctrl + R` - Search command history -- `Tab` - Autocomplete -- `↑ / ↓` - Command history -- `Ctrl + L` - Clear screen +**Клавіатурні скорочення:** +- `Ctrl + R` — Пошук в історії команд +- `Tab` — Автодоповнення +- `↑ / ↓` — Історія команд +- `Ctrl + L` — Очистити екран -**Multi-line Input:** +**Багаторядковий ввід:** ```bash User: \ > Long complex prompt @@ -3089,9 +3089,9 @@ User: \ > \end ``` -### Configuration +### Конфігурація -Complete configuration example: +Повний приклад конфігурації: ```json { @@ -3113,22 +3113,22 @@ Complete configuration example: } ``` -**See**: [09-advanced-features/](09-advanced-features/) for comprehensive guide +**Дивіться**: [09-advanced-features/](09-advanced-features/) для повного посібника --- -## Resources +## Ресурси -- [Claude Code Documentation](https://code.claude.com/docs/en/overview) -- [Anthropic Documentation](https://docs.anthropic.com) -- [MCP GitHub Servers](https://github.com/modelcontextprotocol/servers) -- [Anthropic Cookbook](https://github.com/anthropics/anthropic-cookbook) +- [Документація Claude Code](https://code.claude.com/docs/en/overview) +- [Документація Anthropic](https://docs.anthropic.com) +- [MCP-сервери на GitHub](https://github.com/modelcontextprotocol/servers) +- [Кулінарна книга Anthropic](https://github.com/anthropics/anthropic-cookbook) --- -*Last updated: April 2026* -*For Claude Haiku 4.5, Sonnet 4.6, and Opus 4.6* -*Now includes: Hooks, Checkpoints, Planning Mode, Extended Thinking, Background Tasks, Permission Modes (6 modes), Headless Mode, Session Management, Auto Memory, Agent Teams, Scheduled Tasks, Chrome Integration, Channels, Voice Dictation, and Bundled Skills* +*Останнє оновлення: квітень 2026* +*Для Claude Haiku 4.5, Sonnet 4.6 та Opus 4.6* +*Тепер включає: хуки, контрольні точки, режим планування, розширене мислення, фонові завдання, режими дозволів (6 режимів), headless-режим, управління сесіями, авто-пам'ять, команди агентів, заплановані завдання, інтеграцію з Chrome, канали, голосовий ввід та комплектні навички* --- **Last Updated**: April 9, 2026 From f6d73e2659947b45f7c9994aa23d33c3ecaebe8c Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 08:54:06 +0300 Subject: [PATCH 18/20] fix(uk): replace stub README with full translation, fix broken anchors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 3KB stub README with full 31KB translation matching original structure - Fix apostrophe anchor mismatch in 04-subagents (U+02BC vs U+0027) - Fix duplicate heading in 06-hooks (Prompt-хуки → Хуки на основі промптів) Ref: luongnv89/claude-howto#63 --- uk/04-subagents/README.md | 4 +- uk/06-hooks/README.md | 4 +- uk/README.md | 717 ++++++++++++++++++++++++++++++++++---- 3 files changed, 654 insertions(+), 71 deletions(-) diff --git a/uk/04-subagents/README.md b/uk/04-subagents/README.md index 6786dc1..991a16b 100644 --- a/uk/04-subagents/README.md +++ b/uk/04-subagents/README.md @@ -22,7 +22,7 @@ 7. [Використання субагентів](#використання-субагентів) 8. [Відновлювані агенти](#відновлювані-агенти) 9. [Ланцюжки субагентів](#ланцюжки-субагентів) -10. [Постійна пам'ять для субагентів](#постійна-памʼять-для-субагентів) +10. [Постійна пам'ять для субагентів](#постійна-память-для-субагентів) 11. [Фонові субагенти](#фонові-субагенти) 12. [Ізоляція через Worktree](#ізоляція-через-worktree) 13. [Обмеження створюваних субагентів](#обмеження-створюваних-субагентів) @@ -35,7 +35,7 @@ 20. [Найкращі практики](#найкращі-практики) 21. [Приклади субагентів у цій папці](#приклади-субагентів-у-цій-папці) 22. [Інструкції з встановлення](#інструкції-з-встановлення) -23. [Пов'язані концепції](#повʼязані-концепції) +23. [Пов'язані концепції](#повязані-концепції) --- diff --git a/uk/06-hooks/README.md b/uk/06-hooks/README.md index 44078d8..e94e488 100644 --- a/uk/06-hooks/README.md +++ b/uk/06-hooks/README.md @@ -133,7 +133,7 @@ Claude Code підтримує чотири типи хуків: } ``` -LLM оцінює промпт і повертає структуроване рішення (деталі див. у [Prompt-хуки](#prompt-хуки-1)). +LLM оцінює промпт і повертає структуроване рішення (деталі див. у [Хуки на основі промптів](#хуки-на-основі-промптів)). ### Agent-хуки @@ -504,7 +504,7 @@ hooks: | `${CLAUDE_PLUGIN_DATA}` | Хуки плагінів | Шлях до каталогу даних плагіна | | `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` | Хуки SessionEnd | Налаштовуваний таймаут у мілісекундах для хуків SessionEnd (перевизначає стандартний) | -## Prompt-хуки +## Хуки на основі промптів Для подій `Stop` та `SubagentStop` можна використовувати оцінку на основі LLM: diff --git a/uk/README.md b/uk/README.md index c622b73..eb3adb1 100644 --- a/uk/README.md +++ b/uk/README.md @@ -1,79 +1,662 @@ - + -# Посібник Claude Code + + + Claude How To + 🌐 **Language / Мова:** [English](../README.md) | [Tiếng Việt](../vi/README.md) | [中文](../zh/README.md) | [Українська](README.md) -> **Опануй Claude Code за вихідні** +# Опануй Claude Code за вихідні -Це українська версія документації [Claude Code How-To Guide](../README.md). +Від простого введення `claude` до оркестрації агентів, хуків, навичок та MCP-серверів — з візуальними туторіалами, готовими шаблонами та керованим навчальним шляхом. -## 📖 Про що це - -Цей посібник допоможе вам: - -- Зрозуміти та ефективно використовувати Claude Code -- Автоматизувати завдання з розробки програмного забезпечення -- Інтегрувати Claude Code у ваш щоденний робочий процес - -## 🚀 Швидкий старт - -### Вимоги - -- Встановлений Claude Code -- Базові знання роботи з терміналом -- Базові знання програмування - -### Встановлення - -```bash -# Клонувати репозиторій -git clone https://github.com/luongnv89/claude-howto.git -cd claude-howto - -# Скопіювати слеш-команди до вашого проекту -mkdir -p .claude/commands -cp 01-slash-commands/*.md .claude/commands/ -``` - -## 📚 Структура документації - -Документація поділена на 10 модулів у порядку вивчення: - -1. **[01 — Слеш-команди](01-slash-commands/)** — Ярлики для підвищення продуктивності -2. **[02 — Пам'ять](02-memory/)** — Збереження контексту між сесіями -3. **[03 — Навички (Skills)](03-skills/)** — Багаторазові можливості -4. **[04 — Субагенти](04-subagents/)** — Спеціалізовані AI-помічники -5. **[05 — MCP](05-mcp/)** — Model Context Protocol -6. **[06 — Хуки](06-hooks/)** — Автоматизація на основі подій -7. **[07 — Плагіни](07-plugins/)** — Пакетні розширення -8. **[08 — Контрольні точки](08-checkpoints/)** — Знімки сесій -9. **[09 — Розширені функції](09-advanced-features/)** — Планування, мислення, фонові завдання -10. **[10 — CLI](10-cli/)** — Довідник командного рядка - -## 🔗 Посилання - -- [Англійська версія](../README.md) -- [Офіційна документація Claude Code](https://code.claude.com/docs) -- [GitHub-репозиторій](https://github.com/luongnv89/claude-howto) - -## 🤝 Як долучитися - -Див. [CONTRIBUTING.md](../CONTRIBUTING.md) для деталей. - -## 📝 Примітки до перекладу - -Див. [TRANSLATION_NOTES.md](TRANSLATION_NOTES.md) для: - -- Глосарію технічних термінів -- Правил стилю перекладу -- Правил роботи з кодом та командами +**[Почни за 15 хвилин](#почни-за-15-хвилин)** | **[Визнач свій рівень](#не-знаєш-з-чого-почати)** | **[Каталог функцій](CATALOG.md)** --- -**Переклад у процесі.** Див. [TRANSLATION_QUEUE.md](TRANSLATION_QUEUE.md) для відстеження прогресу. +## Зміст -**Останнє оновлення:** 2026-04-09 -**Мова:** Українська (uk-UA) +- [Проблема](#проблема) +- [Як Claude How To вирішує це](#як-claude-how-to-вирішує-це) +- [Як це працює](#як-це-працює) +- [Не знаєш з чого почати?](#не-знаєш-з-чого-почати) +- [Почни за 15 хвилин](#почни-за-15-хвилин) +- [Що можна побудувати?](#що-можна-побудувати) +- [FAQ](#faq) +- [Внесок](#внесок) +- [Ліцензія](#ліцензія) + +--- + +## Проблема + +Ви встановили Claude Code. Виконали кілька промптів. Що далі? + +- **Офіційна документація описує функції — але не показує як їх комбінувати.** Ви знаєте, що слеш-команди існують, але не знаєте як поєднати їх з хуками, пам'яттю та субагентами в робочий процес, що реально економить години. +- **Немає чіткого навчального шляху.** Чи вивчати MCP перед хуками? Навички перед субагентами? В результаті ви переглядаєте все і не опановуєте нічого. +- **Приклади занадто базові.** "Hello world" слеш-команда не допоможе побудувати продакшен-пайплайн код-рев'ю, який використовує пам'ять, делегує спеціалізованим агентам та автоматично запускає перевірки безпеки. + +Ви використовуєте лише 10% потужності Claude Code — і не знаєте, чого не знаєте. + +--- + +## Як Claude How To вирішує це + +Це не черговий довідник функцій. Це **структурований, візуальний, заснований на прикладах довідник**, що навчає використовувати кожну функцію Claude Code з реальними шаблонами, які можна скопіювати у ваш проєкт вже сьогодні. + +| | Офіційна документація | Цей довідник | +|--|----------------------|-------------| +| **Формат** | Довідкова документація | Візуальні туторіали з Mermaid-діаграмами | +| **Глибина** | Опис функцій | Як працює під капотом | +| **Приклади** | Базові фрагменти | Готові до продакшену шаблони для негайного використання | +| **Структура** | Організовано за функціями | Прогресивний навчальний шлях (від початківця до просунутого) | +| **Онбординг** | Самостійне вивчення | Керована дорожня карта з оцінками часу | +| **Самооцінка** | Відсутня | Інтерактивні тести для пошуку прогалин та побудови персоналізованого шляху | + +### Що ви отримаєте: + +- **10 навчальних модулів**, що охоплюють кожну функцію Claude Code — від слеш-команд до кастомних команд агентів +- **Готові конфігурації** — слеш-команди, шаблони CLAUDE.md, скрипти хуків, конфіги MCP, визначення субагентів та повні пакети плагінів +- **Mermaid-діаграми**, що показують як кожна функція працює всередині, щоб ви розуміли *чому*, а не лише *як* +- **Керований навчальний шлях**, що проведе від початківця до досвідченого користувача за 11-13 годин +- **Вбудована самооцінка** — запустіть `/self-assessment` або `/lesson-quiz hooks` прямо у Claude Code для виявлення прогалин + +**[Почати навчальний шлях ->](LEARNING-ROADMAP.md)** + +--- + +## Як це працює + +### 1. Визначте свій рівень + +Пройдіть [тест самооцінки](LEARNING-ROADMAP.md#-визначте-свій-рівень) або запустіть `/self-assessment` у Claude Code. Отримайте персоналізовану дорожню карту на основі того, що ви вже знаєте. + +### 2. Слідуйте керованому шляху + +Проходьте 10 модулів по порядку — кожен будує на попередньому. Копіюйте шаблони безпосередньо у свій проєкт під час навчання. + +### 3. Комбінуйте функції в робочі процеси + +Справжня потужність — у комбінуванні функцій. Навчіться поєднувати слеш-команди + пам'ять + субагенти + хуки в автоматизовані пайплайни для код-рев'ю, розгортань та генерації документації. + +### 4. Перевірте розуміння + +Запустіть `/lesson-quiz [тема]` після кожного модуля. Тест точно вказує, що ви пропустили, щоб швидко заповнити прогалини. + +**[Почни за 15 хвилин](#почни-за-15-хвилин)** + +--- + +## Не знаєш з чого почати? + +Пройдіть самооцінку або оберіть свій рівень: + +| Рівень | Ви вмієте... | Почніть тут | Час | +|--------|-------------|-------------|-----| +| **Початківець** | Запустити Claude Code та спілкуватись | [Слеш-команди](01-slash-commands/) | ~2.5 години | +| **Середній** | Використовувати CLAUDE.md та кастомні команди | [Навички](03-skills/) | ~3.5 години | +| **Просунутий** | Конфігурувати MCP-сервери та хуки | [Просунуті функції](09-advanced-features/) | ~5 годин | + +**Повний навчальний шлях з усіма 10 модулями:** + +| Порядок | Модуль | Рівень | Час | +|---------|--------|--------|-----| +| 1 | [Слеш-команди](01-slash-commands/) | Початківець | 30 хв | +| 2 | [Пам'ять](02-memory/) | Початківець+ | 45 хв | +| 3 | [Контрольні точки](08-checkpoints/) | Середній | 45 хв | +| 4 | [Основи CLI](10-cli/) | Початківець+ | 30 хв | +| 5 | [Навички](03-skills/) | Середній | 1 год | +| 6 | [Хуки](06-hooks/) | Середній | 1 год | +| 7 | [MCP](05-mcp/) | Середній+ | 1 год | +| 8 | [Субагенти](04-subagents/) | Середній+ | 1.5 год | +| 9 | [Просунуті функції](09-advanced-features/) | Просунутий | 2-3 год | +| 10 | [Плагіни](07-plugins/) | Просунутий | 2 год | + +**[Повний навчальний план ->](LEARNING-ROADMAP.md)** + +--- + +## Почни за 15 хвилин + +```bash +# 1. Клонувати довідник +git clone https://github.com/luongnv89/claude-howto.git +cd claude-howto + +# 2. Скопіювати першу слеш-команду +mkdir -p /path/to/your-project/.claude/commands +cp 01-slash-commands/optimize.md /path/to/your-project/.claude/commands/ + +# 3. Спробувати — у Claude Code введіть: +# /optimize + +# 4. Готові до більшого? Налаштуйте пам'ять проєкту: +cp 02-memory/project-CLAUDE.md /path/to/your-project/CLAUDE.md + +# 5. Встановіть навичку: +cp -r 03-skills/code-review ~/.claude/skills/ +``` + +Хочете повне налаштування? Ось **необхідне за 1 годину**: + +```bash +# Слеш-команди (15 хв) +cp 01-slash-commands/*.md .claude/commands/ + +# Пам'ять проєкту (15 хв) +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Встановити навичку (15 хв) +cp -r 03-skills/code-review ~/.claude/skills/ + +# Ціль на вихідні: додати хуки, субагенти, MCP та плагіни +# Слідуйте навчальному шляху для керованого налаштування +``` + +--- + +## Що можна побудувати? + +| Сценарій | Функції, які ви поєднаєте | +|----------|--------------------------| +| **Автоматичне код-рев'ю** | Слеш-команди + Субагенти + Пам'ять + MCP | +| **Онбординг команди** | Пам'ять + Слеш-команди + Плагіни | +| **Автоматизація CI/CD** | CLI + Хуки + Фонові завдання | +| **Генерація документації** | Навички + Субагенти + Плагіни | +| **Аудит безпеки** | Субагенти + Навички + Хуки (режим читання) | +| **DevOps-пайплайни** | Плагіни + MCP + Хуки + Фонові завдання | +| **Складний рефакторинг** | Контрольні точки + Режим планування + Хуки | + +--- + +## FAQ + +**Це безкоштовно?** +Так. Ліцензія MIT, безкоштовно назавжди. Використовуйте в особистих проєктах, на роботі, у команді — без обмежень, крім включення ліцензії. + +**Це підтримується?** +Активно. Довідник синхронізується з кожним релізом Claude Code. Поточна версія: v2.3.0 (квітень 2026), сумісна з Claude Code 2.1+. + +**Чим це відрізняється від офіційної документації?** +Офіційна документація — це довідник функцій. Цей довідник — туторіал з діаграмами, готовими до продакшену шаблонами та прогресивним навчальним шляхом. Вони доповнюють одне одного — починайте тут для навчання, звертайтесь до офіційних документів коли потрібні деталі. + +**Скільки часу потрібно пройти все?** +11-13 годин для повного шляху. Але ви отримаєте цінність за 15 хвилин — просто скопіюйте шаблон слеш-команди та спробуйте. + +**Чи працює це з Claude Sonnet / Haiku / Opus?** +Так. Усі шаблони працюють з Claude Sonnet 4.6, Claude Opus 4.6 та Claude Haiku 4.5. + +**Чи можна долучитися?** +Звичайно. Див. [CONTRIBUTING.md](CONTRIBUTING.md) для настанов. Ми вітаємо нові приклади, виправлення, покращення документації та шаблони спільноти. + +**Чи можна читати офлайн?** +Так. Запустіть `uv run scripts/build_epub.py` для генерації EPUB-книги з усім контентом та відрендереними діаграмами. + +--- + +## Почніть опановувати Claude Code сьогодні + +Ви вже встановили Claude Code. Єдине, що відділяє вас від 10-кратного підвищення продуктивності — знання як його використовувати. Цей довідник дає вам структурований шлях, візуальні пояснення та готові шаблони для цього. + +Ліцензія MIT. Безкоштовно назавжди. Клонуйте, форкніть, зробіть своїм. + +**[Почати навчальний шлях ->](LEARNING-ROADMAP.md)** | **[Каталог функцій](CATALOG.md)** | **[Почни за 15 хвилин](#почни-за-15-хвилин)** + +--- + +
+Швидка навігація — Усі функції + +| Функція | Опис | Папка | +|---------|------|-------| +| **Каталог функцій** | Повний довідник з командами встановлення | [CATALOG.md](CATALOG.md) | +| **Слеш-команди** | Ярлики, ініційовані користувачем | [01-slash-commands/](01-slash-commands/) | +| **Пам'ять** | Постійний контекст | [02-memory/](02-memory/) | +| **Навички** | Багаторазові можливості | [03-skills/](03-skills/) | +| **Субагенти** | Спеціалізовані AI-помічники | [04-subagents/](04-subagents/) | +| **Протокол MCP** | Доступ до зовнішніх інструментів | [05-mcp/](05-mcp/) | +| **Хуки** | Автоматизація на основі подій | [06-hooks/](06-hooks/) | +| **Плагіни** | Пакетні функції | [07-plugins/](07-plugins/) | +| **Контрольні точки** | Знімки сесій та відкат | [08-checkpoints/](08-checkpoints/) | +| **Просунуті функції** | Планування, мислення, фонові завдання | [09-advanced-features/](09-advanced-features/) | +| **Довідник CLI** | Команди, прапорці та опції | [10-cli/](10-cli/) | + +
+ +
+Порівняння функцій + +| Функція | Виклик | Постійність | Найкраще для | +|---------|--------|------------|-------------| +| **Слеш-команди** | Ручний (`/cmd`) | Лише сесія | Швидкі ярлики | +| **Пам'ять** | Авто-завантаження | Між сесіями | Довгострокове навчання | +| **Навички** | Авто-виклик | Файлова система | Автоматизовані процеси | +| **Субагенти** | Авто-делегування | Ізольований контекст | Розподіл завдань | +| **Протокол MCP** | Авто-запити | Реальний час | Доступ до живих даних | +| **Хуки** | За подіями | Налаштовувані | Автоматизація та валідація | +| **Плагіни** | Одна команда | Усі функції | Комплексні рішення | +| **Контрольні точки** | Ручний/Авто | Сесійні | Безпечне експериментування | +| **Режим планування** | Ручний/Авто | Фаза плану | Складні реалізації | +| **Фонові завдання** | Ручний | Час завдання | Тривалі операції | +| **Довідник CLI** | Термінальні команди | Сесія/Скрипт | Автоматизація та скриптинг | + +
+ +
+Швидкий довідник встановлення + +```bash +# Слеш-команди +cp 01-slash-commands/*.md .claude/commands/ + +# Пам'ять +cp 02-memory/project-CLAUDE.md ./CLAUDE.md + +# Навички +cp -r 03-skills/code-review ~/.claude/skills/ + +# Субагенти +cp 04-subagents/*.md .claude/agents/ + +# MCP +export GITHUB_TOKEN="token" +claude mcp add github -- npx -y @modelcontextprotocol/server-github + +# Хуки +mkdir -p ~/.claude/hooks +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh + +# Плагіни +/plugin install pr-review + +# Контрольні точки (увімкнені за замовчуванням) +# Див. 08-checkpoints/README.md + +# Просунуті функції (налаштування в settings) +# Див. 09-advanced-features/config-examples.json + +# CLI (не потребує встановлення) +# Див. 10-cli/README.md +``` + +
+ +
+01. Слеш-команди + +**Розташування**: [01-slash-commands/](01-slash-commands/) + +**Що**: Ярлики, ініційовані користувачем, збережені як Markdown-файли + +**Приклади**: +- `optimize.md` — Аналіз оптимізації коду +- `pr.md` — Підготовка pull request +- `generate-api-docs.md` — Генератор API-документації + +**Встановлення**: +```bash +cp 01-slash-commands/*.md /path/to/project/.claude/commands/ +``` + +**Використання**: +``` +/optimize +/pr +/generate-api-docs +``` + +
+ +
+02. Пам'ять + +**Розташування**: [02-memory/](02-memory/) + +**Що**: Постійний контекст між сесіями + +**Приклади**: +- `project-CLAUDE.md` — Командні стандарти проєкту +- `directory-api-CLAUDE.md` — Правила для каталогу +- `personal-CLAUDE.md` — Персональні налаштування + +**Встановлення**: +```bash +# Пам'ять проєкту +cp 02-memory/project-CLAUDE.md /path/to/project/CLAUDE.md + +# Пам'ять каталогу +cp 02-memory/directory-api-CLAUDE.md /path/to/project/src/api/CLAUDE.md + +# Персональна пам'ять +cp 02-memory/personal-CLAUDE.md ~/.claude/CLAUDE.md +``` + +**Використання**: Автоматично завантажується Claude + +
+ +
+03. Навички + +**Розташування**: [03-skills/](03-skills/) + +**Що**: Багаторазові можливості з автовикликом, інструкціями та скриптами + +**Приклади**: +- `code-review/` — Комплексне код-рев'ю зі скриптами +- `brand-voice/` — Перевірка відповідності голосу бренду +- `doc-generator/` — Генератор API-документації + +**Встановлення**: +```bash +# Персональні навички +cp -r 03-skills/code-review ~/.claude/skills/ + +# Навички проєкту +cp -r 03-skills/code-review /path/to/project/.claude/skills/ +``` + +**Використання**: Автоматично викликаються за потреби + +
+ +
+04. Субагенти + +**Розташування**: [04-subagents/](04-subagents/) + +**Що**: Спеціалізовані AI-помічники з ізольованими контекстами та кастомними промптами + +**Приклади**: +- `code-reviewer.md` — Комплексний аналіз якості коду +- `test-engineer.md` — Стратегія тестування та покриття +- `documentation-writer.md` — Технічна документація +- `secure-reviewer.md` — Рев'ю безпеки (тільки читання) +- `implementation-agent.md` — Повна реалізація функцій + +**Встановлення**: +```bash +cp 04-subagents/*.md /path/to/project/.claude/agents/ +``` + +**Використання**: Автоматичне делегування головним агентом + +
+ +
+05. Протокол MCP + +**Розташування**: [05-mcp/](05-mcp/) + +**Що**: Model Context Protocol для доступу до зовнішніх інструментів та API + +**Приклади**: +- `github-mcp.json` — Інтеграція з GitHub +- `database-mcp.json` — Запити до бази даних +- `filesystem-mcp.json` — Файлові операції +- `multi-mcp.json` — Кілька MCP-серверів + +**Встановлення**: +```bash +# Встановити змінні оточення +export GITHUB_TOKEN="your_token" +export DATABASE_URL="postgresql://..." + +# Додати MCP-сервер через CLI +claude mcp add github -- npx -y @modelcontextprotocol/server-github +``` + +**Використання**: MCP-інструменти автоматично доступні Claude після налаштування + +
+ +
+06. Хуки + +**Розташування**: [06-hooks/](06-hooks/) + +**Що**: Shell-команди на основі подій, що виконуються автоматично у відповідь на події Claude Code + +**Приклади**: +- `format-code.sh` — Автоформатування коду перед записом +- `pre-commit.sh` — Запуск тестів перед комітами +- `security-scan.sh` — Сканування на проблеми безпеки +- `log-bash.sh` — Логування всіх bash-команд +- `validate-prompt.sh` — Валідація промптів +- `notify-team.sh` — Надсилання сповіщень + +**Встановлення**: +```bash +mkdir -p ~/.claude/hooks +cp 06-hooks/*.sh ~/.claude/hooks/ +chmod +x ~/.claude/hooks/*.sh +``` + +**Використання**: Хуки виконуються автоматично за подіями + +**Типи хуків** (4 типи, 25 подій): +- **Хуки інструментів**: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest` +- **Хуки сесій**: `SessionStart`, `SessionEnd`, `Stop`, `StopFailure`, `SubagentStart`, `SubagentStop` +- **Хуки завдань**: `UserPromptSubmit`, `TaskCompleted`, `TaskCreated`, `TeammateIdle` +- **Хуки життєвого циклу**: `ConfigChange`, `CwdChanged`, `FileChanged`, `PreCompact`, `PostCompact`, `WorktreeCreate`, `WorktreeRemove`, `Notification`, `InstructionsLoaded`, `Elicitation`, `ElicitationResult` + +
+ +
+07. Плагіни + +**Розташування**: [07-plugins/](07-plugins/) + +**Що**: Пакетні набори команд, агентів, MCP та хуків + +**Приклади**: +- `pr-review/` — Повний процес рев'ю PR +- `devops-automation/` — Розгортання та моніторинг +- `documentation/` — Генерація документації + +**Встановлення**: +```bash +/plugin install pr-review +/plugin install devops-automation +/plugin install documentation +``` + +**Використання**: Використовуйте пакетні слеш-команди та функції + +
+ +
+08. Контрольні точки та відкат + +**Розташування**: [08-checkpoints/](08-checkpoints/) + +**Що**: Збереження стану розмови та повернення до попередніх точок для дослідження різних підходів + +**Ключові поняття**: +- **Контрольна точка**: Знімок стану розмови +- **Відкат**: Повернення до попередньої контрольної точки +- **Точка розгалуження**: Дослідження кількох підходів з однієї точки + +**Використання**: +``` +# Контрольні точки створюються автоматично з кожним промптом +# Для відкату натисніть Esc двічі або: +/rewind + +# Потім оберіть: +# 1. Відновити код і розмову +# 2. Відновити розмову +# 3. Відновити код +# 4. Підсумувати звідси +# 5. Скасувати +``` + +
+ +
+09. Просунуті функції + +**Розташування**: [09-advanced-features/](09-advanced-features/) + +**Що**: Просунуті можливості для складних робочих процесів та автоматизації + +**Включає**: +- **Режим планування** — Детальні плани реалізації перед кодуванням +- **Розширене мислення** — Глибоке міркування для складних проблем (перемикання через `Alt+T` / `Option+T`) +- **Фонові завдання** — Тривалі операції без блокування +- **Режими дозволів** — `default`, `acceptEdits`, `plan`, `dontAsk`, `bypassPermissions` +- **Headless-режим** — Claude Code у CI/CD: `claude -p "Run tests and generate report"` +- **Управління сесіями** — `/resume`, `/rename`, `/fork`, `claude -c`, `claude -r` +- **Конфігурація** — Налаштування поведінки в `~/.claude/settings.json` + +Див. [config-examples.json](09-advanced-features/config-examples.json) для повних конфігурацій. + +
+ +
+10. Довідник CLI + +**Розташування**: [10-cli/](10-cli/) + +**Що**: Повний довідник інтерфейсу командного рядка Claude Code + +**Швидкі приклади**: +```bash +# Інтерактивний режим +claude "explain this project" + +# Print mode (неінтерактивний) +claude -p "review this code" + +# Обробка вмісту файлу +cat error.log | claude -p "explain this error" + +# JSON-вивід для скриптів +claude -p --output-format json "list functions" + +# Відновлення сесії +claude -r "feature-auth" "continue implementation" +``` + +**Сценарії**: Інтеграція CI/CD-пайплайнів, автоматизація скриптів, пакетна обробка, багатосесійні процеси + +
+ +
+Приклади робочих процесів + +### Повний процес код-рев'ю + +```markdown +# Використовує: Слеш-команди + Субагенти + Пам'ять + MCP + +User: /review-pr + +Claude: +1. Завантажує пам'ять проєкту (стандарти кодування) +2. Отримує PR через GitHub MCP +3. Делегує субагенту code-reviewer +4. Делегує субагенту test-engineer +5. Синтезує знахідки +6. Надає комплексний огляд +``` + +### Автоматична документація + +```markdown +# Використовує: Навички + Субагенти + Пам'ять + +User: "Generate API documentation for the auth module" + +Claude: +1. Завантажує пам'ять проєкту (стандарти документації) +2. Виявляє запит на генерацію документації +3. Автоматично викликає навичку doc-generator +4. Делегує субагенту api-documenter +5. Створює комплексну документацію з прикладами +``` + +### DevOps-розгортання + +```markdown +# Використовує: Плагіни + MCP + Хуки + +User: /deploy production + +Claude: +1. Запускає pre-deploy хук (валідація середовища) +2. Делегує субагенту deployment-specialist +3. Виконує розгортання через Kubernetes MCP +4. Моніторить прогрес +5. Запускає post-deploy хук (перевірки стану) +6. Звітує про статус +``` + +
+ +
+Найкращі практики + +### Робіть +- Починайте просто зі слеш-команд +- Додавайте функції поступово +- Використовуйте пам'ять для командних стандартів +- Тестуйте конфігурації локально спочатку +- Документуйте кастомні реалізації +- Контролюйте версії проєктних конфігурацій +- Діліться плагінами з командою + +### Не робіть +- Не створюйте надлишкових функцій +- Не хардкодьте облікові дані +- Не пропускайте документацію +- Не ускладнюйте прості завдання +- Не ігноруйте найкращі практики безпеки +- Не комітьте чутливі дані + +
+ +
+Усунення неполадок + +### Функція не завантажується +1. Перевірте розташування та назву файлу +2. Перевірте синтаксис YAML frontmatter +3. Перевірте дозволи файлу +4. Перевірте сумісність з версією Claude Code + +### MCP-з'єднання не вдалося +1. Перевірте змінні оточення +2. Перевірте встановлення MCP-сервера +3. Протестуйте облікові дані +4. Перевірте мережеве з'єднання + +### Субагент не делегує +1. Перевірте дозволи інструментів +2. Перевірте чіткість опису агента +3. Перевірте складність завдання +4. Протестуйте агента окремо + +
+ +--- + +## Внесок + +Ми вітаємо внески! Будь ласка, ознайомтесь з [Настановами для контриб'юторів](CONTRIBUTING.md) для деталей. + +--- + +## Ліцензія + +Ліцензія MIT — див. [LICENSE](LICENSE). Вільне використання, модифікація та розповсюдження. Єдина вимога — включити повідомлення про ліцензію. + +--- + +**Останнє оновлення**: Квітень 2026 +**Версія Claude Code**: 2.1.97 +**Сумісні моделі**: Claude Sonnet 4.6, Claude Opus 4.6, Claude Haiku 4.5 From d970cc6b2dd068ad90e847fab3f700cb627b8409 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 08:57:34 +0300 Subject: [PATCH 19/20] fix(uk): fix CP1251 encoding in claude_concepts_guide.md ToC --- uk/claude_concepts_guide.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/uk/claude_concepts_guide.md b/uk/claude_concepts_guide.md index 3b996a9..d432eec 100644 --- a/uk/claude_concepts_guide.md +++ b/uk/claude_concepts_guide.md @@ -11,16 +11,16 @@ ## Зміст -1. [Slash Commands](#slash-commands) -2. [Subagents](#subagents) -3. [Memory](#memory) -4. [MCP Protocol](#mcp-protocol) -5. [Agent Skills](#agent-skills) -6. [Plugins](#claude-code-plugins) -7. [Hooks](#hooks) -8. [Checkpoints and Rewind](#checkpoints-and-rewind) -9. [Advanced Features](#advanced-features) -10. [Comparison & Integration](#comparison--integration) +1. [Слеш-команди](#слеш-команди) +2. [Субагенти](#субагенти) +3. [Пам'ять](#память) +4. [Протокол MCP](#протокол-mcp) +5. [Навички агентів](#навички-агентів) +6. [Плагіни](#плагіни-claude-code) +7. [Хуки](#хуки) +8. [Контрольні точки та відкат](#контрольні-точки-та-відкат) +9. [Просунуті функції](#просунуті-функції) +10. [Порівняння та інтеграція](#порівняння-та-інтеграція) --- From b8a7b1f491fa09e7992b5f08303270d28219e7a1 Mon Sep 17 00:00:00 2001 From: Evgenij I Date: Fri, 10 Apr 2026 13:43:14 +0300 Subject: [PATCH 20/20] fix: change bad mermaid example to text block to pass CI --- uk/TRANSLATION_NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uk/TRANSLATION_NOTES.md b/uk/TRANSLATION_NOTES.md index c11688f..1709155 100644 --- a/uk/TRANSLATION_NOTES.md +++ b/uk/TRANSLATION_NOTES.md @@ -134,7 +134,7 @@ graph TD ``` -```mermaid +```text graph TD # Це зламає парсер! A[User] --> B[Agent]