В прошлой статье я закончил на том, что следующая часть серии, скорее всего, уже выйдет за границы самого Obsidian-плагина, в Companion и MCP.
Вышла.
За это время Vault Audit AI успел обзавестись отдельным сервером, MCP-интерфейсом для AI-клиентов, механизмом предложений изменений и вторым репозиторием.
А потом стало понятно, что старое название уже довольно плохо объясняет, что вообще происходит.
Поэтому теперь проект называется Veynrel.
Сам плагин при этом не был переписан с нуля. Существующим пользователям не нужно ничего переустанавливать, заново вводить API-ключи или перестраивать semantic index. Я специально постарался сделать самый скучный ребрендинг из возможных с технической точки зрения.
Зато вокруг самого плагина стало заметно интереснее.
Сейчас всё это в упрощённом виде выглядит так:
Obsidian | vVeynrel | | semantic index | Similar Notes | semantic duplicates | Ask your Vault | AI workflows | vVeynrel Companion | | persistent semantic mirror | SQLite | optional Qdrant | change proposals | vMCP | +---- Codex +---- Claude Code +---- другие MCP-клиенты
В этой статье расскажу, почему я вообще полез строить отдельный Companion, зачем между агентом и Markdown появился ещё один слой, почему MCP-сервер не умеет напрямую переписывать заметки и как всё это в итоге закончилось полноценным ребрендингом.
А ещё ближе к концу будет редкое для моих статей нововведение: я наконец добавил проекту кнопку, которая не запускает очередной индекс, а позволяет поддержать разработку деньгами.
Почему Vault Audit AI перестал быть Vault Audit AI
Когда я начинал проект, название было вполне честным.
Есть Vault. Есть Audit. Где-то рядом AI.
Плагин получает заметки, прогоняет их через модель и помогает разбираться с хранилищем.
Потом появился MapReduce для больших Vault.
Потом автоматизация работы с заметками.
Потом semantic index, Similar Notes, поиск смысловых дублей и Ask your Vault.
В какой-то момент аудит остался одной из функций, а название всё ещё продолжало делать вид, что именно ради него всё и затевалось.
Продолжать называть проект Vault Audit AI было примерно как назвать IDE «редактором main.ts». Формально неправды нет, но описание уже слегка отстаёт от реальности.
Так появилось имя Veynrel.
Самое важное здесь было не поменять надпись в README, а не превратить смену названия в пользовательскую миграцию.
Поэтому внутри проекта всё ещё встречаются старые технические идентификаторы.
Например, plugin ID остался таким:
ai-knowledge-hub
Некоторые переменные окружения Companion тоже не менялись:
VAULT_AUDIT_COMPANION_DIRVAULT_AUDIT_MCP_TOKEN
Иногда встречается и vault_audit.
Это не забытый Ctrl+Shift+H.
Если строка уже используется в пользовательском конфиге, storage key или протоколе, переименовывать её только ради красоты довольно бессмысленно.
Получится красивый diff и менее красивые поломанные установки.
Поэтому Veynrel стал новым пользовательским именем, а старые идентификаторы остались там, где они уже являются частью совместимости.
Существующий пользователь просто обновляется.
Настройки остаются на месте. Semantic index остаётся на месте. Hotkeys тоже. Companion продолжает понимать тот же протокол.
Как по мне, хороший ребрендинг именно так и должен выглядеть. Большая часть сложности должна остаться проблемой автора, а не пользователя.
Зачем вообще понадобился Companion
Пока Veynrel живёт только внутри Obsidian, всё довольно удобно.
Плагин видит Vault, следит за изменениями и держит локальный semantic index.
Но у такого подхода есть очевидная граница.
Чтобы спросить что-то у Vault, нужно открыть Obsidian и вызвать функцию внутри плагина.
А мне хотелось другого сценария.
Например, я работаю в Codex и пишу:
Найди в моём Vault всё, что я писал про MCP,и покажи нерешённые архитектурные вопросы.
Или:
Посмотри мои заметки по проекту и найди,где я уже описывал похожую идею.
Или вообще:
Предложи обновление README на основе моих заметок.
Копировать Markdown руками в чат довольно быстро надоедает.
Особенно забавно это выглядит после того, как ты несколько месяцев пишешь семантический поиск, а потом продолжаешь сам искать нужную заметку, чтобы вставить её в AI-клиент.
Нужен был слой, который сможет жить отдельно от интерфейса Obsidian.
Так появился Veynrel Companion.
Это отдельный Node.js-сервис, который хранит постоянное зеркало нужного семантического состояния.
И здесь важное слово именно «зеркало».
Companion не открывает директорию Vault и не ходит по Markdown-файлам напрямую.
Он не становится вторым владельцем заметок.
И главное, он не может просто взять и переписать файл, пока Obsidian смотрит в другую сторону.

