Я много работаю с веб-проектами и параллельно постоянно использую нейросети. Довольно быстро стало ясно простое вещь: обсуждать с моделью реальный проект, перекидывая ей по одному файлу, бессмысленно. Ей нужен не фрагмент, а контекст — структура каталогов, реальные пути, живой код, а не абстрактные «примерчики».

Типичный сценарий выглядел так. Я отправляю модели один файл, получаю ответ, понимаю, что информация обрезана: нет конфига, нет шаблона, нет сервисного класса. Докидываю ещё один файл, потом третий, потом кусок верстки. В итоге я больше таскаю код туда-сюда и объясняю «как у нас всё устроено», чем решаю исходную задачу.

На этом фоне возник очень приземлённый запрос: один раз аккуратно «сфотографировать» проект в технически удобный формат, а дальше работать уже с этим снимком. Хранить его в репозитории рядом с кодом, прикладывать к задачам, загружать ассистентам GPT, подключать к своим RAG-сервисам. Так появился небольшой PHP-репозиторий scan2json.

Репозиторий лежит на GitHub: https://github.com/simai/scan2json. Его идея простая: в одну сторону он превращает проект в JSON/JSONL, а в другую — по JSONL может развернуть структуру папок и файлов в отдельную директорию. Дальше буду говорить, зачем мне это понадобилось, что именно я сделал и как этим можно пользоваться в реальной работе.

Почему «просто отправить пару файлов» не работает

Если честно, проблема не в том, что модели «не понимают код». Проблема в том, что мы подаём этот код в совершенно неудобной форме. Мы даём мозаику: кусок контроллера без шаблона, шаблон без данных, конфиг без использования. Разработчик ещё держит в голове карту проекта: он знает, где лежат модули, где общий хелпер, какие части связаны между собой. У модели этой карты нет, пока мы её явно не передали.

Инструменты в IDE частично помогают. Они могут автоматически подкидывать соседние файлы, можно настроить локальный индекс, кое-как подружить это с отдельным агентом. Но всё это жёстко привязано к конкретному редактору и плохо живёт снаружи: вы не положите такой индекс в репозиторий, не приложите к задаче, не передадите стороннему разработчику как самостоятельный артефакт.

Мне хотелось иметь именно артефакт. Файл или набор файлов, который существует независимо от IDE и конкретной машины. Его можно коммитить, версионировать, отдавать ассистентам GPT, использовать в своих сервисах. Внутри у него должен быть честный срез проекта: относительные пути, дерево каталогов и содержимое файлов. Не обязательно всего проекта — только той части, с которой я сейчас работаю. Но этот срез должен быть полным внутри себя: без «ой, забыл ещё вот этот файл».

Отсюда родилась формулировка: нужен скрипт, который из выбранной части проекта делает структурированный JSON, а при желании позволяет по этому JSON собрать отдельную копию. Всё остальное — детали реализации.

Что такое scan2json и из чего он состоит

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

  • scan.php — сканирует выбранную папку проекта и превращает её содержимое в JSONL, цельный JSON и JSON по частям;

  • restore.php — читает JSONL и по нему создаёт файлы и папки в отдельной директории.

Оба файла — обычные PHP-скрипты, которые я кладу под DOCUMENT_ROOT в нужном окружении. Они работают через браузер, защищены паролем и ни к чему не привязаны: им без разницы, это сайт, API-сервис или монолитное приложение.

Главным героем здесь является scan.php. Именно он решает основную задачу — сделать из живого проекта аккуратный JSON-снимок. restore.php появился чуть позже как естественное продолжение: когда стало понятно, что иногда хочется развернуть такой снимок обратно в отдельную песочницу.

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

Как устроен scan.php: выбор корня и фильтрация

Когда я открываю scan.php в браузере и ввожу пароль, первый вопрос, который нужно решить, — откуда вообще сканировать. Мне не всегда нужен весь проект целиком: иногда достаточно одного модуля, иногда только директории app или src, иногда — отдельной «рабочей» части большого монолита.

