Graphify: код, документация и PDF в граф знаний
Локальный парсинг кода, SQL-схем и PDF без векторной базы. Graphify строит граф знаний для Claude Code, Cursor, Codex и Gemini CLI.
Что такое Graphify и зачем он нужен
Что такое Graphify и зачем он нужен
Graphify — локальный инструмент для построения графа знаний из исходного кода, SQL-схем и PDF-документов. Он не использует векторную базу, а работает с абстрактным синтаксическим деревом (AST) и прямыми связями между сущностями. Результат можно отдавать в Claude Code, Cursor, Codex или Gemini CLI, чтобы ИИ-агент видел не только отдельные файлы, но и зависимости между ними.
Когда я в первый раз подключил Claude Code к большому репозиторию, модель «не видела» связи между файлами. Она знала, что функция существует, но не знала, какая таблица в PostgreSQL за ней стоит, или какой раздел PDF-регламента описывает её поведение. Graphify решает эту задачу: строит граф, где узлы — функции, классы, таблицы и разделы документов, а рёбра — вызовы, импорты, внешние ключи и ссылки.
Почему поиск по коду перестал справляться
Во-первых, обычный текстовый поиск (grep, ripgrep) находит совпадения по строке, но не понимает семантику. Если вы ищете calculate_tax, вы найдёте определение и вызовы, но не узнаете, какие поля из SQL-схемы участвуют в расчёте, или какой раздел PDF-инструкции регламентирует ставку НДС.
Во-вторых, векторные базы пытаются решить проблему семантическим поиском, но добавляют сложность: нужна модель эмбеддингов, индексация, переобучение при изменении кода. В больших монорепо это превращается в отдельный инфраструктурный проект с собственными проблемами актуальности данных.
Пример из практики. В одном проекте на Python с десятком микросервисов разработчики тратили по 15–20 минут на поиск того, кто вызывает устаревший эндпоинт. ripgrep находил все вхождения, но не различал реальный вызов и упоминание в комментарии. Векторный поиск выдавал «похожие» функции, но не показывал цепочку зависимостей до базы данных.
Graphify не заменяет ripgrep, он добавляет слой связей поверх кода. Вы получаете не просто список файлов, а граф: функция A вызывает функцию B, которая читает таблицу C, описанную в разделе D PDF-документа.
Что получается на выходе
На выходе Graphify формирует граф знаний в формате, понятном ИИ-агентам. Узлы — это сущности кода и документов, рёбра — их отношения. Можно экспортировать в JSON, GraphML или подключить напрямую к Claude Code через CLAUDE.md.
Пример конфигурации Graphify:
yamlgraphify:
version: "1"
sources:
- path: ./src
parser: python-ast
include:
- "*.py"
- path: ./sql
parser: sql-schema
include:
- "*.sql"
- path: ./docs
parser: pdf
include:
- "*.pdf"
output:
format: json
path: ./knowledge-graph.json
ai_integration:
- claude-code
- cursor
Запуск выглядит предсказуемо:
bashgraphify build --config graphify.yaml --output ./knowledge-graph.json
После этого в CLAUDE.md для Claude Code можно добавить ссылку на граф, и модель будет учитывать связи между файлами при генерации кода. Например, если вы просите добавить новое поле в таблицу, Claude Code увидит все функции, которые с этой таблицей работают, и предложит обновить их сразу, а не только одну.
Если вы уже работаете с ИИ-агентами, стоит посмотреть, как настраивать CLAUDE.md для Claude Code по Карпати и какие навыки для агентов можно подключить поверх графа Graphify.
Как Graphify строит граф знаний
Детерминистичный парсинг AST без векторной базы
Graphify не использует векторную базу и не считает эмбеддинги. Вместо этого он парсит исходный код, SQL-схемы и PDF через синтаксическое дерево (AST) и записывает связи напрямую в граф. Это даёт предсказуемость: если ты запустишь парсинг дважды на одних и тех же файлах, получишь идентичный результат. Векторные базы такого не гарантируют — достаточно чуть изменить формулировку в комментарии, и вектор «уплывёт» в другое место пространства.
Во-первых, Graphify берёт файл, определяет его тип по расширению и пропускает через соответствующий парсер. Для Python это ast модуль, для JavaScript — @babel/parser, для SQL — отдельный грамматический парсер, для PDF — извлечение текста и поиск ссылок между документами.
Вот как выглядит запуск парсинга для репозитория с кодом:
bashgraphify parse --path ./my-project \
--include '*.py' \
--include '*.js' \
--include '*.sql' \
--output knowledge-graph.json
Флаг --include задаёт маски файлов, которые нужно обработать. Graphify рекурсивно обходит директорию, пропускает node_modules, .git и другие служебные каталоги. Если нужно добавить свои исключения, правьте конфиг:
yaml# graphify.yaml
parsers:
python:
enabled: true
extract_docstrings: true
extract_type_hints: true
javascript:
enabled: true
jsx: true
sql:
enabled: true
dialect: postgresql
pdf:
enabled: true
extract_toc: true
follow_links: false
exclusions:
- '**/node_modules/**'
- '**/.git/**'
- '**/venv/**'
- '**/__pycache__/**'
С практической точки зрения, детерминистичный парсинг означает, что ты можешь положить результат в Git и отслеживать изменения графа коммитом за коммитом. Если разработчик переименовал функцию, в графе изменится один узел и несколько рёбер — а не половина векторного индекса.
Если мы посмотрим на внутреннее устройство, каждый узел графа получает устойчивый идентификатор на основе хеша содержимого и пути к файлу. Это позволяет Graphify понимать, что src/utils/helpers.py и src/utils/helpers.py после рефакторинга — это всё ещё тот же файл, даже если внутри появились новые классы.
Какие связи попадают в граф
Graphify извлекает три типа сущностей и четыре типа связей между ними. Сущности — это файлы, функции, классы, таблицы SQL, разделы PDF и отдельные абзацы. Связи описывают, как эти сущности зависят друг от друга.
Вот основные типы связей:
- import — один модуль импортирует другой
- call — функция вызывает другую функцию
- defines — файл или класс определяет функцию, метод или константу
- references — документ ссылается на другой документ или раздел
Пример вывода графа в формате JSON:
json{
"nodes": [
{
"id": "file:src/auth.py",
"type": "file",
"label": "src/auth.py",
"language": "python"
},
{
"id": "func:src/auth.py:hash_password",
"type": "function",
"label": "hash_password",
"file": "src/auth.py",
"line": 42
},
{
"id": "func:src/auth.py:verify_token",
"type": "function",
"label": "verify_token",
"file": "src/auth.py",
"line": 78
}
],
"edges": [
{
"from": "file:src/auth.py",
"to": "func:src/auth.py:hash_password",
"type": "defines"
},
{
"from": "func:src/auth.py:verify_token",
"to": "func:src/auth.py:hash_password",
"type": "call"
}
]
}
Для SQL-схем Graphify строит связи между таблицами через внешние ключи. Если в схеме есть таблица orders с полем user_id, ссылающимся на users.id, в графе появится ребро references между этими таблицами. Это полезно, когда нужно понять, какие таблицы затронет изменение в одной из них.
Пример SQL-схемы и того, что Graphify из неё извлечёт:
sql-- schema.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
total NUMERIC(10, 2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending'
);
В графе это отобразится как два узла типа table и одно ребро references от orders к users. Если потом добавить таблицу order_items с внешним ключом на orders, граф разрастётся соответствующим образом, и ты увидишь цепочку зависимостей.
Для PDF Graphify извлекает оглавление и гиперссылки внутри документа. Если в одном PDF есть ссылка на раздел другого PDF, эта связь тоже попадает в граф. Так получается междокументовый граф знаний, который можно скормить Claude Code, Cursor, Codex или Gemini CLI — они будут видеть не только отдельные файлы, но и связи между ними.
Если ты уже используешь CLAUDE.md для настройки Claude Code, Graphify может дополнить его автоматически сгенерированным описанием графа. Подробнее про настройку CLAUDE.md можно почитать в руководстве по Карпати.
Граф знаний без векторной базы — это как бумажная карта вместо GPS: она не подскажет оптимальный маршрут в реальном времени, но ты всегда будешь знать, где именно находится каждый объект и как он связан с остальными. Для анализа кода это часто важнее, чем семантический поиск.
Интеграция с Claude Code, Cursor, Codex и Gemini CLI
Интеграция с Claude Code, Cursor, Codex и Gemini CLI
Graphify парсит исходный код, SQL-схемы и PDF-файлы локально и строит из них ориентированный граф знаний. Векторная база не требуется — граф фиксирует прямые зависимости: вызов функции, импорт модуля, внешний ключ между таблицами. Для Claude Code, Cursor, Codex и Gemini CLI это означает, что ассистент получает не «похожий по смыслу» фрагмент, а реальную архитектуру проекта с путями к файлам и номерами строк.
Навык /graphify для ИИ-ассистентов
Навык /graphify задаёт ассистенту правило: когда пользователь спрашивает о структуре кода или связях между компонентами, использовать Graphify вместо обычного чтения файлов.
Во-первых, для Claude Code навык прописывается в CLAUDE.md. Если вы ещё не настраивали этот файл, посмотрите руководство Настройка CLAUDE.md для Claude Code по Карпати — там описано, как форматировать инструкции для ассистента. Ниже пример блока, который я добавляю в свои проекты:
markdown## Навык /graphify
Когда пользователь спрашивает о связях в коде, структуре модулей или содержимом PDF-документации, вызови Graphify.
Graphify строит граф знаний из локального репозитория без векторной базы. Он парсит:
- исходный код на Python, Go, JavaScript, TypeScript, Rust, C++;
- SQL-схемы (CREATE TABLE, внешние ключи, индексы);
- PDF-документацию (спецификации, инструкции, отчёты).
Возвращай результат в виде списка узлов и рёбер с путями к файлам и номерами строк.
С практической точки зрения, такой навык работает предсказуемее семантического поиска. Векторная база может выдать фрагмент, который «похож» на запрос, но не покажет, что функция process_order в orders.py вызывает validate_payment в payments.py, а та в свою очередь читает таблицу payments из схемы billing. Graphify отобразит эту цепочку явно.
Для Cursor навык описывается в файле правил проекта. Пример конфигурации:
json{
"name": "graphify",
"description": "Построение графа знаний из кода, SQL и PDF",
"command": "graphify query --format json --context $CURSOR_FILE",
"triggers": ["структура", "связь", "зависимость", "pdf", "схема"]
}
Codex и Gemini CLI не требуют отдельного файла навыка — достаточно добавить инструкцию в системный промпт:
Перед ответом на вопросы об архитектуре проекта используй инструмент graphify для анализа репозитория.
Если вы ищете готовые навыки для других ассистентов, репозиторий mattpocock/skills содержит несколько полезных примеров, которые можно адаптировать под Graphify.
Пример запроса и ответ
Пользователь спрашивает:
Как связаны заказы и платежи в нашем коде? Есть ли схема таблицы платежей?
Graphify возвращает граф в формате JSON:
json{
"nodes": [
{
"id": "file:src/orders.py",
"label": "orders.py",
"type": "file",
"path": "src/orders.py"
},
{
"id": "func:process_order",
"label": "process_order",
"type": "function",
"file": "src/orders.py",
"line": 42
},
{
"id": "file:src/payments.py",
"label": "payments.py",
"type": "file",
"path": "src/payments.py"
},
{
"id": "func:validate_payment",
"label": "validate_payment",
"type": "function",
"file": "src/payments.py",
"line": 15
},
{
"id": "table:billing.payments",
"label": "billing.payments",
"type": "sql_table",
"schema": "billing"
}
],
"edges": [
{
"from": "file:src/orders.py",
"to": "file:src/payments.py",
"label": "импортирует"
},
{
"from": "func:process_order",
"to": "func:validate_payment",
"label": "вызывает"
},
{
"from": "func:validate_payment",
"to": "table:billing.payments",
"label": "читает"
}
]
}
Что это значит на практике. Функция process_order из модуля заказов вызывает validate_payment из модуля платежей. Эта функция читает таблицу payments в схеме billing. Если вы меняете структуру таблицы, Graphify покажет, какие именно функции и файлы затронуты — без угадываний и без векторного поиска.
Команда для запуска анализа выглядит так:
bashgraphify parse ./src --include '*.py' --include '*.sql' --include '*.pdf' --output graph.json
graphify query "Как связаны заказы и платежи?" --graph graph.json
Если мы посмотрим на вывод выше, становится ясно: ассистенту не нужно читать весь репозиторий, чтобы ответить на вопрос. Достаточно обойти несколько рёбер в графе. Это и есть предсказуемость, которой не хватает обычному поиску по ключевым словам.
Ограничения, выводы и часто задаваемые вопросы
Ограничения, выводы и часто задаваемые вопросы
Когда подход перестаёт работать
Graphify строит граф знаний локально, без векторной базы. Это его преимущество и одновременно граница. Во‑первых, если вам нужен семантический поиск по смыслу, а не по структуре, граф не поможет. Пример: запрос «как считается налог на добавленную стоимость» не найдёт фрагмент, где слова «налог» и «стоимость» не встречаются вместе, даже если смысл совпадает. Для таких задач подойдёт векторная база, а Graphify лучше использовать как дополнение.
С практической точки зрения, парсинг кода через AST зависит от языка. Поддерживаются основные — Python, JavaScript, TypeScript, Go, Java, C#, Rust — но если в репозитории есть код на редком диалекте или только что вышедшей версии языка, грамматика может не распознать конструкции. Тогда в графе появится «чёрная дыра»: файл есть, а связей нет.
Если мы посмотрим на репозиторий с несколькими сотнями тысяч файлов, локальная индексация превратится в ожидание. Graphify пересчитывает зависимости при каждом изменении, и на больших проектах это заметно замедляет работу. Для таких масштабов лучше индексировать только изменённые пути или разбить репозиторий на модули.
PDF без текстового слоя — ещё одна граница. Graphify не делает OCR, поэтому сканированные счета или договоры он прочитать не сможет. Сначала нужно прогнать файл через tesseract или аналоги, а потом уже скормить Graphify.
SQL‑схемы извлекаются по диалекту. Если в дампе есть специфичные расширения PostgreSQL или Oracle, которые парсер не знает, связи между таблицами могут потеряться. Перед индексацией стоит проверить, какой диалект используется:
bash# Пример проверки диалекта в дампе PostgreSQL
grep -i "CREATE TABLE" dump.sql | head -20
Если парсер не справляется, можно предварительно очистить дамп от специфичных конструкций или указать диалект в конфиге:
yaml# graphify.yaml
sql:
dialect: postgresql
ignore_extensions:
- plpgsql
- dblink
Вывод простой: Graphify хорош там, где важна предсказуемость структуры — зависимости между файлами, таблицы в базе, ссылки в документации. Он не заменяет векторный поиск и не лечит проблемы с масштабом или отсутствием текстового слоя в PDF.
Часто задаваемые вопросы
Нужен ли Graphify, если у меня уже есть векторная база?
Нет, не вместо, а вместе. Векторная база ищет по смыслу, Graphify — по структуре и связям. Например, вы можете спросить у агента «где используется функция calculate_tax?» и получить точный путь к файлу и строке, а не приблизительный фрагмент. Оба инструмента дополняют друг друга, особенно в сложных проектах с большим количеством кода и документации.
Какие языки программирования и форматы поддерживаются?
На текущий момент Graphify парсит Python, JavaScript, TypeScript, Go, Java, C# и Rust через AST. SQL‑схемы поддерживаются для PostgreSQL, MySQL и SQLite. PDF принимаются с текстовым слоем; сканы нужно предварительно обработать OCR. Полный список языков лучше уточнять в репозитории проекта, так как поддержка расширяется с каждым релизом.
Как подключить Graphify к Claude Code?
Через файл CLAUDE.md, где описывается структура графа и пути к ключевым модулям. Claude Code читает этот файл и может ориентироваться в связях, которые построил Graphify. Подробнее о настройке CLAUDE.md можно почитать в этой статье по Карпати. Для Cursor и Codex принцип аналогичный: достаточно указать путь к сгенерированному графу в конфиге агента.
Можно ли использовать Graphify с приватным кодом?
Да, и это один из главных плюсов. Парсинг происходит локально, ничего не отправляется на внешние серверы. Граф остаётся на вашем оборудовании, поэтому подходит для закрытых репозиториев и проектов с NDA.
Как часто нужно переиндексировать?
После каждого коммита или при изменении файлов. Можно настроить файловый сторож (watcher), который запускает индексацию по событию. Пример на systemd:
ini# /etc/systemd/system/graphify-watcher.service
[Unit]
Description=Graphify file watcher
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/graphify watch --path /home/user/project --config /home/user/graphify.yaml
Restart=always
User=alexey
Но для больших репозиториев лучше индексировать только изменённые ветки, а не весь проект целиком.
Работает ли Graphify с Rivet или другими инструментами оркестрации агентов?
Да, граф можно экспортировать в формат, понятный Rivet, и использовать для маршрутизации агентов. Если вы уже строите оркестрацию на базе Rivet, Graphify даст ей точку опоры в виде реальной структуры кода, а не только описаний в промптах. Больше про Rivet можно почитать в материале про оркестрацию AI‑агентов и варианте на S3.
Почему в статье упоминается Ponytail?
Ponytail помогает агенту писать меньше кода, а Graphify — понимать, какой код уже есть. Вместе они снижают количество повторов и ошибок при генерации. Подробнее про Ponytail — в отдельной статье.
Где взять навыки для агентов, которые будут работать с графом?
В репозитории mattpocock/skills есть готовые навыки для разных агентов. Их можно адаптировать под Graphify, чтобы агент понимал, как обходить граф и извлекать зависимости. Ссылка: Навыки для ИИ‑агентов из репозитория mattpocock/skills.
Graphify не панацея, но даёт предсказуемость там, где хаос связей обычно остаётся невидимым.