
git blameпоказывает кто, когда и что изменил. whyso показывает почему.
Проблема
Когда хочется понять, почему строка кода выглядит именно так, единственное, что мы можем сделать — посмотреть git blame и сообщение коммита.
$ git blame internal/handler/page.go
a3f1b2c (parkjunwoo 2026-03-08) func CreatePage(c *gin.Context) {
Кто, когда и что изменил — это есть. Почему изменил — нет.
Можно же писать причину в сообщении коммита? Реальность такова:
fix: update handler
refactor: clean up
wip
Писать хорошие сообщения коммитов — дело дисциплины. Какие бы командные конвенции ни существовали, мало кто в три часа ночи, исправляя баг, думает: «Нужно тщательно записать контекст и обоснование этого изменения в сообщении коммита».
Но в эпоху AI-разработки ситуация другая. Причина изменения уже записана.
Данные сессий Claude Code
Claude Code сохраняет все разговоры в виде JSONL-файлов в директории ~/.claude/projects/. Каждая запись содержит сообщение пользователя, ответ AI, вызовы tool_use (Write, Edit, Bash) и цепочку parentUuid, связывающую их вместе.
Пользователь: "Начни реализацию команды whyso validate"
→ AI: Write internal/crosscheck/crosscheck.go
→ AI: Edit internal/crosscheck/crosscheck.go
→ AI: "Создание начального пакета crosscheck — проверка соответствия SSaC↔OpenAPI operationId"
Почему был создан файл, почему он был изменён — всё это остаётся в самом разговоре. Богаче, чем сообщение коммита, и писать специально ничего не нужно. Если разговор состоялся — запись создаётся автоматически.
whyso парсит эти данные и извлекает историю изменений по каждому файлу.
Видна вся жизнь файла
file: internal/crosscheck/crosscheck.go
created: 2026-03-08T14:23:01Z
history:
- timestamp: 2026-03-08T14:23:01Z
session: 09351222-d7be-41fe-994f-87c2d7067e5d
user_request: "Начни реализацию команды whyso validate"
answer: "Создание начального пакета crosscheck — проверка соответствия SSaC↔OpenAPI operationId"
tool: Write
- timestamp: 2026-03-09T10:15:33Z
session: 4e9b4e5e-3a50-43f2-be6e-e5db228ecc3b
user_request: "Добавь проверку наличия колонки x-sort в DDL"
answer: "Добавлена перекрёстная проверка колонок x-sort/x-filter → DDL"
tool: Edit
- timestamp: 2026-03-10T09:41:22Z
session: b2e43b4f-cb21-4286-975d-1eb9de8a16c0
user_request: "Добавь перекрёстную проверку спецификации Func"
answer: "Добавлена перекрёстная проверка @call ↔ спецификации Func по количеству и типам аргументов"
tool: Edit
Почему был создан, как эволюционировал под влиянием каких запросов. Вся жизнь одного файла как на ладони.
Зачем это нужно
Пробел в code review
При ревью PR бывает момент, когда задаёшь вопрос: «Зачем было сделано это изменение?» Если причина не указана в сообщении коммита, приходится спрашивать автора. Если автор не помнит — нужно перечитывать код и строить догадки.
В среде AI-разработки ответ на этот вопрос есть в данных сессии. whyso его достаёт.
Онбординг
Самый быстрый способ для нового члена команды разобраться в кодовой базе — понять, «почему код стал именно таким». git log — это хронологический список изменений, документация — снимок текущего состояния. История по файлам в whyso показывает то, что между ними — цепочку намерений.
Личная летопись
Даже работая в одиночку, бывают моменты, когда не помнишь, почему три месяца назад написал именно так. whyso восстанавливает разговор между прошлым собой и AI. Там есть контекст, который не попал в сообщение коммита.
Отношение к git blame
whyso не заменяет git blame. Он его дополняет.
| git blame | whyso | |
|---|---|---|
| Кто | O | — |
| Когда | O | O |
| Что изменил | O (построчно) | O (по tool_use) |
| Почему изменил | △ (сообщение коммита) | O (запрос пользователя + объяснение AI) |
| Источник данных | история git | сессии Claude Code |
Если git blame — это «официальная запись» на основе коммитов, то whyso — «рабочий журнал» на основе разговоров. В рабочем журнале хранится контекст, который не вошёл в официальную запись.
Структура, где AI читает собственные записи
Самый интересный сценарий использования whyso — это когда его читает не человек, а сам AI.
Claude Code забывает всё по окончании сессии. Когда в следующей сессии открывается тот же проект, он не знает: почему вчера я написал именно так, какие варианты рассматривались и были отброшены, в каком контексте был сделан запрос пользователя — ничего этого нет. Остаётся только читать код и строить догадки.
Представьте, что в CLAUDE.md добавить одну строку:
Перед изменением файла обязательно выполни `whyso history <file>`. Если история есть — прочитай её перед правкой.
Что меняет эта строка:
Знает, какие изменения нельзя откатывать
Читая файл перед изменением, замечаешь странный на вид код. Глядя только на текущее состояние, хочется его исправить — кажется, что это ошибка. Но если в истории whyso написано: «Пользователь явно запросил такую структуру, и причина — не производительность, а читаемость» — трогать не будешь.
Не предлагает снова уже отброшенные варианты
В предыдущей сессии был разговор: «Попробовать вариант A?» → «Нет, идём по B». AI в новой сессии этого не знает. И снова предлагает A. Для пользователя это раздражает. С whyso AI знает, какие направления уже рассматривались и были отвергнуты.
Сохраняет контекст непрерывной работы
«Продолжи вчерашний рефакторинг» — сейчас приходится смотреть diff и строить догадки. С историей whyso сразу читаешь запросы пользователя из вчерашней сессии и обоснования решений AI. Вместо догадок — работа, основанная на фактах.
Записи накапливаются между сессиями
В такой структуре история whyso накапливается с каждой сессией. Причина изменения в текущей сессии передаётся AI следующей. Проблема отсутствия памяти между сессиями решается на уровне файлов. Без отдельной системы памяти.
То, что записано в whyso — это работа AI. Но AI её не помнит. Записи, которые он сам создал, нужны ему самому больше всего. Вот в чём уникальность whyso в связке с инструментами AI-разработки.
Для людей whyso — «инструмент, автоматически оставляющий хорошие сообщения коммитов». Для AI whyso — память, переживающая сессию.
Использование
Установка
go install github.com/park-jun-woo/whyso/cmd/whyso@latest
Просмотр истории файла
# Один файл
whyso history README.md
# Вся директория
whyso history internal/ --all
# Вывод с зеркалированием структуры файлов
whyso history . --all --output .file-histories/
# Формат JSON
whyso history README.md --format json
Список сессий
whyso sessions
Как это работает
Обратный обход цепочки parentUuid
Каждая запись в JSONL связана через uuid и parentUuid. Поднимаясь по цепочке parentUuid от tool_use, где AI изменил файл, можно добраться до исходного запроса пользователя, спровоцировавшего это изменение.
user message (uuid: A) ← "Добавь проверку наличия колонки x-sort в DDL"
→ assistant tool_use (parentUuid: A)
→ tool_result (parentUuid: B)
→ assistant Edit (parentUuid: C) ← причина этого изменения = A
Поскольку между ними могут вклиниваться сообщения типа tool_result, нужно извлекать только те, у которых type == "user" и content является строкой — так найдёшь настоящий запрос пользователя.
Архитектурные решения
Отслеживаются только Write/Edit. tool_use Write и Edit в Claude Code явно содержат путь к файлу и внесённые изменения. Файловые операции через Bash-команды (rm, mv, cp) определяются эвристически, но Write/Edit — основной объект отслеживания. Claude Code спроектирован так, чтобы использовать Write/Edit при изменении файлов, поэтому этих двух инструментов достаточно для фиксации большинства изменений.
Включаются и субагенты. Когда Claude Code обрабатывает сложные задачи, он может порождать субагентов. Сессии субагентов сохраняются в поддиректориях родительской сессии. whyso парсит и эти сессии субагентов, выстраивая полную историю.
Инкрементальное обновление. При выводе в директорию через --output уже обработанные сессии пропускаются. Даже если сессий станет несколько сотен, каждый раз заново парсить всё не придётся.
Цифры
Результаты отслеживания процесса разработки самого проекта whyso через whyso:
| Показатель | Значение |
|---|---|
| Количество сессий | 17 |
| Вызовы Write | 660 |
| Вызовы Edit | 1 415 |
| Файловые операции через Bash | 206 |
| Уникальных изменённых файлов | 480 |
Из 17 сессий извлечена история изменений 480 файлов. Для каждого файла записано «почему был создан и почему изменялся».
Ограничения
- Только для Claude Code. Данные сессий других AI-инструментов разработки имеют другой формат. В настоящее время поддерживается только JSONL-формат Claude Code.
- Отслеживаются только текстовые файлы. tool_use Write/Edit работает с текстовыми файлами. Изменения изображений и бинарных файлов не отслеживаются.
- Данные сессий должны быть локальными. Файлы сессий должны находиться в
~/.claude/projects/. Если они удалены или работа велась на другой машине — этих записей нет.
Итог
В эпоху написания кода совместно с AI причину изменения больше не нужно доверять только сообщению коммита. Сам разговор является записью, и из этой записи можно автоматически извлечь историю изменений по каждому файлу.
Если git blame показывает «кто, когда и что изменил», то whyso показывает «почему изменил».