Почему я специально запретил Companion писать в Vault
На первый взгляд здесь можно было сделать намного проще.
Дать серверу путь:
/home/me/Vault
и дальше обычные:
readFile()writeFile()
Готово.
Агент читает заметки, агент пишет заметки, демо выглядит красиво.
Заодно готов будущий пост:
Как я за один вечер научил AI работать с Obsidian и за второй вечер восстанавливал Vault из Git.
Проблема не только в том, что модель может сделать что-нибудь странное.
У самого Obsidian есть состояние.
Плагин следит за файлами. Работает AutoSync. Semantic index меняется вместе с заметками. Некоторые операции читают текущую версию файла, некоторое время думают, а потом пытаются применить результат.
Если после этого добавить ещё один независимый процесс, который пишет Markdown когда захочет, появляется второй writer.
А два писателя в одну базу знаний без общей модели конкурентного доступа выглядят весело ровно до первой гонки.
Поэтому правило получилось довольно жёстким:
Only Obsidian writes the Vault.
Companion получает состояние от плагина и хранит его у себя.
AI через MCP может это состояние читать.
AI может даже предложить изменение.
Но применяет его всё равно Veynrel внутри Obsidian.
Вместо write_note появился propose_change
Это одна из частей архитектуры, которая мне сейчас нравится больше всего.
Самое очевидное MCP API выглядело бы примерно так:
read_notesearch_noteswrite_notedelete_note
Но если дать модели write_note, предыдущий раздел можно почти выкинуть.
Поэтому вместо команды «измени файл» появился другой сценарий:
AI | | propose_change vCompanion | | stores proposal vObsidian | | user reviews diff vApprove / Reject
Агент создаёт proposal.
Например:
operation: replacepath: Projects/Veynrel.mdsummary: Update Companion architecture section
Companion сохраняет предложение.
После этого Veynrel показывает его пользователю.
Можно посмотреть diff, отклонить предложение или подтвердить его.
Только после подтверждения плагин проверяет, что заметка с момента создания proposal не изменилась неожиданным образом, и применяет операцию.
То есть MCP способен участвовать в изменении Vault, но сам Vault ему не принадлежит.
Мне такой вариант нравится куда больше простого CRUD.
AI получает возможность делать полезную работу, но граница записи остаётся явной.
Что именно видит MCP-клиент
Сейчас Companion предоставляет семь инструментов:
vault_statuslist_notesget_noteget_chunkssearch_vaultpropose_changeget_proposal
Набор специально небольшой.
Я не хотел превращать MCP description в телефонную книгу из пятидесяти почти одинаковых функций.
vault_status позволяет понять, существует ли зеркало, сколько в нём заметок и chunks, какое поколение сейчас актуально.
list_notes возвращает известные пути и служебные данные.
get_note читает Markdown конкретной заметки. Большие файлы можно получать кусками.
get_chunks работает уже с частями заметки из семантического индекса.
search_vault делает то, ради чего всё это и затевалось.
Клиент отправляет обычный текст:
как я хотел организовать общую память между агентами
Companion строит embedding запроса и ищет близкие chunks.
При этом сохранённые тексты заметок повторно никуда для embedding не отправляются. Индекс уже существует.
propose_change создаёт предложение изменения, а get_proposal позволяет проверить его состояние.
Никакого approve_proposal в MCP нет.
Это тоже специально.
Подтверждение остаётся внутри Obsidian.
Откуда Companion берёт semantic search
Здесь получился ещё один забавный поворот.
Когда я писал semantic search для самого плагина, я специально отказался от отдельной векторной базы.
Для обычного Obsidian-плагина поднимать Qdrant ради пары тысяч заметок выглядело слегка чрезмерно.
Поэтому Veynrel использует собственный локальный LocalVectorStore.
И это решение никуда не исчезло.
Но Companion уже сервер.
У него Node.js, SQLite и совсем другой набор ограничений.
В результате постоянным источником состояния стал SQLite, а поверх него при желании можно включить Qdrant как ускоритель поиска.
Ключевой момент в том, что Qdrant не становится главным хранилищем.
Если его выключить или потерять, canonical data остаётся в SQLite.
Veynrel | | sync vCompanion | +---- SQLite <-- permanent state | +---- Qdrant <-- optional derived index
Для небольшого Vault можно вообще жить без Qdrant.
Если зеркало становится достаточно большим и линейный поиск начинает раздражать, ускоритель уже есть куда подключить.
Мне такой подход нравится больше схемы, где исчезновение дополнительного сервиса внезапно означает потерю основной базы.
А где здесь MCP
Если сильно упростить, MCP решает довольно скучную задачу.
Он даёт AI-клиенту стандартный способ узнать:
какие действия здесь вообще доступны и как их вызвать.
Без него для Codex пришлось бы делать один адаптер.
Для Claude Code другой.
Потом появится ещё один клиент, и у разработчика внезапно появится новое хобби.
С MCP Companion выставляет один интерфейс.
Дальше клиент получает инструменты и сам вызывает их по мере необходимости.
Например:
Codex | | search_vault("MCP security model") vVeynrel Companion | | embedding query | vector search vmatching chunks
Если результата мало, агент может запросить полную заметку через get_note.
Если после анализа нужно что-то изменить, создаёт propose_change.
То есть модель получает не огромный dump Vault в context window, а возможность постепенно добирать нужную информацию.
Для базы знаний это выглядит куда естественнее.
Два токена вместо одного
Раз уж сервер умеет и синхронизировать состояние, и отдавать данные AI-клиентам, довольно быстро появился следующий вопрос.
Почему MCP-клиент вообще должен иметь те же права, что и сам Obsidian?
Не должен.
Поэтому у Companion разные credentials.
COMPANION_TOKEN используется доверенным плагином для синхронизации.
MCP_TOKEN используется MCP-клиентом.
Если кто-то получает MCP token, это не должно автоматически давать ему возможность притвориться Veynrel и загрузить новое состояние зеркала.
Равные значения токенов Companion вообще не принимает при запуске.
На локальной машине это может показаться паранойей.
На VPS уже меньше.
Один Companion и для локалки, и для VPS
Отдельной «серверной версии» Companion нет.
Запускается один и тот же код.
Локально это может быть:
127.0.0.1:27124
Плагин синхронизируется туда же.
Codex подключается к:
http://127.0.0.1:27124/mcp
Если хочется держать зеркало на VPS, Companion можно поставить туда и спрятать за reverse proxy:
Internet | HTTPS |Caddy / Nginx |127.0.0.1:27124 |Veynrel Companion
Сам Companion TLS не терминирует.
Для удалённого подключения plaintext HTTP я бы не использовал. Там всё-таки лежит зеркало личной базы знаний, а bearer token не становится менее секретным оттого, что находится в красивом JSON.