У меня есть два способа задать корневую папку. В простейшем варианте я просто указываю путь: корень сайта, конкретный каталог, модуль и так далее. Если структуру проекта я хорошо знаю, это самый быстрый путь.

Если путь вспоминать не хочется, удобнее воспользоваться встроенной навигацией. Интерфейс показывает текущую директорию, даёт возможность подняться на уровень выше и выбрать одну из подпапок. Я постепенно «проваливаюсь» туда, где лежит нужная область, и в какой-то момент просто останавливаюсь: вот отсюда и начинаем.

На этом этапе у меня есть конкретная директория, которая станет корнем обхода. Но этого мало: в живом проекте почти всегда лежит куча того, что в JSON совершенно не нужно. Это могут быть каталоги с загруженными файлами, кеши, временные артефакты, какие-то отдельные модули, которые к текущей задаче не относятся.

Под тонкую настройку я сделал в интерфейсе кнопку Choose items…. Логика простая: я задаю корень сканирования, нажимаю кнопку и вижу список всех элементов первого уровня внутри этой папки. Напротив каждого — чекбокс. По умолчанию всё включено. Дальше я просто снимаю галочки с того, что не хочу видеть в итоговом JSON: отдельные каталоги, большие папки с файлами, единичные тяжёлые объекты. После применения выбора сканер обходит только отмеченные элементы верхнего уровня, а внутрь уже заходит автоматически.

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

Какие форматы сканер создаёт на выходе

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

  • JSONL — файл, где каждая строка соответствует одному файлу проекта и содержит поля file и content;

  • цельный JSON — один большой массив объектов {file, content};

  • разбитый JSON — тот же массив, но автоматически нарезанный на несколько файлов, если проект слишком большой для одного.

Базовым форматом для дальнейшей обработки у меня является JSONL. Он выглядит примерно так:

{"file":"local/components/app/orders/class.php","content":"..."}

Такой файл удобно читать построчно: не нужно тянуть всё в память, можно стримить, можно обрабатывать его любыми инструментами командной строки или своими скриптами. Я использую JSONL, когда хочу построить поверх среза собственные пайплайны: индексировать код, делать векторизацию, искать повторяющиеся структуры, собирать аналитику по проекту.

Цельный JSON нужен там, где ожидают один валидный документ: ассистенты GPT, некоторые внешние утилиты, внутренние сервисы, которым проще работать с массивом. Для больших проектов одного такого файла может быть слишком много, и тогда на помощь приходит нарезка. Сканер ориентировочно считает объём данных и, когда он становится слишком большим, закрывает текущий файл и начинает следующий. Каждая запись {file, content} всегда попадает целиком в одну часть.

Все эти файлы складываются в директорию scan_tmp под DOCUMENT_ROOT. Там же на странице я вижу список того, что уже сформировано, могу скачать нужный вариант и посмотреть, сколько примерно «слов» получилось. Это не точный подсчёт токенов под конкретную модель, но хороший индикатор масштаба: сотни тысяч слов или десятки мегабайт — это уже сигнал подумать, как лучше нарезать данные для ассистента.

Кратко про restore.php: зачем он мне нужен

Изначально я делал инструмент только «в одну сторону» — чтобы получать JSON. Но довольно быстро стало понятно, что JSONL сам по себе — это уже почти автономный артефакт. Логично уметь по нему поднять отдельную копию проекта, пусть и не полную, а именно ту, которая была в срезе.

Под это я написал restore.php. Его задача минималистична: прочитать JSONL, который ранее сформировал scan.php, и для каждой строки с объектом вида {file, content} создать соответствующий файл в выбранной директории. Скрипт нормализует относительные пути, следит за тем, чтобы никакие .. не позволили выйти за пределы целевой папки, по мере необходимости создаёт недостающие каталоги.

