Есть паттерн, который видит каждый, кто работает с агентами: первые 5–15 минут уходят не на задачу, а на "ориентацию". Где точка входа? Откуда растут зависимости? Почему эта библиотека, а не другая? Кто считает это публичным API? В маленьком проекте раздражает. В большом — превращается в постоянный налог на токены и внимание.
DSP (Data Structure Protocol) "выносит карту проекта наружу" — в простой, версионируемый, языковой граф, который живёт рядом с кодом и доступен агенту как постоянная память.
k-kolomeitsev/data-structure-protocol
Цель в архитектуре сформулирована так:
1) Цель и границы
Цель DSP — хранить минимальный, но достаточный контекст о репозитории/системе артефактов в виде графа «сущности → зависимости/публичный API», чтобы LLM могла:
- быстро находить нужные фрагменты по UID,
- понимать «зачем» сущности существуют и «как» они связаны,
- не требовать загрузки исходников целиком в контекстное окно.
DSP — это долговременная память и индекс проекта для LLM. Агент может в любой момент выполнить поиск (grep) по проекту, найти нужные сущности по описаниям/ключевым словам и от найденного UID раскрутить весь граф связей: входящие зависимости, исходящие импорты, реципиентов через exports. Это заменяет необходимость «помнить» структуру проекта или загружать его целиком — вся карта проекта всегда доступна через .dsp.
DSP = граф сущностей + причины связей
DSP хранится в каталоге .dsp/. Каждая "сущность" (entity) получает стабильный UID и небольшой набор файлов:
description: где находится (source), что это (kind), зачем существует (purpose).
imports: кого эта сущность использует (UID-ссылки).
shared: что она выставляет как публичный API (экспорты).
exports/: обратный индекс — кто импортирует эту сущность и зачем (текст why рядом с потребителями).
В больших системах особенно важна одна деталь: DSP фиксирует не только "что зависит от чего", но и почему. Это резко снижает количество догадок в задачах рефакторинга, миграций и удаления легаси.
Сущностей всего два базовых типа
Object: модуль/файл/класс/конфиг/ресурс/внешняя зависимость — "всё, что не функция".
Function: функция/метод/хэндлер/пайплайн.
Отдельный плюс: DSP язык-агностичен. Он одинаково работает с TS/JS, Python, Go, инфраструктурными YAML, SQL, ассетами и так далее. Причём в архитектуре прямо прописана "полнота импортов": если что-то импортируется — оно должно существовать в .dsp, включая стили, картинки, JSON, wasm и прочие артефакты. Это важнее, чем кажется: агенты чаще теряют не код, а именно ресурсные зависимости.
DSP строится на идентичности по UID, а не по пути. Путь — это атрибут. UID — это "личность" сущности.
Переименовали файл → делаете move-entity, UID остаётся прежним.
Переставили код / отформатировали → UID прежний.
UID меняется только когда меняется назначение (semantic identity): модуль реально стал про другое.
Чтобы привязать UID к сущностям внутри файла (экспортируемым функциям/классам), используется простой маркер-комментарий @dsp <uid> прямо в исходнике. Прагматичное решение: не зависит от строк, работает в любом языке, ищется grep'ом.
Типичный цикл работы агента в DSP-проекте выглядит так:
Найти сущность: search по ключевым словам или find-by-source по пути файла.
Понять границы: прочитать description, shared, imports.
Собрать контекст пакетами: вместо "давай весь репозиторий" агент подтягивает только нужные узлы и 1–2 уровня зависимостей.
Оценить влияние: кто потребляет сущность и зачем (get-parents / get-recipients), есть ли циклы, есть ли "сироты".
Примеры команд (в PowerShell-стиле; CLI поставляется внутри скилла):
python .\.cursor\skills\data-structure-protocol\scripts\dsp-cli.py --root . search "авторизация" python .\.cursor\skills\data-structure-protocol\scripts\dsp-cli.py --root . get-entity obj-a1b2c3d4 python .\.cursor\skills\data-structure-protocol\scripts\dsp-cli.py --root . get-children obj-a1b2c3d4 --depth 2 python .\.cursor\skills\data-structure-protocol\scripts\dsp-cli.py --root . get-recipients obj-a1b2c3d4 python .\.cursor\skills\data-structure-protocol\scripts\dsp-cli.py --root . get-path obj-a1b2c3d4 func-7f3a9c12
Архитектура DSP — это правила. Но агент без дисциплины легко их нарушает: лезет в код наугад, тащит полрепо в контекст, не обновляет индекс, ломает целостность графа.
Скилл закрывает именно операционную часть:
Вшивает Agent Prompt: "перед изменением — найди сущности; при создании — зарегистрируй; при импорте — добавь why; при удалении — сделай каскадную очистку".
Даёт справочники в references/: формат хранения, bootstrap-алгоритм (DFS от entrypoint'ов), семантика операций.
Поставляет production-ready CLI scripts/dsp-cli.py, который реализует операции из ARCHITECTURE.md и умеет навигацию/диагностику (cycles/orphans/stats).
DSP становится не "документом", а живым контрактом, который агент исполняет в ходе работы — и поддерживает консистентность .dsp без ручного вмешательства.
Да. Первичный bootstrap на большом репозитории стоит дорого — временем, вниманием и токенами.
Почему:
Нужно определить root entrypoint'ы (а в монорепо их много).
Нужно пройти зависимости в глубину (DFS), зафиксировать все достижимые модули/файлы/ресурсы.
Для каждого узла нужно написать минимальное, но точное purpose.
Нужно дисциплинированно заполнить причины (why) для связей импорта — иначе половина ценности DSP пропадает.
Иногда нужно проставить @dsp маркеры в исходниках для экспортируемых сущностей (чтобы UID был "якорем" в коде).
На больших системах это реально может быть отдельным мини-проектом.
Ценность DSP не в "красивой структуре". Она в экономике работы агентов:
Меньше токенов на ориентацию: вместо повторного "прогрева" контекста агент читает короткие description/imports/shared/exports и берёт ровно те файлы, которые нужно менять.
Контекст не растворяется между задачами: .dsp — это внешняя память, не зависящая от текущего окна контекста и настроения модели.
Быстрый поиск по смыслу: search находит сущности по ключевым словам, а exports/ отвечает на вопрос "зачем это тут вообще".
Рефакторинг становится безопаснее: impact analysis дешевеет — быстро получаешь всех реципиентов сущности и проходишься по ним точечно.
Внешние зависимости прозрачны: внешние пакеты фиксируются как kind: external, не раздувая граф, но остаются навигируемыми через exports index.
И важная вещь из архитектуры — контроль гранулярности, чтобы DSP не превратился в свалку:
10) Гранулярность и политика минимального контекста
- Полнота по файлам, но не по коду внутри файла. «Полнота импортов» (раздел 2) означает, что каждый файл/модуль, который импортируется в проекте, должен иметь Object в .dsp. Это про файлы и модули — не про каждую переменную внутри файла. Внутри одного файла отдельный UID получает только та сущность, которая шарится наружу (shared) или используется из нескольких мест. Локальные переменные, внутренние хелперы, приватные поля — остаются частью родительского Object, без собственного UID. Если гранулярность растёт — что-то делается не так.
- Обновление реципиентов — через exports. Для обновления библиотеки/модуля/символа достаточно открыть exports импортируемой сущности и получить список импортёров (реципиентов) по UID, а затем точечно обновить их.
- Отслеживание изменений. По git diff видно, что поменялось — создался новый файл, изменилась функция или объект. Изменённые файлы отдаются в LLM для обновления DSP. Изменения внутри функций зачастую не требуют обновления DSP, потому что описание фиксирует назначение, а не детали реализации — если только не добавились/убрались импорты.
Именно это делает DSP жизнеспособным на дистанции: индекс остаётся компактным, обновления — редкими и осмысленными.
Большие монолиты и монорепо, где контекст "не влезает никогда".
Долгоживущие продукты, где агенты будут работать месяцы и годы, а не один спринт.
Команды, которые часто делают рефакторинги/миграции/замены зависимостей.
Проекты со сложной ресурсной частью (ассеты/конфиги/генерация), которую агентам трудно держать в голове.
DSP — это попытка сделать для LLM-агентов то, что люди давно делают неформально: держать в голове карту системы. Только вместо головы — граф на диске, вместо "я так помню" — минимальные описания, связи и причины, вместо "прочитай весь проект" — точечная навигация от entrypoint'ов.
Да, бутстрап на большом проекте будет дорогим. Но если вы реально планируете использовать агентов системно, эта цена обычно возвращается через:
меньше токенов на ориентацию,
меньше потерь контекста между задачами,
более быстрый поиск нужных модулей/зависимостей,
более предсказуемое выполнение задач (особенно рефакторинговых).
Источник


