Гайд по настройке
Подключение RAGRAF к DeepSeek Harness
--agent-kind external MCP · stdio · JSON-RPC mcp__ragraf__ragraf_* подтверждено замерами · dsh 0.2.0-rc.2
Electron-приложение DeepSeek Harness 0.2.0-rc.2 со встроенным MCP-клиентом (плагин @deepseek-ai/dsh-mcp-client). RAGRAF подключается к нему как MCP-сервер по stdio; инструменты становятся видны под именами mcp__ragraf__ragraf_*. Связка отлажена до конца и подтверждена замерами живой сессии: всё ниже — повторяемые команды, пути и измеренные выводы.
- dsh 0.2.0-rc.2 · Electron
- 24 инструмента ragraf_*
- 3 правки RAGRAF
- 4 уровня проверки
Обозначения в командах: $repo — путь к локальному клону RAGRAF (сниппеты задают его первой строкой), $dsh — поставляемый CLI приложения. Команды и выводы приводятся как измерены — включая русские строки, которые печатает продукт.
Источник: документ интеграционной сессии «RAGRAF × DeepSeek Harness» — повторяемые команды, пути и измеренные выводы живой сессии (dsh 0.2.0-rc.2).
Как это устроено
Почему stdio, а не streamable-http
MCP-клиент HARNESS объявляет capabilities: {} — корней (roots) сервер не получает. Подними RAGRAF по HTTP как один сервис — и «какой сейчас проект» определить нечем: текущий каталог клиента до сервера не доходит. У stdio-сервера рабочий каталог процесса известен, и корпус определяется по реестру разработок.
Почему один сервер на все проекты
Клиент HARNESS не даёт инструментам RAGRAF перезапустить себя, а держать по серверу на проект значило бы держать по копии индекса в памяти на каждый. Вместо этого корпус переключается операцией mcp__ragraf__use_project, а корпус по умолчанию определяется по рабочему каталогу через реестр. Не нашёлся — сервер всё равно поднимается, честно отвечает на catalog и use_project, а остальным операциям отказывает с причиной.
| Что | Где |
|---|---|
| Точка входа сервера | tools/ragraf-mcp.py · репозиторий RAGRAF |
| Встроенные 24 инструмента | src/ragraf/mcp_server.py |
| Фасад операций (22) | src/ragraf/facade.py |
| Реестр корпусов | catalog/catalog.json |
| Слой патчей профиля | %USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml |
| Навык | %USERPROFILE%\.dsh\skills\ragraf-core\SKILL.md |
| Глобальные правила | %USERPROFILE%\.dsh\AGENTS.md · раздел 6 |
Что было доработано в RAGRAF
Дефект был не «неудобно», а «не работает вовсе»: первый же ответ с русским текстом убивал сервер. Измерено запуском — три причины, каждая подтверждена замером.
UnicodeEncodeError: 'charmap' codec can't encode characters in position 97-105
File "src/ragraf/mcp_server.py", line 551, in send
sys.stdout.write(json.dumps(message, ensure_ascii=False) + "\n")- Кодировка потокаMCP SDK передаёт дочернему процессу лишь 12 переменных (APPDATA, PATH, TEMP, USERPROFILE и др. — DEFAULT_INHERITED_ENV_VARS), а HARNESS дополнительно вычищает имена с PASSWORD|SECRET|TOKEN|KEY и все DSH_*. Ни PYTHONUTF8, ни PYTHONIOENCODING в набор не входят — локаль процесса остаётся cp1252. Правка: force_utf8_stdio() перенастраивает stdin, stdout, stderr на UTF-8, не полагаясь на окружение.
- Зависимостиfastembed, PyYAML, sqlite_vec, tree_sitter, ijson были достижимы интерпретатору из PATH только через переменную PYTHONUSERBASE — HARNESS её вычищает, и сервер рапортует «не установлен PyYAML». Решение: сервер запускается интерпретатором из .venv самого проекта — замерено, что при полностью снятых PYTHON*-переменных он импортирует все пакеты.
- Обязательный --projectКлиент, запускающий сервер без аргументов, не мог стартовать вообще. Правка: --project больше не обязателен — корпус определяется по рабочему каталогу через реестр (_resolve_default_project()), для ручного переключения добавлен инструмент ragraf_use_project, а --agent берётся ещё и из переменной RAGRAF_AGENT.
| Файл | Что сделано |
|---|---|
| src/ragraf/mcp_server.py | force_utf8_stdio(); --project больше не обязателен; _resolve_default_project(); инструмент ragraf_use_project; --agent берётся ещё и из RAGRAF_AGENT; отказ при невыбранном корпусе — понятный текст вместо ConfigError |
| src/ragraf/cli.py | команда reindex теперь записывает прогон в реестр, как index |
| tests/test_mcp_compat.py | новый файл: проверки на урезанное окружение, автоопределение корпуса и переключение |
| tools/Invoke-ProjectDoctrine.ps1 | проверки Test-McpClientCompatibility и Test-ExternalOpsAreRecorded; правило записи в реестр смотрит каждую функцию, запускающую индексатор, а не файл целиком (16 проверок вместо 14) |
| README.md · INTEGRATION.md · AGENTS.md | числа приведены к коду: 24 инструмента; задокументированы «три ловушки» с замерами |
Совместимость с прежними клиентами сохранена: AutoClaw и SagaAI передают --project явно и выставляют PYTHONIOENCODING — для них ничего не изменилось.
Установка — три шага
Все три шага кладут файлы в домашний каталог HARNESS (%USERPROFILE%\.dsh или $DSH_HOME); готовые блоки лежат в каталоге harness/ репозитория RAGRAF. В командах ниже $repo — путь к локальному клону RAGRAF, $dsh — поставляемый CLI приложения.
- Подключите MCP-серверГотовый блок harness/ragraf-mcp.patch.yml дописывается в конец слоя патчей профиля cordis.patch.yml. Приложение хранит патчи массивом, поэтому блок вставляется отдельной строкой «- insert:». Сначала бэкап — файл принадлежит пользователю.Дописывание патч-блока (PowerShell)
$repo = 'C:\AutoClaw\RAGRAF' # путь к локальному клону RAGRAF $src = Join-Path $repo 'harness\ragraf-mcp.patch.yml' $dst = Join-Path ([Environment]::GetFolderPath('UserProfile')) '.dsh\profiles\desktop\cordis.patch.yml' # 1. бэкап (обязательно: файл принадлежит пользователю) Copy-Item $dst "$dst.bak-$(Get-Date -Format yyyyMMdd-HHmmss)" # 2. проверить, что блока ещё нет Select-String -LiteralPath $dst -Pattern 'mcp-ragraf' # 3. дописать блок (слой патчей — массив; блок вставляется отдельной строкой "- insert:") Add-Content -LiteralPath $dst -Value (Get-Content -LiteralPath $src -Raw) -Encoding utf8NoBOMПроверить, что патч применяется — без запуска приложения:
Проверка через dsh --dump-config$dsh = Join-Path $env:LOCALAPPDATA 'Programs\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd' & $dsh --profile headless --patch $src --dump-config | Select-String 'serverName: ragraf' -Context 1,3Профиль desktop — рабочий профиль приложения; headless — одноразовые задачи из командной строки. Для профиля, отличного от desktop, блок кладётся в его cordis.patch.yml тем же способом.
- Установите навыкКорень навыков %USERPROFILE%\.dsh\skills читает провайдер @deepseek-ai/dsh-skill-filesystem: на верхнем уровне он ищет <имя>/SKILL.md. Навык в этом каталоге обнаруживается без перезапуска — провайдер следит за корнем.Установка навыка ragraf-core
$skills = Join-Path ([Environment]::GetFolderPath('UserProfile')) '.dsh\skills\ragraf-core' New-Item -ItemType Directory -Path $skills -Force | Out-Null Copy-Item (Join-Path $repo 'harness\skills\ragraf-core\SKILL.md') "$skills\SKILL.md" -Force - Добавьте правило в глобальные инструкцииHARNESS читает %USERPROFILE%\.dsh\AGENTS.md (модуль dsh-agent-instructions; dshHome = $DSH_HOME или ~/.dsh). Раздел для вставки — harness/agents-section.md; ставится перед разделом «Журнал изменений», иначе правило окажется после истории (в проверенной установке это раздел 6). Ожидаемое поведение: на вопрос «с чего начинается задача о коде» агент отвечает mcp__ragraf__ensure и ссылается на этот раздел.
Проверка — четыре уровня
От узкого к широкому: сервер сам по себе → живой запуск внутри приложения → навык → чекер проекта. Каждый уровень — команда и ожидаемый вывод, измеренные в живой сессии.
Проверка того самого дефекта: PYTHONUTF8 и PYTHONIOENCODING сняты перед запуском — так, как это делает HARNESS. Тест — tests/test_mcp_compat.py: урезанное окружение, автоопределение корпуса, переключение.
cd $repo
Remove-Item Env:\PYTHONUTF8, Env:\PYTHONIOENCODING -ErrorAction SilentlyContinue
python tests\test_mcp_compat.pyОжидаемый вывод
ИТОГ: пройдено 13, провалено 0Задача headless-профиля, в которой агент обязан вызвать инструмент. В потоке событий — tool_call и tool_result с полным конвертом: op, rev, capability.
& $dsh --profile headless --patch $src --json `
"Вызови mcp__ragraf__index_status и приведи первую строку ответа"Ожидаемый вывод
{"type":"tool_call","tool":"mcp__ragraf__ragraf_index_status","input":{}}
{"type":"tool_result","status":"completed","result":"op=index_status rev=rev-0043 capability=full ..."}Провайдер обнаруживает ragraf-core без перезапуска; проверка убеждается, что агент действительно загружает навык и опирается на его тело.
& $dsh --profile headless --patch $src "Загрузи навык ragraf-core и назови первый шаг"Ожидаемый вывод
{"type":"tool_call","tool":"skill","input":{"name":"ragraf-core"}}Правило на свойство совместимости в доктрин-чекере проекта — чтобы регресс среды поймался до запуска приложения, а не в сессии.
pwsh -NoLogo -NoProfile -NonInteractive -File tools\Invoke-ProjectDoctrine.ps1Ожидаемый вывод
checks: 16, errors: 0, warnings: 0, Result: PASS
[PASS] MCP server survives a scrubbed client environment
[PASS] operations outside the facade are recordedТри ограничения, которые надо знать
Перезапуск приложения обязателен
Настройки профиля читаются при старте. Вставленный блок mcp-ragraf начнёт работать после перезапуска DeepSeek Harness; до этого инструментов mcp__ragraf__* в интерфейсе не будет. Это нормальное поведение, а не сбой.
Висящий сервер Joern при индексации
Полная индексация поднимает Joern (JVM) на порту 9500. Замерено: после первой переиндексации остался процесс java.exe на 3 ГБ, державший порт; снят вместе с родительским cmd.exe (taskkill /PID <cmd> /T /F). Перед долгой работой и после неё проверяйте процессы и порт:
Get-CimInstance Win32_Process -Filter "Name='java.exe'" |
Select-Object ProcessId, @{n='MB';e={[int]($_.WorkingSetSize/1MB)}}
Get-NetTCPConnection -LocalPort 9500 -ErrorAction SilentlyContinue
# висящий сервер снимается вместе с родительским процессом:
taskkill /PID <PID родительского cmd.exe> /T /FКоманда reindex теряла запись прогона в реестре
Найдено и исправлено при работе над этой же задачей: index записывал результат в реестр, а reindex — нет. Замерено на корпусе самого RAGRAF: в индексе rev-0046, в реестре rev-0045 — из-за этого check реиндексировал корпус заново на каждой проверке, что выглядело как «RAGRAF тормозит». Признак расхождения: catalog показывает ревизию, отличную от index_status. Правило чекера теперь смотрит каждую функцию, запускающую индексатор.
Откат
HARNESS: вернуть слой патчей и AGENTS.md из бэкапов (их имена печатала установка), удалить каталог навыка ragraf-core.
$home2 = [Environment]::GetFolderPath('UserProfile')
# 1. вернуть слой патчей из бэкапа (имя печатала установка)
Copy-Item "$home2\.dsh\profiles\desktop\cordis.patch.yml.bak-<метка>" `
"$home2\.dsh\profiles\desktop\cordis.patch.yml" -Force
# 2. вернуть глобальные правила
Copy-Item "$home2\.dsh\AGENTS.md.bak-<метка>" "$home2\.dsh\AGENTS.md" -Force
# 3. убрать навык
Remove-Item "$home2\.dsh\skills\ragraf-core" -Recurse -ForceRAGRAF: правки аддитивные — они не затрагивают индекс, схему хранилища, нумерацию ревизий и реестр, поэтому откат не требует переиндексации. Чтобы вернуть прежнее поведение, достаточно трёх изменений: убрать вызов force_utf8_stdio(), вернуть required=True у --project и удалить инструмент ragraf_use_project из TOOLS и _handlers.
Поведение HARNESS: где лежит что
| Что | Где |
|---|---|
| Установка приложения | %LOCALAPPDATA%\Programs\DeepSeek Harness |
| Плагины HARNESS | resources\app.asar · дерево dsh/node_modules |
| Домашний каталог HARNESS | %USERPROFILE%\.dsh |
| Настройки профилей | %USERPROFILE%\.dsh\profiles\<имя> |
| Данные Electron | %APPDATA%\@deepseek-ai\dsh-desktop |
| Реестр плагинов | https://registry.npmjs.org/ |
| CLI | resources\runtime\cli\bin\dsh.cmd |
Домашним каталогом управляют переменные DSH_HOME (явный путь важнее) и DSH_AGENTS_HOME (общий каталог навыков агентов, по умолчанию ~/.agents). Из окружения дочерних процессов HARNESS вычищает обе — на запуск MCP-сервера это не влияет: он читает только --project и рабочий каталог.
Порядок разрешения корней навыков (rank): <проект>/.dsh/skills (100), <проект>/.agents/skills (200), пользовательские customSkillDirs (300), ~/.dsh/skills (400), ~/.agents/skills (500). Проектный корень — ближайший каталог с .git.
HARNESS разрабатывается в приватном репозитории (github.com/deepseek-ai/deepseek-harness); публичной проверки API не делалось. Контракт выше описан по фактам текущей установки — lib/index.js и README пакетов внутри app.asar, — а не по документации.
Регламент агента
Регламент поставляется двумя слоями: навык ragraf-core (провайдер загружает его без перезапуска) и раздел глобальных правил %USERPROFILE%\.dsh\AGENTS.md — «задача о коде начинается с mcp__ragraf__ensure». Универсальный фрагмент регламента (страница «Интеграции») — основа навыка; он работает и сам по себе.
Телеметрия
Телеметрия идентична другим external-агентам: kind=external, хеши аргументов вместо полных текстов запросов, оценка токенов (символы/4) в usage_call — можно сравнивать экономику связки с grep-подходом. Имя агента задаёт --agent в патч-блоке или переменная RAGRAF_AGENT: сервер читает её со времён HARNESS-правок.