Записывает, как код на самом деле исполнялся: вызовы, доводы, результаты, исключения, длительности
Модель, читающая исходник, рассуждает о том, что должно происходить. Модель, читающая записи о вызовах, знает, что происходило.
Разница не в объёме сведений, а в том, какой вопрос вообще имеет ответ. По исходнику видно, что может случиться: ветви, которые там написаны, доводы, которые там объявлены. По записям видно другое — какие ветви исполнялись, какие доводы встретились на самом деле, какие вызовы зависли и какие бросили исключение. Второго в исходнике нет ни в каком виде, и вывести его чтением нельзя.
Обратное тоже верно, и это надо держать рядом: записи не скажут, что код неправильный. Они скажут, что он делает. Вывод «а должно быть иначе» остаётся человеку.
Дописать в настройку клиента один блок:
{ "mcpServers": { "ouroboros": { "type": "stdio", "command": "ouroboros-mcp" } } }
wrap_file,
read_trace, trace_stats и остальные — всего семнадцать.Сервер выкладывает операции напрямую, без промежуточного слоя выбора: агент видит все семнадцать имён и зовёт их по имени.
Дописать запись о вызовах
| инструмент | что делает |
|---|---|
wrap_code_snippet |
обмазывает переданную строку кода, ничего не сохраняя |
wrap_file |
обмазывает файл на месте |
wrap_functions |
обмазывает только названные функции — для горячих и больших файлов |
Прочитать записи
| инструмент | что делает |
|---|---|
read_trace |
записи с отбором и чтением частями |
trace_stats |
сводка: сколько раз звали, сколько бросили, сколько шло |
Черновик
| инструмент | что делает |
|---|---|
create_project |
заводит черновик с историей изменений |
write_file |
обмазывает до сохранения; неразбираемое отвергает |
read_file, list_files |
посмотреть, что в черновике |
execute |
запускает команду, сам подставляя путь к debug.info |
finish |
копирует черновик в чистовик; обмазку не снимает |
C и C++ через clangd — выбрать, что обмазывать, в большом дереве
| инструмент | что делает |
|---|---|
lint_file |
разбор clang-tidy |
symbol_search |
найти имя по всему дереву |
document_symbols |
что определено в одном файле |
references |
кто зовёт |
call_hierarchy |
кто зовёт кого, по цепочке |
describe_symbol |
где определено и с какой подписью |
У каждого инструмента проставлено, что он делает с файлами: читающие помечены
как безопасные, wrap_file и finish — как переписывающие, execute — как
запускающий произвольную команду. Клиент видит это до первого вызова
(ouroboros/mcp/server.py:644).
Таблицы выше — краткий пересказ. Полный справочник снят с живого сервера:
Справочник средств MCP — на каждое из семнадцати средств
заголовок, описание, схема доводов, схема ответа и настоящий ответ на настоящий
вызов. Он не написан руками, а напечатан из
docs/mcp-tools.json, который снимается разговором с сервером
командой scripts/probe/build-reference.sh. Если пересказ здесь и справочник
разойдутся — верен справочник.
Вызов wrap_file через сервер MCP:
{
"ok": true,
"path": "/srv/tmp/ouro-work/mcpdemo/stats.py",
"language": "python",
"functions_wrapped": 3,
"runtime_header": "/srv/tmp/ouro-work/mcpdemo/ouroboros_runtime.py"
}
После прогона программы — trace_stats по тому же черновику:
{
"ok": true,
"calls_parsed": 5,
"malformed": 0,
"total_calls": 5,
"by_function": [
{ "name": "parse_line", "count": 3, "result": 3, "raised": 0, "unknown": 0,
"duration_seconds": { "min": 1e-06, "max": 2e-06, "mean": 2e-06, "total": 5e-06, "count": 3 } },
{ "name": "average", "count": 1, "result": 1, "raised": 0, "unknown": 0,
"duration_seconds": { "min": 2e-06, "max": 2e-06, "mean": 2e-06, "total": 2e-06, "count": 1 } },
{ "name": "report", "count": 1, "result": 1, "raised": 0, "unknown": 0,
"duration_seconds": { "min": 0.000351, "max": 0.000351, "mean": 0.000351, "total": 0.000351, "count": 1 } }
]
}
Это настоящий обмен с сервером, а не образец.
create_project → write_file → execute → read_trace → finish
черновик обмазывает запускает читаем переносим
при записи записи наружу
Или короче, без черновика: wrap_file → агент сам запускает программу →
read_trace.
Горячие файлы. wrap_file на файле с миллионом вызовов в секунду топит
нужные записи в шуме. Агент, которому не сказали иного, скорее возьмёт
wrap_file — поэтому на горячем файле имя wrap_functions называют в задании
прямо.
Годится как есть:
Разберись, как на самом деле исполняется
<файл>. Возьми уроборос: заведи черновик, обмажь<файл>(на горячем файле —wrap_functions, назови функции), прогони на настоящих данных, прочитай записи.В отчёте назови: сколько вызовов записано, какие функции исполнялись и с какими доводами, что вернулось, что бросило исключение и что не вернулось (
in_flight). Отдельно — сколько строк не разобралось (malformed).Выводов о правильности программы не делай: записи говорят, что код сделал, а не что он должен был сделать. Если увидишь странность — назови её вопросом ко мне, а не утверждением.
Что вообще что-то записалось. calls_parsed: 0 значит, что обмазанный код
не исполнялся, а не что всё чисто. Это первое, на что стоит смотреть.
Испорченные строки. malformed больше нуля — часть записей не разобралась,
и выводы сделаны по неполной картине.
Невернувшиеся вызовы. in_flight — это вход без выхода: зависание, падение
или жёсткий выход. Пустой список хорошо, непустой требует объяснения.
Покрытие. Ветвь, в которую не зашли, записей не даст и не пожалуется. Утверждать по трассе что-либо о неисполнявшемся коде нельзя.
Что именно записано. Запись утверждает «на этом входе вышло вот это». Она не утверждает, что так правильно. Агент, подающий трассу как доказательство правильности, ошибается — и это самая частая ошибка при работе с инструментом.
Длительность — не цена. Поле d измеряет обмазанный прогон. Читать его
как стоимость обычного прогона нельзя.
В хранилище лежит навык skill/SKILL.md
— короткое описание инструмента для агента: что поставить, как подключить сервер,
все семнадцать средств, порядок работы и границы с замеренными числами. Он
описывает этот инструмент и ничего сверх него.