Важно зафиксировать одно ограничение: restore.php не знает и не пытается знать, как проект выглядел «по-настоящему». Он восстанавливает только то, что попало в JSONL. Если при сканировании я исключил какие-то каталоги, их не будет и в развёрнутой копии. Если я сканировал не весь проект, а только один модуль, после восстановления у меня будет именно этот модуль, а не весь сайт.

На практике я использую restore.php реже, чем scan.php, но он несколько раз очень помог. Например, когда нужно было собрать из снимка отдельную песочницу для экспериментов, отдать срез проекта подрядчику в виде «вот вам JSONL и скрипт, сами развернёте» или выделить проблемный модуль в отдельный мини-проект, не выдёргивая его руками из большого репозитория.

Как я использую scan2json день за днём

Сейчас scan2json для меня — не разовая утилита, а часть обычного рабочего процесса. Сценарии при этом довольно разные.

Частая ситуация: мне нужно обсудить с ИИ доработку в существующем проекте. Я беру scan.php, кладу его под DOCUMENT_ROOT, настраиваю пароль и открываю в браузере. Дальше выбираю корень, откуда буду сканировать, через путь или навигацию, отрезаю лишнее через Choose items… и запускаю сканирование. На выходе получаю JSONL, который уже можно обрабатывать любыми своими инструментами.

Дальше поверх этого JSONL я строю контур для общения с моделью. Например, пишу небольшого агента, который по запросу пользователя отбирает файлы по маске пути, по имени класса или по ключевым словам, склеивает их содержимое в осмысленный контекст и только потом отправляет модели. В этом сценарии мы с ИИ обсуждаем не абстрактный «PHP-проект», а реально существующий код, полностью находящийся в данных.

Другой сценарий — ассистенты «по проекту» внутри GPT. Здесь я обычно беру цельный JSON или набор частей, создаю ассистента, загружаю эти файлы как знания и в инструкциях объясняю, что это конкретный проект: как устроены пути, где искать шаблоны, где бизнес-логику. После этого разработчик может прийти к ассистенту и задать прикладной вопрос: где реализована регистрация, какие классы отвечают за оплату, как правильно добавить новый статус сделки. Ассистент отвечает уже с опорой на реальные файлы.

Есть и сценарии исследования. Когда я разбираю чужой или legacy-проект, мне удобно сначала сделать срез через scan.php, а уже потом подключать ассистента или свои скрипты. Можно попросить модель описать архитектуру по каталогам, найти подозрительные места (копипаст, странные зависимости), накидать список технического долга. Можно, наоборот, использовать чисто свои инструменты для анализа JSONL и только на итогах анализа звать ИИ.

Иногда бывает и обратная история: у меня уже есть старый JSONL, например, снимок конкретного релиза. Тогда я запускаю restore.php, разворачиваю срез в отдельную директорию и получаю «мини-проект» с той же структурой, но без всего, что было специально отрезано на этапе сканирования. В такой песочнице можно не бояться экспериментировать: переписывать код, подключать различные инструменты, давать доступ ассистентам — основную кодовую базу это никак не затрагивает.

Ограничения и нюансы

У инструмента есть несколько естественных ограничений и тонкостей.

Во-первых, scan2json работает по файловой системе честно и последовательно. Если в проекте много тяжёлых артефактов, медиа и бинарников, их лучше сразу исключать: либо через общие настройки, либо через Choose items…. Иначе JSON-файлы получатся слишком крупными и не очень пригодными для передачи ассистентам.

Во-вторых, restore.php не предназначен для резервного копирования. Он не восстанавливает «всё как было», он поднимает именно тот срез, который вы сами сформировали через scan.php. Для полноценной стратегии бэкапов нужны другие инструменты, а scan2json здесь может быть только вспомогательной частью — например, чтобы дополнительно хранить структурированные срезы кода.

В-третьих, к безопасности стоит относиться серьёзно. Скрипты живут под DOCUMENT_ROOT, запускаются из браузера и по этой причине должны быть защищены не только паролем в коде. Я всегда меняю пароль по умолчанию, при необходимости ограничиваю доступ по IP и предпочитаю держать инструмент либо в изолированной среде, либо на стендах, а не на открытом проде.

