Graphify: превращаем код и конфиги в граф знаний
Graphify превращает код, документацию, SQL-схемы и PDF в запрашиваемый граф знаний. Локальный парсинг AST без векторного хранилища для Claude Code и Cursor.
Что делает Graphify и зачем он инженеру
Что делает Graphify и зачем он инженеру
Graphify превращает код, документацию, SQL-схемы и PDF в запрашиваемый граф знаний. От обычного векторного поиска его отличает отсутствие эмбеддингов и векторной базы — парсинг идёт локально через AST, а результат отдаётся в Claude Code или Cursor как контекст для AI-агентов.
С практической точки зрения это значит, что вместо того чтобы кормить модель фрагментами кода по принципу «ближайший по косинусу», мы даём ей связанную структуру: зависимости между файлами, вызовы функций, связи таблиц в базе данных, ссылки в документации.
От репозитория к графу: как работает парсинг
Graphify обходит репозиторий, определяет язык каждого файла и строит абстрактное синтаксическое дерево (AST). Для Python используется встроенный модуль ast, для TypeScript — парсер на базе TypeScript compiler API, для SQL — отдельный парсер схем. Результат не сохраняется в векторное хранилище, а складывается в граф: узлы — это файлы, классы, функции, таблицы, поля; рёбра — вызовы, импорты, внешние ключи, ссылки.
Пример. Допустим, в репозитории есть простой сервис на Python:
python# services/users.py
from database import SessionLocal
from models import User
def get_user_by_email(email: str):
db = SessionLocal()
return db.query(User).filter(User.email == email).first()
Graphify распарсит этот файл, выделит функцию get_user_by_email, увидит импорт SessionLocal из database и User из models, и свяжет узел функции с узлами этих модулей. Если в другом файле есть вызов get_user_by_email, в графе появится ребро между ними.
Потом граф можно экспортировать в формат, который понимают Claude Code и Cursor — например, JSON с узлами и рёбрами, или загрузить в локальную графовую базу, если нужно что-то более тяжёлое. Базовый вариант работает без внешней базы данных.
Почему не нужна векторная база
Векторные базы решают задачу семантического поиска: найти фрагмент текста, который «по смыслу» близко к запросу. Проблема в том, что семантика не равна структуре. Модель может найти функцию, которая упоминает «email», но не поймёт, что эта функция вызывается из трёх других мест и зависит от конкретной таблицы в базе данных.
С графом всё иначе. Если спросить Claude Code: «где используется функция get_user_by_email?», агент ходит по рёбрам графа, а не угадывает по эмбеддингам. Это даёт предсказуемость: ответ не плавает в зависимости от того, как модель настроена сегодня утром.
Во-первых, векторная база требует индексации, хранения эмбеддингов и переиндексации при изменении кода. Во-вторых, она не показывает связи между сущностями — только близость по тексту. В-третьих, для локальной работы на ноутбуке векторная база — лишний вес: она потребляет много оперативной памяти и требует отдельного сервиса.
Graphify обходится без этого. Парсинг идёт локально, результат — обычный файл или встроенная графовая база, которую можно коммитить в репозиторий вместе с кодом.
Код проекта открыт: Graphify-Labs/graphify: Кодовая база в запросную графическую базу знаний.
Для сравнения с другими инструментами для агентов можно почитать про QA-агенты Momentic ищут баги в веб и мобильных приложениях и про ECC: оптимизация и безопасность агентных оболочек.
Установка и первый запуск /graphify
Установка и первый запуск /graphify
Код растёт быстрее, чем успевает расти документация. Через полгода никто не помнит, зачем в сервисе оплаты есть отдельный репозиторий с миграциями, а схема базы данных размазана по десяти SQL-файлам. Новый разработчик тратит первые две недели на то, чтобы просто найти, где лежит описание API. Graphify решает это иначе, чем обычно делают AI-инструменты: он не ведёт векторное хранилище и не перекладывает ваш код в облако. Локальный парсер обходит AST, вытягивает связи между функциями, таблицами и конфигами, и складывает всё в запрашиваемый граф. Для Claude Code и Cursor это означает, что агент может спросить «где описывается схема пользователей» и получить точный ответ с путями к файлам, а не вероятностное угадывание. Подробнее о концепции можно прочитать в обзоре кодовой базы Graphify-Labs/graphify.
Установить Graphify можно одной командой. Я предпочитаю собирать из исходников, но бинарник тоже есть в релизах.
bashcargo install graphify-cli graphify --version graphify init ./my-project
После init в корне проекта появится файл graphify.yaml. Это единственный конфиг, который нужно править руками — GUI для тех, кто не знает, где лежит конфиг.
yaml# graphify.yaml
project: my-project
roots:
- ./src
- ./sql
- ./docs
parsers:
- rust
- typescript
- sql
- markdown
exclude:
- target/
- node_modules/
- *.lock
output:
path: ./graphify.db
format: sqlite
Во-первых, укажите в roots все директории, которые стоит индексировать. Во-вторых, добавьте в exclude всё, что не несёт смысловой нагрузки — иначе граф раздуется от сгенерированного кода. С практической точки зрения, достаточно одного запуска graphify build, чтобы получить первый снимок состояния репозитория.
bashgraphify build
Подключение навыка в Claude Code, Cursor и Codex
Graphify отдаёт данные через MCP (Model Context Protocol), поэтому подключение сводится к добавлению одного сервера в конфигурацию IDE или агента.
Claude Code
В файле ~/.claude.json (или .mcp.json в корне проекта) добавьте запись:
json{
"mcpServers": {
"graphify": {
"command": "graphify",
"args": ["mcp", "--db", "./graphify.db"]
}
}
}
После перезапуска Claude Code навык станет доступен под именем graphify. Агент сам решит, когда к нему обращаться, но вы можете явно вызвать его в запросе.
Cursor
Откройте Настройки → MCP Servers → Add new server. Укажите команду и аргументы, как в примере выше. Cursor подхватит сервер без перезапуска окна.
Codex
Для Codex конфиг лежит в ~/.codex/config.toml:
toml[mcp.servers.graphify]
command = "graphify"
args = ["mcp", "--db", "./graphify.db"]
Если вы используете Codex в терминале, убедитесь, что переменная окружения CODEX_MCP_ENABLED=1 выставлена, иначе навык не подхватится.
Первый запрос к кодовой базе
Теперь можно спросить у агента что-то конкретное. Не «расскажи про проект», а именно то, что обычно требует чтения десяти файлов.
В Claude Code:
@graphify найди, где описывается схема таблицы пользователей и какие сервисы от неё зависят
Агент обойдёт граф, найдёт SQL-определение, связанные ORM-модели и эндпоинты, и выдаст ответ со ссылками на файлы и номерами строк.
В Cursor достаточно выделить фрагмент кода и спросить:
Как эта функция связана с конфигурацией базы данных?
Graphify покажет рёбра между функцией, конфигурационным файлом и миграцией.
Если мы посмотрим на практическую сторону, первый запуск на среднем репозитории занимает от нескольких секунд до пары минут. Граф хранится локально в SQLite, поэтому нет задержек на запросы к внешнему API и нет риска утечки кода. Предсказуемость конфигурации здесь играет ключевую роль: вы точно знаете, какие директории проиндексированы, и можете повторить сборку на любой машине одной командой.
На следующем этапе стоит настроить автоматическое обновление графа при каждом коммите — например, через Git-хук или CI-задачу. Тогда агенты всегда будут работать с актуальной структурой, а не с снимком трёхнедельной давности.
Как Graphify объясняет связи между файлами
Как Graphify объясняет связи между файлами
Когда открываешь проект, которым не пользовался полгода, нужно не угадывание семантической близости, а точный ответ: какой файл импортирует какой, какая таблица фигурирует в запросе, какой ключ конфига управляет каким сервисом. Graphify строит именно такой граф — локально, через разбор AST, без векторного хранилища. Для Claude Code и Cursor это значит, что агент получает предсказуемую карту зависимостей, а не вероятностное приближение.
AST-разбор и детерминизм
Graphify обходит дерево файлов, парсит исходный код в абстрактное синтаксическое дерево и извлекает из него узлы и рёбра. Узел — это файл, функция, класс, таблица или ключ конфига. Ребро — связь между ними: импорт, вызов, ссылка на таблицу, обращение к переменной окружения.
Главное отличие от векторных подходов — детерминизм. Один и тот же набор файлов всегда даёт одинаковый граф. Если ты изменишь одну строку импорта, пересчитается только затронутое ребро, а не весь индекс эмбеддингов. Для ИИ-агентов это критично — как и для QA-агентов Momentic, которым нужна точная карта приложения, а не предположения. Claude Code или Cursor могут доверять результату запроса, потому что он не «плывёт» от переобучения модели.
Пример. Возьмём простой Python-файл:
python# services/users.py
from database import SessionLocal
from models.user import User
def get_user(user_id: int):
db = SessionLocal()
return db.query(User).filter(User.id == user_id).first()
Graphify зафиксирует три ребра из этого файла:
services/users.py→database(импортSessionLocal);services/users.py→models.user(импортUser);services/users.py→User(использование в запросе).
Никаких эмбеддингов, никакого угадывания. Если завтра переименуешь User в Client, граф обновится детерминированно, и агент сразу увидит, где именно нужно поправить код.
Примеры рёбер: импорты, SQL, конфиги
Graphify выделяет три типа связей, которые на практике объясняют архитектуру проекта лучше любого README.
Импорты. Это базовое ребро между модулями. Graphify понимает import и require в разных языках и показывает, кто от кого зависит.
typescript// src/api.ts
import { createClient } from './db/client';
import { config } from '../config/env';
Здесь два ребра: src/api.ts зависит от src/db/client и от src/config/env. Если агент спрашивает «где инициализируется клиент БД?», ответ — конкретный файл, а не похожий по смыслу фрагмент.
SQL. Graphify парсит SQL-строки и файлы миграций, выделяет имена таблиц и соединяет их с кодом, который эти таблицы использует.
sqlSELECT id, email FROM orders WHERE user_id = $1 AND status = 'paid';
Результат в графе: файл с этим запросом связан с таблицей orders. Если ты планируешь переименовать таблицу, достаточно обойти все рёбра, выходящие из узла orders, и увидишь список файлов для правки.
Конфиги. YAML, JSON, .env — тоже узлы графа. Graphify связывает конфигурацию с кодом, который её читает, и с сервисами, которые от неё зависят.
yaml# docker-compose.yml
services:
api:
image: myapp/api:latest
environment:
- DATABASE_URL=postgres://graphify:password@db:5432/graphify
- LOG_LEVEL=debug
Ребро из docker-compose.yml ведёт к ключу DATABASE_URL, а из кода — к месту, где этот ключ считывается через os.getenv или аналоги. С практической точки зрения, это позволяет ответить на вопрос «какие переменные окружения критичны для API?» без чтения всего репозитория.
Если мы посмотрим на граф целиком, получится карта, где код, схема базы и конфигурация связаны явно. Для Claude Code и Cursor это значит, что агент может переходить по рёбрам от таблицы к файлу, от файла к конфигу и обратно — и всё это работает локально, без отправки кода во внешнее векторное хранилище. Подробнее про кодовую базу проекта можно посмотреть в репозитории Graphify-Labs/graphify.
Ограничения и когда подход перестаёт работать
Graphify строит граф по статическому анализу исходников. Это даёт предсказуемость: вы знаете, какие узлы и рёбра получите, и можете проверить результат вручную. Но статический анализ не видит того, что появляется только в рантайме.
Graphify-Labs/graphify: Кодовая база в запросную графическую базу знаний
Что не попадает в граф
Во-первых, парсер AST работает с исходным кодом, а не с поведением программы. Если в коде есть динамический импорт, граф покажет только вызов функции, но не то, какой модуль загрузится в итоге.
pythonimport importlib
import os
provider_name = os.environ.get("PAYMENT_PROVIDER", "stripe")
module = importlib.import_module(f"providers.{provider_name}")
provider = module.Provider()
Graphify зафиксирует узел import_module и ребро к строке с os.environ, но не разрешит providers.stripe или providers.paypal. С практической точки зрения, это значит, что зависимости, выбираемые через переменные окружения, остаются невидимыми.
Во-вторых, декларативная инфраструктура не попадает в граф кода. Kubernetes-манифесты, Helm-чарты, Ansible-инвентари — это не AST в привычном смысле. Graphify может распарсить YAML как текст, но не поймёт, что {{ .Values.image.tag }} ссылается на конкретный образ в конкретном реестре.
yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: payments
spec:
template:
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
Здесь граф не покажет, какой секрет реально лежит в db-credentials, и с каким кластером БД приложение соединится в продакшене. У меня на домашнем сервере «Винни-Пух» такое вылезало постоянно: в графе всё выглядит связно, а в рантайме приложение не может достучаться до БД, потому что сетевая политика или секрет подтягиваются извне.
В-третьих, семантический разрыв. AST знает, что функция calculate_vat вызывает round, но не знает, что она реализует начисление НДС для ЕС. Комментарии, документация в docstring и бизнес-контекст из PDF не превращаются в рёбра графа автоматически. Если логика описана только в словах, граф будет пустым в этом месте.
Наконец, минифицированный код, обфусцированные скрипты и бинарные файлы не дают ничего полезного. Парсер либо пропустит их, либо построит нечитаемый граф из тысяч безымянных функций.
Альтернативы и комбинация с векторным поиском
Если статический граф не отвечает на вопрос «как это работает?», стоит добавить векторный поиск. Эмбеддинги ищут по смыслу, а не по структуре: запрос «где описана логика начисления налогов?» найдёт релевантные фрагменты даже без точного совпадения имён функций.
С практической точки зрения, лучше использовать гибрид:
- Граф — для структурных вопросов: кто вызывает эту функцию, какие таблицы затрагивает миграция, откуда берётся переменная окружения.
- Векторный поиск — для семантических вопросов: как реализована оплата, где описана бизнес-логика скидок, что делает этот микросервис.
Для Claude Code и Cursor это выглядит так: вы даёте агенту доступ и к графу зависимостей, и к векторному индексу документации. Агент сам решает, какой инструмент использовать. Если нужно понять, не сломает ли изменение сигнатуры функции смежные сервисы, он идёт в граф. Если нужно разобраться, почему расчёт налога даёт не ту сумму, — ищет по эмбеддингам в документации и коммитах.
Если мы посмотрим на архитектуру агента, то увидим, что векторный поиск не заменяет граф, и наоборот. Эмбеддинги могут выдать релевантный, но устаревший фрагмент кода, а граф покажет актуальные зависимости, но не объяснит намерение автора. Я видел, как команды пытались заменить один другим и получали ложные срабатывания: агент находил похожую функцию в другом микросервисе и предлагал скопировать её, не зная, что в оригинале есть критичное условие по обработке пустых значений.
Если вы уже используете агентные оболочки в роде Claude Code, стоит посмотреть в сторону ECC: оптимизация и безопасность агентных оболочек — там разобрано, как ограничить доступ агента к файловой системе, чтобы он не случайно изменил конфиг, которого не должен трогать.
Для поиска багов в уже работающем приложении статический анализ беспомощен. Лучше подключить что-то в роде QA-агентов Momentic ищут баги в веб и мобильных приложениях, которые наблюдают за приложением в рантайме, а не только читают исходники.
Вывод простой: Graphify даёт предсказуемую карту кода, но карта не местность. Если вам нужно понять, что делает программа в реальности, добавьте векторный поиск и инструменты рантаймового анализа. Граф остаётся основой, а векторное хранилище — дополнением, которое закрывает слепые зоны статического парсинга.
Часто задаваемые вопросы
Чем Graphify отличается от векторного поиска в редакторе?
Векторный поиск ищет фрагменты по близости эмбеддингов, а Graphify строит реальные связи между узлами: импорты, вызовы функций, внешние ключи. С практической точки зрения это значит, что вы получаете не «похожий» кусок кода, а точную зависимость. Если нужно понять, зачем в репозитории существует тот или иной модуль, граф покажет это без гаданий на косинусное сходство.
Нужно ли разворачивать графовую базу данных?
Не обязательно. Graphify может отдать результат в виде JSON с узлами и рёбрами, который Claude Code или Cursor подхватят как контекст. Если хотите хранить граф надолго и запрашивать его повторно — тогда имеет смысл загрузить в локальную графовую базу, но для разовой работы с кодом этого не требуется.
Какие языки и форматы поддерживает Graphify?
На данный момент парсит Python через встроенный модуль ast, TypeScript через TypeScript compiler API, а также SQL-схемы и PDF. Узлами становятся файлы, классы, функции, таблицы и поля, а рёбрами — импорты, вызовы, внешние ключи и ссылки. Если ваш стек выходит за эти рамки, придётся подождать добавления новых парсеров или написать свой.
Безопасно ли использовать Graphify с закрытым кодом?
Да, потому что парсинг идёт локально на вашей машине, а код не отправляется ни в какое облако. Граф остаётся у вас, и вы сами решаете, какую часть отдать в Claude Code или Cursor. С точки зрения конфиденциальности это предсказуемее, чем отдавать репозиторий на обработку стороннему сервису.
Как Graphify попадает в Claude Code и Cursor?
Graphify экспортирует граф в JSON с узлами и рёбрами, и этот файл подключается как контекст для AI-агента. Модель видит не разрозненные фрагменты, а связанную структуру репозитория: от вызова функции до определения таблицы в базе. Так агент может отвечать на вопросы про архитектуру, не теряя контекста между файлами.