Почему Companion пришлось вынести в отдельный репозиторий
Изначально сервер жил прямо внутри репозитория плагина.
Выглядело удобно:
veynrel/├── plugin code├── semantic/├── companionSync/└── companion/
Один проект, всё рядом.
Потом началось ревью Obsidian Community Plugin.
Scanner видел Node.js-код Companion и вполне логично с его точки зрения начинал объяснять мне, что node:http и node:sqlite недоступны на мобильном Obsidian.
Он был прав.
Кроме одной небольшой детали.
Этот код вообще никогда не должен был попадать в Obsidian.
Сервер и плагин просто находились в одном Git-репозитории.
Можно было бесконечно объяснять tooling, где заканчивается мобильный плагин и начинается standalone Node-сервис.
А можно было провести нормальную архитектурную границу.
Теперь репозитория два:
github.com/zinverno/veynrelgithub.com/zinverno/veynrel-companion
В основном репозитории остался companionSync, который действительно является частью плагина.
Сам сервер живёт отдельно.
После этого исчезли не только лишние scanner warnings.
Стало проще само устройство проекта.
У Companion теперь свои зависимости, свой CI, свои тесты и свой lifecycle.
И, что неожиданно приятно, его теперь можно развивать как самостоятельный сервис, не притворяясь, что это просто большая подпапка Obsidian-плагина.