В-четвёртых, оценка объёма данных по словам в интерфейсе — это именно оценка, а не точный пересчёт токенов в конкретной модели. Её хватает, чтобы понять порядок величин и прикинуть, как лучше нарезать JSON на части, но если вы оптимизируете диалоги под жесткие лимиты, имеет смысл дополнительно проверять размеры уже на стороне совокупного пайплайна.

Всё остальное — детали использования и предпочтения. Кому-то удобнее всегда сканировать весь проект, кому-то — только отдельные модули. Кто-то использует JSONL только для своих внутренних анализаторов, кто-то строит поверх него полноценные ассистенты.

Для меня scan2json стал довольно простым, но полезным ответом на реальную задачу: перестать объяснять проект ИИ по кусочкам. Сейчас это два небольших скрипта, которые делают ровно то, что от них требуется: scan.php снимает структурированный снимок проекта в JSON/JSONL, а restore.php по этому снимку умеет поднять отдельную копию. Если вам близка сама идея, можно просто клонировать репозиторий, положить scan.php рядом с одним из своих проектов, снять первый срез и посмотреть, как такой формат ляжет на ваш процесс работы с ИИ.

Комментарии (15)


  1. ktibr0
    06.12.2025 11:56

    Хм...спасибо, весьма интересная идея.

    Натолкнуло на размышления....

    Читал, что модели лучше понимают запрос, контекст, если им давать в json виде.

    Если развить идею, то сам кодинг/вайбкодинг можно начинать с просьбы сформировать структуру проекта в виде json, в котором описать не только файловую структуру, но функции, параметры вызовов, переменные и т.д.

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


    1. zabarov Автор
      06.12.2025 11:56

      Вы очень точно нащупали идею «сначала структура, потом код».

      В этом посте я показываю более низкий уровень — как дать модели снимок проекта в виде JSON/JSONL. А дальше поверх этого хорошо ложится как раз то, о чём вы пишете: формализованная модель в файлах, с которыми ИИ сверяется перед изменениями.

      В отдельной статье я как раз разбираю подход, где перед кодом мы строим для Copilot набор структурированных артефактов: ТЗ, домен, архитектуру, план батчей, pipeline в JSON/YAML, и только потом подключаем «строителя кода». Это вот здесь: https://habr.com/ru/articles/972648/

      Так что ваше «пусть модель сначала описывает структуру/изменения в JSON, а потом кодит» — это очень в том же духе, просто я раскладываю это на несколько файлов и этапов вместо одного большого JSON.


    1. Bardakan
      06.12.2025 11:56

      сколько токенов у вас уходит на то, чтобы ИИ сделал работу этого скрипта за вас?


      1. zabarov Автор
        06.12.2025 11:56

        Сам скрипт как раз работает без участия ИИ и без токенов. Это обычный PHP: он локально проходит по файловой системе и сохраняет срез проекта в JSON/JSONL.

        Модель подключается уже на следующем шаге, когда я готовый снимок передаю в чат. Чат у меня по подписке, обычно использую gpt-5.1 thinking (extended) — её хватает, чтобы спокойно переваривать довольно большие объёмы кода.

        То есть ИИ не «делает работу скрипта». Наоборот: скрипт снимает рутину по обходу файлов, чтобы токены тратились уже на анализ и планирование, а не на то, что проще и дешевле сделать на стороне PHP.


        1. Bardakan
          06.12.2025 11:56

          ничего не понял. Человек предлагает работу вашего скрипта заменить на запрос к нейросети. Я спрашиваю, сколько на это понадобится токенов, а вы пишете так, как будто это моя идея была использовать нейросети


          1. zabarov Автор
            06.12.2025 11:56

            Кажется, я ваш вопрос в прошлый раз немного не так понял, сорри.

            Если речь про вариант "вообще не писать скрипт, а просить нейросеть самой пройтись по проекту и собрать JSON", то я так просто не делаю из-за большого расхода токенов, поэтому прям точных цифр у меня нет. Я как раз пошёл от обратного: локальный PHP-снимок без токенов, а уже потом ИИ для анализа.

            Если вы имели в виду что-то другое, напишите, пожалуйста, чуть точнее, чтобы я ответил по делу.


            1. Bardakan
              06.12.2025 11:56

              нет, теперь вы все правильно поняли. Спасибо за информацию


  1. needsomedata
    06.12.2025 11:56

    Так, идея хорошая. Применима когда внутренний проектный индекс вацбкодера не справляется.

    Но обычно они неплохо работает в этом направлении.

    1) Будут ли сравнения?

    2) Будет ли плагин для популярных IDE?


    1. zabarov Автор
      06.12.2025 11:56

      Спасибо за вопросы.

      У меня сейчас два разных сценария вайб-кодинга. В первом — работа через VS Code и агентов Копилота, там дополнительный скрипт не нужен: агенты и так видят проект и работают по своим правилам. Про это у меня уже есть отдельная статья: https://habr.com/ru/articles/972648/.

      Во втором сценарии я разделяю роли: GPT в браузере разбирает архитектуру, формулирует ТЗ и план действий, а Codex в VS Code этот план уже реализует. Codex видит репозиторий, а вот GPT нужно как-то дать такой же контекст — здесь как раз пригождается scan2json, который превращает проект в JSON/JSONL и становится «мостиком» между GPT (планирует) и Codex (пишет код по ТЗ).

      1. Сравнения с «чистым» IDE-подходом как раз планирую вынести в отдельную статью по связке GPT + Codex, там будет больше практики именно в этом разрезе.

      2. Отдельный плагин для популярных IDE пока не планирую: сами IDE-помощники (Copilot, Codex и т.п.) хорошо закрывают сторону «видеть код и помогать писать». Задача scan2json другая — дать внешний переносимый снимок проекта, с которым удобно работать уже вне IDE (GPT, свои сервисы, RAG и т.д.), поэтому поверх существующих плагинов городить ещё один не вижу большого смысла.


  1. kai
    06.12.2025 11:56

    Чем это лучше, чем repomix?


    1. zabarov Автор
      06.12.2025 11:56

      Хороший вопрос, я бы сказал, что это не "лучше", а просто под другой стек и сценарий.

      repomix классный, если живешь в мире git + Node + CLI, и нужен инструмент "упаковать репозиторий для ИИ".

      У меня немного другой контекст - мы делаем готовые веб-решения на Bitrix и Laravel и сознательно живем в php-стеке без Node/SSR. Частый кейс - прод или стейджинг, где есть только php и браузер, без node, без удобного терминала.

      Под это я и делал scan2json:

      • это обычный php-скрипт, который можно закинуть прямо на сервер и снять снимок именно "живого" проекта, а не только того, что лежит в git

      • управляется через веб-интерфейс - можно выбрать корень, отрезать лишние папки, скачать json/jsonl, не заходя в консоль

      • плюс есть обратная сторона с restore.php - можно из снимка собрать отдельную копию модуля или проекта для экспериментов или передачи подрядчику

      То есть если у вас уже выстроен процесс вокруг repomix и Node - вообще ок, он решает свою задачу. scan2json я делал под другой мир - php/Bitrix/Laravel без Node, когда нужно снять и отдать срез кода прямо с сервера через браузер.


  1. vmkazakoff
    06.12.2025 11:56

    Что-то мне кажется, что лучше так не делать. Безопасность, это во первых. У вас даже защиты от брутфорса нет, я молчу про двухфакторку и всякие otp ... Но это оставим в стороне, кого я тут лечить собрался.

    Во всех ide уже есть решение вашей проблемы. Любая система, когда вы откроете проект и скажете "давай поменяем класс Х" или "давай передаём компонент У" сама grep'нет по всему проекту упоминания класса. А если у вас прямо в проекте есть файл agents.md, то ещё и поймет по какому принципу с вашим кодом работать. А если есть ещё и документация в md файлах... ой ладно, совсем я размечтался...

    В общем то что агенты умеют делать автоматически, вы зачем-то превратили в ручную работу. То, что есть скрипт, который не облегчает - хорошо, но всё-таки лучше использовать именно агентский подход.

    Мой совет:

    • Фронт, бэк, бд, очереди, докерфайлы... Это все должно быть одним проектом, даже если деплоится все совершенно по отдельности.

    • Документация должна быть. И быть актуальной. И актуализироваться после любого изменения кода. Обычно это кучка md файлов как в корне проекта, так и в отдельных его частях. От первого readme до последнего описания структуры какой-то таблички должны быть ссылки, чтобы агент понял, какой файл читать перед внесением изменений.

    • Файл agents.md очень важен. Вот прям в разы улучшает ответы. Без него 4 раза из 5 ИИ может отдать полную дичь, и на 5й раз что-то, что уже есть смысл допиливать ручками. С ним 4 раза из 5 отдаст что-то что можно допиливать, а 1 раз может и вообще отдать годный код который не требует полировки. Сильно зависит от кода, размера задачи, промпта, так что цифры условные, разумеется.


    1. zabarov Автор
      06.12.2025 11:56

      Спасибо за развёрнутый коммент, реально есть с чем согласиться.

      По безопасности: этот скрипт я вообще не подразумеваю как штуку "повесили на прод и пусть все ходят". В реальной жизни я им пользуюсь на локалке или на сервере разработки. На боевых проектах не запускаю. Плюс там есть защита от совсем уж классического косяка: с паролем по умолчанию авторизоваться нельзя, он просто не пустит, пока не поменяете. Для битрикс-проектов ещё и используется стандартная авторизация Битрикса, то есть сам скрипт доступен только админам. А дальше уже по ситуации можно хоть за VPN его прятать, хоть под http-auth.

      Про IDE/агентов я с вами в целом не спорю. В идеальном мире, который вы описываете, я тоже за то, чтобы был один проект, нормальная структура, живая дока в md и agents.md, а Copilot/Cursor всё это видел и сам грепал. Под такой сценарий у меня есть отдельная линия статей и репозиторий с workspace и кастомными агентами.

      scan2json решает другую, более приземлённую задачу. Мы много работаем с php-проектами (Bitrix, Laravel) в окружениях без Node и без нормального CLI, где до "агентского рая" ещё далеко, а вот живой код на сервере уже есть. В таких случаях удобно один раз "щёлкнуть" проект этим скриптом, получить JSON/JSONL со срезом именно того, что реально крутится, и уже этот снимок отдать GPT/агентам/своим сервисам. То есть он не заменяет автоматизм агентов, а даёт им сырьё там, где никакого agents.md и репомикса пока просто нет.


  1. andylab
    06.12.2025 11:56

    Автор, попробуй Claude Code, вряд ли что то лучше него сейчас есть


    1. zabarov Автор
      06.12.2025 11:56

      Я пробовал Claude Code, да, он вполне ок и местами, возможно, даже ощущается поудобнее.

      Но у меня сейчас всё крутится вокруг продуктов OpenAI: корпоративный тариф уже оформлен, настроена куча ассистентов, есть обвязка под проекты, интеграции, свой опыт работы именно с их стеком. В такой ситуации брать ещё отдельную подписку под Claude Code, чтобы по сути дублировать те же сценарии в другом интерфейсе, я для себя смысла не вижу.

      Скорее углубляюсь дальше в экосистему OpenAI – assistants, инструменты, интеграцию во внутренние процессы – чем развожу зоопарк из нескольких платных решений, которые делают примерно одно и то же. Но если человек живёт в антропиковском стеке, то для него Claude Code, скорее всего, и правда будет самым удобным вариантом.