# Habr Post

> Статьи для Habr твоим голосом: технические кейсы с кодом и цифрами; 4 длины + series mode. Триггеры: «пост для Хабра», «статья для Хабра». НЕ личный бизнес-опыт→vc-post.

- Skill: `jhamidun/habr-post` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add jhamidun/habr-post`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jhamidun/habr-post/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: JHamidun (https://skillmd.com/u/jhamidun)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/jhamidun/habr-post

---


# Habr Post Writer

## Что понадобится

| Нужно | Зачем | Без этого |
|---|---|---|
| `~/.claude/author-profile.md` | кто автор, регалии, площадки, о чём молчим | статья выйдет от безликого «эксперта»; шаблон — `~/.claude/templates/author-profile.md` |
| `~/.claude/voice-sample.md` | 2-3 твоих текста как образец голоса | voice-keeper не с чем сверять, статья звучит как ИИ; шаблон — `~/.claude/templates/voice-sample.md` |
| Доступ к своему репо/логам/мониторингу | правило №0: цифры и код только из источника | писать нечего — см. правило №0 |
| `GOOGLE_API_KEY` (платный, ai.google.dev) | обложка через `templates/gen_cover.py` | обложку делаешь сам, остальной пайплайн работает |
| `python-docx`, `Pillow`, `google-genai`, `python-dotenv` | `build_docx.py`, `gen_cover.py` | `pip install python-docx Pillow google-genai python-dotenv` |

## 🛑 ПРАВИЛО №0 — НИКАКОЙ ОТСЕБЯТИНЫ

**Критичнее всех остальных. Нарушение = статья удаляется целиком.** Habr наказывает за фактические ошибки сильнее, чем за корпоративный голос: один придуманный latency, несуществующий сервис или код не из репо — и в комментах разнесут, карму срежут.

1. **Ни одной цифры без проверяемого источника** (мониторинг, скриншот Grafana, `git log`, `cloc`, логи, отчёты). Нельзя достать источник — не использовать вообще. Лучше «в нашем масштабе» без числа, чем выдуманное «40К RPS».
2. **Ни одного куска кода, которого нет в репо.** Открыть реальный файл, скопировать, упростить — но семантику сохранить. Выдуманные сигнатуры/модули/классы запрещены.
3. **Путь к репо, про который пишешь, задаётся в RESEARCH.md полем `repo:`.** Перед статьёй прочитать его `CLAUDE.md` / `README.md` (архитектурная карта) и те файлы, о которых речь. **На память не полагаться** — там устаревшее; память лишь подсказка ГДЕ искать, факт берётся из живого файла.
4. **Ни одной истории/инцидента без подтверждения у автора** прямым вопросом «это реально было или придумать?». Обобщение писать как обобщение («обычно так бывает»), не как конкретный случай.
5. **Ни одной прямой цитаты, которую не произносил реальный человек.**
6. **Ни одного имени клиента или работодателя без письменного разрешения.** Кого нельзя называть и чем заменять («крупный ритейлер», «банк из топ-10») — раздел «О чём НЕ говорю» в `author-profile.md`. Нет разрешения — обобщать, а не «наверное, можно».
7. **Ни одного упоминания коллег и команды без сверки с ними.**
8. **«Это ты правда видел?»** — перед каждой конкретной деталью: автор реально это видел/делал/знает, или я интерполирую?

## 🛑 ПРАВИЛО №0.5 — БЕЗОПАСНОСТЬ ЛИЧНЫХ ДАННЫХ

Перед каждой публикацией — `templates/security_scan.py` на FINAL.md (exit 1 = блок до решения автора).

Зачем это правило существует: в одной из статей про телеграм-бота в DRAFT уехали числовые
Telegram user_id и хэндл приватного бота. Автоматика их не поймала — поймал ручной фактчек
на последнем проходе. Скрипт закрывает ровно этот класс промахов.

Что ищет из коробки (без всякой настройки):

```
TG numeric ID:   \b\d{9,11}\b   (whitelist годов 1900-2100)
Bot handles:     @[A-Za-z][A-Za-z0-9_]*[Bb]ot\b
CPF:             \d{3}\.\d{3}\.\d{3}-\d{2}
Phones:          \+\d{1,3}\s?\(?\d{2,4}\)?\s?\d{3}-?\d{2}-?\d{2}
Emails:          любой email (кроме твоего whitelist)
Private IPv4:    10.x / 172.16-31.x / 192.168.x
Home paths:      C:\Users\<кто угодно>\..., /home/<кто угодно>/..., /Users/<кто угодно>/...
Tokens/keys:     sk-…, ghp_…, AIza…, xox[bap]-…, Bearer …, PRIVATE KEY
```

**Своё — в `templates/patterns.local.json`** (в git не коммитить, он в `.gitignore` пака):
туда кладутся твои публичные почта и хэндлы (чтобы не подсвечивались каждый раз),
IP твоего сервера, пути к твоим продакшен-каталогам. Образец рядом:
`templates/patterns.local.example.json` — скопируй и заполни.

```bash
cp templates/patterns.local.example.json templates/patterns.local.json
python templates/security_scan.py FINAL.md          # подхватит автоматически
python templates/security_scan.py FINAL.md --patterns /path/to/my.json
```

## ПРОТОКОЛ ВЕРИФИКАЦИИ (8 проходов, без всех — не публиковать)

1. Разметка неизвестного — каждую цифру/имя/историю/код пометить ❓.
2. Добыча фактов — для каждого ❓ пойти в источник, заменить на ✅ или удалить ❌.
3. Вычитка на отсебятину (прочитать вслух).
4. de-ai-ify — прогнать через skill `de-ai-ify`.
5. Security scan (выше).
6. Тех-апрув: человек, который систему реально эксплуатирует (для инфраструктурных статей).
7. Юр-апрув: тот, кто отвечает за PR/договоры, — если упоминаются клиенты или работодатель.
8. Финальное чтение автором вслух.

> Пункты 6-7 — не бюрократия, а единственная защита от «я думал, про этого клиента можно».
> Некому апрувить (пишешь от себя, клиентов нет) — пункты пропускаются, но тогда правило
> №0.6 действует жёстче: любое чужое имя обобщается.

## Кто ты

Читается из `~/.claude/author-profile.md`: имя, роль, регалии для byline, площадки, стоп-лист.
Файла нет — **остановиться и сказать об этом**, а не сочинять автора.

Установка для Habr, поверх профиля: пишешь как **инженер-практик**, не как представитель
компании. Личный кейс на Habr собирает в разы больше вовлечения, чем корпоративный:
читателю интересно, что ты делал руками. Свой продукт упоминать только как источник опыта
и боли — **одно упоминание на статью**, в P.S., вскользь.

## Уровни длины

Определяется на research'е (поле `length` в RESEARCH.md), протаскивается во все стадии.

| Уровень | Слов | Знаков | Когда |
|---------|------|--------|-------|
| short | 1500–2500 | 10–18K | узкая заметка, разбор одной фичи, инцидент |
| medium | 2500–4000 | 18–28K | стандартный кейс, разбор, туториал |
| long | 4000–6000 | 28–40K | развёрнутый кейс с архитектурой, несколько секций |
| flagship | 6000–8000 | 40–60K | серийная флагманская, глубокая архитектура |

**При превышении верхней границы — сокращать абзацы из СЕРЕДИНЫ, не добавлять из конца.** Writer всегда тяготеет дописать, а не обрезать — бороться с этим (реальный замер на флагманской статье: 7679 → 7534 слова за счёт удаления «по сути», «это и есть», лишних связок; смысл не пострадал).

**Структура:** short = TL;DR (3 предложения) → контекст → что произошло → решение с кодом → что узнали (3–5) → P.S. medium = + архитектура со схемой, 2–4 сниппета, инцидент, чек-лист. long = + сравнение с альтернативами (таблица), **обязательный раздел «что не работает / что бы сделал иначе»**, cross-link. flagship = + многосекционная архитектура, series footer, closing CTA «забери каркас».

## Series mode

Серия связанных статей → единый реестр `templates/series.json` (id, title, articles[] с slug/title/url/status). **Writer вместо `[текст](#)` пишет `[текст](series:slug)`.** Pre-publish резолвит `series:slug` в реальный URL; статус `draft` оставляет `series:slug` и блокирует публикацию (видно, что нужен живой URL). Series footer для flagship — шаблон в `templates/cta_templates.md`.

`series.json` в паке — пустой каркас с одним примером серии. Свои серии заводишь сам;
формат виден по примеру.

## ДНК голоса

- **Инженер-практик, не лектор:** показываешь как работает, не объясняешь теорию.
- **Первое лицо функциональное:** «мы сделали», «я написал», «наш router».
- **Честный про провалы:** «мы не предусмотрели», «первая версия падала», «это стоило нам X убытка» — Habr это любит.
- **Конкретные числа:** не «высокий latency», а «P99 ~5.4 секунды».
- Уважение к читателю (не разжёвывать), дистанция с брендом.
- Живое: реальный (упрощённый) код, ASCII-схемы, таблицы «до/после», чек-листы, реальные названия инструментов, временные якоря («в марте, ночью»).
- **НИКОГДА:** «В современном мире ИИ…», «революционный/прорывной/game-changer», «идеальное решение», «все знают, что…», «Компания X представила…» в начале, «Давайте рассмотрим…», «Как известно…», «Это не просто X, а Y», топ-10 без реального отбора.

> Всё выше — общие правила площадки. **Твой голос** — в `~/.claude/voice-sample.md`,
> и при расхождении выигрывает он: правила описывают, чего избегать, образец — как звучать.

**Анти-ИИ фразы (запрещены, наследуется от tg-post; полная чистка — skill `de-ai-ify`):** «Но вот что интересно:», «И тут интересно:», «Что меня зацепило:», «Главный вопрос/наблюдение:», «Вижу паттерн:», «Что это значит на практике:», «Стоит отметить», «Важно понимать», «В заключение», «Подводя итог», «Таким образом», «Это действительно впечатляет», «Безусловно», «На самом деле», «По сути», «Это и есть», «Это открывает новые возможности», «Иными словами», «Простыми словами это означает». **Переходы:** просто следующий абзац, новый `##`, «Тем временем», «При этом», «А тут ещё», «И вот», «Ну и», «Короче».

## Форматирование, хабы, теги

Markdown: `#` (один раз), `##`/`###`, `**жирный**`, `*курсив*`, инлайн-код и блоки **с указанием языка**, `>` цитаты, списки, простые таблицы, `<spoiler>`. Хабы/теги — при публикации, не в тексте.

Хабы (реальные): Искусственный интеллект (основной), Промышленное программирование (инфра), Системное администрирование (DevOps/SRE), Машинное обучение, NLP, Управление разработкой/продуктом, Карьера в IT, Python/JS/TS, Высокая производительность, Базы данных, Open source (почти всегда для AI-стек). Теги: 3–5 коротких без решёток.

Типы статей: инженерный кейс (основной), разбор/исследование (воспроизводимые цифры), туториал, мнение/рефлексия, обзор инструмента.

**Плюсуют:** ошибки+фиксы, конкретные цифры, рабочие сниппеты, диаграммы, таблицы до/после, честное сравнение, чек-листы, «что бы сделал иначе». **Минусуют:** корпоративный PR в начале, отсутствие конкретики, списки без отбора, перевод без адаптации, скрытая реклама, обобщения без данных, статья на один пост.

## Правила-лимиты (проверяет editor/voice-keeper)

- **Цитата одного человека — максимум 1 раз в статье.** Две цитаты одного (проверено дважды на живых статьях) — оставить конкретную, вторую переписать как авторский тезис. Habr-комменты мгновенно замечают «вся статья на двух репликах одного CTO».
- **Упоминаний своего продукта в теле — максимум 2** (P.S. и byline не считаются). Больше = скрытая реклама, Habr минусует (в одной статье было 5+ — вырезали буллет с перечислением фич). Editor считает и BLOCK'ает с указанием каких.
- **Header-block schema** (иначе `build_docx.py` криво парсит metadata и шапка съезжает в тело):
  ```markdown
  # Заголовок

  **Автор:** Имя Фамилия, Должность
  **Площадка:** Habr
  **Формат:** инженерный кейс | разбор | туториал | мнение | обзор
  **Дата:** YYYY-MM-DD
  **Статус:** FINAL — ready for illustration and publishing

  ---

  ## TL;DR
  ```
  Все 5 полей заполнены, после блока обязательна `---` отбивка, TL;DR сразу после неё.

## NBSP-нормализация (обязательна в proofreader)

Non-breaking space (`\xa0`) проникает из Word/Telegram/AI-постпроцессинга. Read показывает его как обычный пробел, но Edit сравнивает байты и валится с «String not found» (в одной статье было 454 NBSP — пол-дня дебага). **Перед каждым Edit-проходом на FINAL.md:**

```python
with open(path, encoding="utf-8") as f: txt = f.read()
n = txt.count("\xa0")
if n:
    open(path, "w", encoding="utf-8").write(txt.replace("\xa0", " "))
    print(f"Normalized {n} NBSP")
```

Симптом: Edit падает «String not found», а Grep ту же строку находит → почти наверняка NBSP (`print(any(ord(c)==0xa0 for c in suspect_line))`).

## Пайплайн субагентов

Редколлегия из 9 субагентов (researcher → writer → fact-checker → voice-keeper → proofreader → editor → security-audit → illustrator → publisher). Артефакты, рабочая директория, VOICE_CORPUS, VOICE_PROMPT_TABOO, templates и CLI-вызовы, race-condition правило, формат вывода — `references/pipeline-mechanics.md`.

## Самопроверка перед публикацией

- [ ] В начале нет «В современном мире» / «Компания X представила»; автор обозначен как человек, не бренд
- [ ] ≥3 конкретные цифры, ≥1 фрагмент реального кода, честный провал/инцидент, чек-лист или «что бы сделал иначе»
- [ ] P.S. про продукт — одна строка; упоминаний продукта в теле ≤2; цитата одного человека ≤1
- [ ] Нет фраз из анти-ИИ списка; код размечен языком; хабы и теги выбраны
- [ ] `templates/security_scan.py` — 0 утечек; прогнано через `de-ai-ify`
- [ ] Все `[текст](#)` зарезолвлены через series.json или удалены
- [ ] Блок `Image prompt suggestions` не попал в FINAL.md (он в `IMAGE-PROMPTS.md`)
- [ ] Длина в пределах уровня; NBSP нормализованы; header-block schema соблюдён

## Отличие от tg-post

| Критерий | TG | Habr |
|---|---|---|
| Длина | 400–3000 символов | 10K–60K (4 уровня) |
| Тон | разговорный, уязвимый | инженерный, деловой, с личностью |
| Эмодзи | 0–2 | нет (кроме подзаголовков-исключений) |
| Подпись | футер канала | автор + регалии в начале |
| CTA | вопрос к аудитории | P.S. про продукт, чек-лист, «забери каркас» |
| Цель | личная связь | проф. репутация + продуктовый PR вскользь |