Ребрендинг оказался ещё и тестом обратной совместимости
Переименование проекта звучит как задача уровня:
Find: Vault Audit AIReplace: Veynrel
Я довольно быстро обнаружил, почему такие операции иногда заканчиваются отдельным migration guide.
Старое имя встречалось не только в README.
Оно успело попасть в package names, environment variables, storage keys, MCP identifiers, Qdrant prefixes, hash inputs и исторические fixtures.
Часть можно было переименовать.
Часть нельзя.
Часть можно, но это не даёт вообще ничего, кроме риска.
В итоге перед заменой каждый такой идентификатор пришлось классифицировать.
Например, private npm package Companion спокойно превратился из:
vault-audit-ai-companion
в:
veynrel-companion
А вот:
VAULT_AUDIT_COMPANION_DIR
остался.
Потому что это уже пользовательская переменная окружения.
То же самое касается некоторых storage keys и protocol identifiers.
Получился довольно простой принцип:
Бренд можно менять агрессивно. Совместимость лучше менять только тогда, когда есть причина кроме нового логотипа.
В итоге Veynrel 1.8.0 обновляется поверх Vault Audit AI 1.7.0 без миграции пользовательских данных.
Тестов снова стало подозрительно много
В прошлой статье я писал про 698 тестов.
Сейчас в основном плагине их уже 849.
Companion живёт отдельно и имеет ещё 218.
И я уже давно перестал воспринимать количество тестов как соревнование с самим собой.
Просто почти каждая новая граница проекта создаёт новый класс неприятных сценариев.
Что если заметка изменилась между созданием proposal и подтверждением?
Что если embedding provider вернул NaN?
Что если два запроса одновременно пытаются обработать одну заметку?
Что если semantic descriptor изменился прямо во время поиска?
Большинство таких вещей в демо никогда не происходят.
В реальном основном Vault почему-то происходят именно они.
Традиция проекта сохраняется.
Что получилось в итоге
После всей этой перестройки Veynrel для меня уже выглядит не как один большой Obsidian-плагин.
Скорее как два слоя.
Первый находится непосредственно рядом с заметками:
Veynrel
Он владеет взаимодействием с Vault.
Индексирует, показывает интерфейс и применяет подтверждённые изменения.
Второй:
Veynrel Companion
может жить отдельно, держать постоянное зеркало и давать контролируемый доступ внешним AI-клиентам.
MCP соединяет этот слой с агентами.
Самое важное здесь для меня то, что границы получились достаточно явными:
Agent can readAgent can searchAgent can proposeAgent cannot silently write Markdown
Это ограничивает часть красивых демо.
Зато заметно повышает шанс, что я сам соглашусь подключить всё это к своему настоящему Vault.
А этот тест для проекта пока остаётся главным.
У проекта появилась поддержка через Boosty
И ещё одно изменение, совсем не архитектурное.
До этого Veynrel был просто open-source проектом, в который я довольно методично складывал свободное время.
Он таким и остаётся.
Код открыт под MIT.
Функции не будут прятаться за подпиской.
Companion и MCP тоже не превращаются в платный тариф.
Но проект уже давно перестал быть маленьким экспериментом на выходные.
Есть Community Plugin, отдельный Companion, документация, CI, тесты, совместимость между версиями и периодические сражения с проблемами, о существовании которых я вчера ещё не подозревал.
Поэтому я наконец добавил возможность добровольно поддержать разработку.
Boosty: https://boosty.to/veynrel
Сейчас там есть простой уровень поддержки проекта.
Без Veynrel Ultimate Enterprise Plus.
Без «semantic search доступен с тарифа Pro».
Если проект вам полезен и хочется помочь мне продолжать его развивать, теперь такая возможность просто есть.
Если нет, ничего в использовании Veynrel от этого не меняется.
Что дальше
В прошлой статье я написал, что следующая часть серии, скорее всего, выйдет за границы Obsidian.
Теперь это уже произошло.
Но Companion и MCP мне интересны ещё по одной причине.
Когда несколько AI-клиентов начинают работать с одними и теми же данными, довольно быстро появляется следующий вопрос.
Почему каждый из них должен заново строить вокруг себя собственную память, интеграции и способ получения контекста?
Пока Veynrel решает эту задачу только для одной конкретной области, Obsidian Vault.
Но архитектурно здесь уже начинают появляться более общие идеи.
Хранилище отдельно.
Агент отдельно.
Контролируемый слой доступа между ними отдельно.
Куда это в итоге приведёт, я пока лучше не буду обещать.
У этого проекта и так есть плохая привычка превращать фразу «добавлю небольшую функцию» в новый репозиторий.
Попробовать
Если вы читали предыдущую часть, новая статья фактически продолжает её последнюю главу:
Я хотел просто навести порядок в Obsidian. В итоге написал два индекса, semantic search и RAG
Veynrel:
https://github.com/zinverno/veynrel
Veynrel Companion:
https://github.com/zinverno/veynrel-companion
Поддержать разработку:
Сам Veynrel доступен как Community Plugin для Obsidian.
Если вы уже пользовались Vault Audit AI, ничего переустанавливать не нужно. Veynrel 1.8.0 продолжает использовать тот же plugin ID, настройки и существующий semantic index.
Мне особенно интересно, как люди будут использовать MCP не в тестовом Vault на десять файлов, а со своими настоящими хранилищами.
Потому что предыдущие этапы проекта уже довольно хорошо показали одну закономерность.
Самые интересные архитектурные решения начинаются примерно через пять минут после того, как аккуратное демо впервые сталкивается с реальными данными.
ссылка на оригинал статьи https://habr.com/ru/articles/1082762/