whyso — то, чего не показывает git blame

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 blamewhyso
КтоO
КогдаOO
Что изменил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
Вызовы Write660
Вызовы Edit1 415
Файловые операции через Bash206
Уникальных изменённых файлов480

Из 17 сессий извлечена история изменений 480 файлов. Для каждого файла записано «почему был создан и почему изменялся».


Ограничения

  • Только для Claude Code. Данные сессий других AI-инструментов разработки имеют другой формат. В настоящее время поддерживается только JSONL-формат Claude Code.
  • Отслеживаются только текстовые файлы. tool_use Write/Edit работает с текстовыми файлами. Изменения изображений и бинарных файлов не отслеживаются.
  • Данные сессий должны быть локальными. Файлы сессий должны находиться в ~/.claude/projects/. Если они удалены или работа велась на другой машине — этих записей нет.

Итог

В эпоху написания кода совместно с AI причину изменения больше не нужно доверять только сообщению коммита. Сам разговор является записью, и из этой записи можно автоматически извлечь историю изменений по каждому файлу.

Если git blame показывает «кто, когда и что изменил», то whyso показывает «почему изменил».

Код: github.com/park-jun-woo/whyso