Давайте будем честны: текущее состояние вызова функций (Function Calling) у LLM и экосистемы MCP (Model Context Protocol) вызывает изжогу в лучшем случае. Чтобы дать агенту возможность сделать curl или дернуть локальный скрипт, современному разработчику предлагают:
Описать килобайты монструозных JSON-схем прямо в системном промпте (и спалить 15-30k токенов контекста еще до первого вопроса пользователя).
Написать полноценный сетевой MCP-сервер со своим бойлерплейтом, SDK и зависимостями.
Завернуть всё это в жирный Docker-контейнер, выделив 200 Мб ОЗУ ради выполнения элементарного скрипта на три строки.
И один bash-tool вместо десяти нормальных инструментов задачу не решает, сессии превращаются в нечто вроде (псевдокод):
bash("systemctl is-active my-app.service") bash("journalctl -u my-app.service -n 50 --no-pager") bash("ss -tunlp | grep 3000") bash("kill -9 $(lsof -t -i:3000)") bash("systemctl restart my-app.service")
Что повторяется три раза только за эту сессию, и это - совсем не DRY (Don’t Repeat Yourself). Интуитивно у инженера в этом моменте слегка подскакивает пульс и давление, и он хочет абстрагировать это в call_tool("check_journals_and_stats", {...})
А когда в проекте накапливается больше 30 таких абстракций - модель неизбежно ловит Lost in the Middle и начинает галлюцинировать схемами, а разработчик оплачивает тонны входящих токенов за документацию API, которую агент даже не собирался вызывать в текущей сессии.
Отдельное спасибо здесь стоит сказать маркетингу Anthropic - работает он отлично. Термины вроде MCP, agent, harness, tooling теперь на слуху у людей, которые до этого к тулингу LLM никакого отношения не имели, причём многие оперируют ими скорее на уровне потребления хайпа, чем реального понимания. Модели у Anthropic отличные, тут вопросов нет. Но стоит помнить, что всё вокруг их флагманского продукта (включая сам MCP как протокол) в первую очередь продвигает этот продукт, а развитие области вокруг него - уже вторичная задача.
Короче, я устал от натягивания совы на глобус именованием MCP как стандартизированного протокола для всего тулинга самой популярной области последних лет и сделал ?️ toolhub - self-hosted движок, который превращает любой консольный скрипт (Bun, Python, Bash, Go, PHP, etc) в инструмент для LLM на лету, с иерархической навигацией по дереву папок и околонулевыми требованиями к зависимостям.
Файловая система навыков вместо плоского списка
Почему контекст модели забивается? Потому что типичные MCP-прокси дают модели плоский массив из 100 тулов.
У меня подход иной - древовидная навигация:
/ ├── system/ │ ├── fetch_logs │ └── restart_service ├── database/ │ └── query_pg └── sublime/ └── replace-literal
Скажите мне, серьёзные разработчики, ML-щики, архитекторы, системные аналитики - не это ли было самым адекватным путём с самого начала? Хотя бы с момента, когда стало ясно, что без кеширования контекста направление продолжит быть убыточным.
Модель не знает схемы сотен инструментов заранее. На старте через hub.getSmartPrompt() в системный промпт инжектится только корневая карта дерева с краткими аннотациями назначений категорий (1–2 строки на папку). Модель стартует с базовым контрактом:
listTools("/system")- посмотреть, что валяется в конкретной ветке, и подтянуть точные описания только нужных инструментов.callTool("/system/fetch_logs", { "service": "nginx" })- вызвать конкретный инструмент с конкретными параметрами.
Результат: окно контекста чистое, модель лезет в папку только тогда, когда ей действительно нужен инструмент из этой категории. Когда она понимает, что к текущему запросу папка с ЭТИМ названием может иметь непосредственное отношение.
Важное уточнение - toolhub сознательно не работает ни с одним из стандартных интерфейсов tool calling каких-то конкретных провайдеров. Весь Re-Act loop построен на классических XML-like командах:
<hub>listTools("/")</hub>
<hub>callTool("/sublime/list-project-files", {})</hub>
Так с минимальным оверхедом на вызов мы даём возможность пользоваться тулами абсолютно любым моделям, даже если у них не встроена поддержка тулинга, или она сделана как-то странно/криво. По сути XML-обвязка (<hub>...</hub>) сопоставима или легче, чем JSON-разметка нативного tool_call у большинства провайдеров. Единственный таким образом порог входа для модели - понимание, что такое xml, json, js и древовидная навигация.
Как это работает
Поднимать Docker-контейнер на каждый чих - это дорого по ресурсам (особенно если вы крутите агентов на скромной VPS или Raspberry Pi). toolhub использует только Bun и его возможности. Глобальная зависимость всего одна, так что я даже не стал собирать для вас бойлерплейтные Dockerfile || docker-compose.yml - нужны они будут не всем, собрать самому - 3 минуты.
Механика исполнения под капотом простая как топор:
Workspace (/tmp) ➔ Инъекция (код + input.json) ➔ Установка deps ➔ runCmd с таймаутом ➔ rm -rf
Создание изолята: На лету генерируется временная папка
/tmp/hub_run_<timestamp>_<hash>.Инъекция кода и аргументов: В папку кладется код и
input.json, а все параметры вызова автоматически пробрасываются в ENV-переменные вида$INPUT_<KEY_NAME>. Хочешь - парси JSON в коде, хочешь - пиши bash-однострочник, который сразу читает$INPUT_HOST. Никаких обвязок.Зависимости: Если прописан
installCmd, он отрабатывает в контексте папки. Bun и современные пакетные менеджеры за счет глобального кэша хоста подтягивают модули за миллисекунды; для Python-скриптов аналогично используются локальные wheel-кэши либо глобальное окружение хоста.Запуск процесса: Выполняется
runCmdс жестким ограничениемtimeoutMs. Результат считывается изoutput.jsonили stdout.Очистка: Папка воркспейса сразу же аннигилируется через
rm -rf.
Если скрипт выполняется в консоли - он автоматически становится навыком ИИ. Без написания оберток на протоколе MCP.
А что с MCP?
Я не против MCP как идеи, я против его кривых реализаций. В toolhub нативная поддержка MCP реализована в двух режимах:
Stateless (Stdio): Классика. Спавнится процесс -> отправляется запрос -> профит -> процесс убивается. Подходит для разовых утилит, т.е. для 90% того что есть на рынке. Так же для удалённых MCP в том числе.
Stateful Pool (Persistent PID): Самое вкусное. Если ваш MCP-сервер держит тяжелый контекст (Puppeteer с авторизованной сессией браузера, SSH-соединение, пул подключений к БД) - toolhub держит процесс в памяти. Повторные вызовы отрабатывают за 10–30 мс без затрат на холодный старт. Простой регулируется через TTL (по дефолту 5 минут), после чего память освобождается. Повторное использование агентом до истечения TTL - продлевает его жизнедеятельность.
Если MCP-инструмент из внешнего сервера вам понравился, но вам хочется затюнить его описание под свою модель, навесить строгую output-schema или прописать few-shots примеры (что классический MCP напрямую не поддерживает) - кнопка MCP Promote в админке в 1 клик переносит его метаданные и схемы вызова напрямую в базу toolhub, позволяя докручивать промпт и валидацию инструмента прямо из UI.
«А если я сижу в Claude Code / Cursor и хочу дергать тулы оттуда?»
Сам я не фанат завязки на конкретные закрытые проприетарные CLI, но если вы плотно сидите на Claude Code, Cursor или Cline - концептуально вам ничего не мешает использовать toolhub как единый бэкенд навыков.
Для этого достаточно написать микроскопический Stdio-мост на 40 строк (toolhub-mcp-bridge), который будет транслировать агентские вызовы Клода в REST API вашего локального toolhub. Прописали один сервер в конфиг - и Клодоподобные на лету видят всю вашу древовидную экосистему скриптов.
Перчатка брошена: кто первый напишет и оформит красивый toolhub-mcp-bridge в виде отдельного пакета/PR - с удовольствием добавлю в официальный README и закреплю авторство!
Бесконечная Федеративность
Узлы toolhub умеют каскадироваться.
Вы можете поднять локальный toolhub на рабочем ноутбуке, подключить к нему Remote-узлом toolhub вашего домашнего сервера, к которому подключен toolhub инфраструктуры дева.
Для агента это выглядит как единый путь: <hub>callTool("/office/home/server/reboot", {})</hub>
HubSDK берет на себя рекурсивную нормализацию путей, проксирование авторизации и прозрачное туннелирование запросов. А для защиты от дурака и циклических ссылок (когда Сервер А случайно ссылается на Сервер Б, ссылающийся на А) каждый запрос маркируется цепочкой заголовков x-hub-nodes с отслеживанием node_id каждого узла и жестким лимитом глубины (maxHops, по умолчанию задан разумный предел).
Шеринг навыков и встроенный Time-Machine
Любой инструмент или целую ветку дерева со всеми подпапками, раннерами и схемами можно экспортировать в один переносимый JSON-манифест .toolpack. Написал крутую связку для деплоя или работы с базой - выгрузил в 1 клик, закинул коллеге, он нажал «Import», и навыки сразу появились в его агенте. Так же с отдельными тулами.
А чтобы не бояться экспериментировать с промптами и кодом инструментов прямо в админке, toolhub ведет автоматический журнал ревизий (ToolVersion). Каждое сохранение создает неизменяемый снимок кода, схем и описания с возможностью отката к любой предыдущей версии в один клик.
Бенчмарки и производительность: а не медленно ли?
Главная претензия теоретиков к древовидной навигации: «Это же лишний RTT! Зачем делать listTools, если можно отправить всё сразу?»
Воспроизводимый бенчмарк-сьют - код лежит прямо в репозитории в папке basic-toolpacks/benchmark/. Замеры проводились на локальном тестовом стенде (VM в Proxmox, 12 vCPU Intel i5-14500 cpu_type: host, 32 GB RAM, Debian 12, NVMe SSD).
Методология: 100 последовательных итераций на каждый сценарий с расчетом p50, p90, p99 перцентилей + стресс-тест на параллельный спавн воркспейсов:
Сценарий / Нагрузка |
Среда / Раннер |
Cold Start |
Avg Latency |
p50 |
p90 |
p99 |
Throughput |
|---|---|---|---|---|---|---|---|
|
Navigation Engine |
5.5 ms |
1.0 ms |
0.8 ms |
1.7 ms |
2.6 ms |
~990 req/s |
|
Navigation Engine |
1.7 ms |
1.5 ms |
1.4 ms |
2.1 ms |
3.6 ms |
~680 req/s |
Bash System Telemetry |
OS Spawn ( |
33.7 ms |
13.4 ms |
12.7 ms |
20.3 ms |
27.1 ms |
~75 req/s |
Bun CPU Cruncher (50k iters) |
Bun Runtime |
30.9 ms |
25.8 ms |
25.2 ms |
30.1 ms |
38.0 ms |
~39 req/s |
Bun Heavy Disk I/O (25 files batch) |
FS Workspace I/O |
31.7 ms |
34.3 ms |
26.2 ms |
66.7 ms |
129.6 ms |
~29 req/s |
Python 3 SHA256 (500 hashes) |
Python 3 Process |
69.5 ms |
64.8 ms |
41.6 ms |
129.1 ms |
177.0 ms |
~15 req/s |
Важно про железо: замеры выше сделаны на мощной VM (12 vCPU/32GB) - это потолок производительности runtime’а, а не то, что вы получите на Raspberry Pi или бюджетной VPS. На слабом железе (1 vCPU/512MB) абсолютные цифры будут выше в разы, но относительная разница между навигацией по дереву (~1 мс) и полноценным спавном процесса (10-60+ мс) сохранится - узкое место всегда сам раннер, а не Navigation Engine.
Параллельный стресс-тест на изоляцию воркспейсов:
15 одновременных вызовов тулов отработали параллельно суммарно за 138 мс (Ошибок: 0, 100% изоляция ФС во временных директориях).
Что значат эти цифры?
Задержка навигации по дереву каталогов составляет 1.0–1.5 мс. Замеры отражают чистый overhead самого toolhub Runtime. На фоне сетевого latency и генерации токенов LLM (500–2000 мс) оверхед toolhub - это абсолютная погрешность.
Полный жизненный цикл одноразового bash-инструмента (генерация воркспейса
/tmp/hub_run_*, записьinput.json, спавн процесса, чтениеoutput.jsonи атомарныйrm -rf) занимает всего 13 миллисекунд.
Про базу данных: По умолчанию из коробки используется легковесная встроенная SQLite - чтобы проект поднимался без поднятия отдельных сервисов СУБД. Но благодаря тому, что весь бэкенд построен на Prisma ORM, при желании вынести ToolHub в высоконагруженный корпоративный кластер переезд на PostgreSQL, MySQL или CockroachDB сводится грубо говоря к изменению одной строчки провайдера в
schema.prisma.
Когда дерево НЕ даёт выигрыша (или даже мешает) - честный список:
Ситуация |
Почему |
|---|---|
Мало тулов (до ~10) |
Схема и так маленькая, а лишний |
Агент трогает почти все категории за сессию |
Если он всё равно облазит 50 из 60 тулов - дерево платит почти как плоский список, но ещё и с лишним RTT сверху |
Задача всегда одна и та же, тул известен заранее |
Навигация не нужна, если и так понятно, что вызывать |
Слабая модель с плохим tool-use |
Двухшаговая схема (сначала посмотреть, потом вызвать) требует дисциплины; модель послабее может путать пути или забывать зайти в папку - тут надёжность плоского списка важнее экономии токенов |
Сервис с очень высокой параллельностью на одном тулсете |
Нишевый кейс, не основной сценарий toolhub - подробно можно обсудить отдельно, если кому-то актуально |
Итого: чем шире набор тулов и чем уже реальное использование за сессию - тем сильнее дерево выигрывает. toolhub целится ровно в этот кейс.
Быстрый запуск
# 1. Клонируем git clone https://github.com/Talos-Popcorn/toolhub.git cd toolhub # 2. Установка зависимостей bun install # 3. Синхронизация схемы БД Prisma bun run db:push # 4. Интерактивный seed+install # (Выбор языка системного промпта EN/RU/ZH, настройка паролей админки и агента) bun run db:seed # Или в тихом режиме для CI/Docker: # bun run prisma/seed.ts --lang=ru --admin-pass=admin --agent-pass=123 # 5. Запуск в дев режиме bun run dev
Панель управления доступна по адресу http://localhost:5173/admin/ (или порт 3000 в прод-сборке). Swagger/OpenAPI документация: http://localhost:3000/docs (в дев-режиме). Дальше - импортируем какие-нибудь тулпаки из папки basic-toolpacks и пробуем запускать их в Playground.
Интеграция в любой JS/TS код занимает пару строк:
import { HubSDK } from './SDK/JS/sdk'; const hub = new HubSDK('http://localhost:3000', '123'); async function runAgentLoop(userQuery: string) { const systemPrompt = await hub.getSmartPrompt(); const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: userQuery } ]; while (true) { const aiResponse = await llm.generate(messages); const action = await hub.processAgentResponse(aiResponse); if (!action.called) { console.log('Ответ агента:', aiResponse); break; } messages.push({ role: 'assistant', content: aiResponse }); messages.push({ role: 'user', content: `HUB_RESULT: ${JSON.stringify(action.result)}` }); } }
Кстати, для тех, кто пробовал мой прошлый проект ?lab (статья, репо) (serverless-клиент для LLM без бэкенда) - поддержка ?️ toolhub уже встроена и прекрасно работает. Теперь можно цеплять локальные тулы прямо из браузерного интерфейса. Смотрим, как работает:



Лицензия и Open Source
Проект полностью открыт, распространяется под AGPL-3.0. Первичная задача - выкинуть из стека лишний оверхед и дать нормальный инструмент для быстрой автоматизации без переплат за токены.
GitHub Repo: github.com/Talos-popcorn/toolhub
Буду рад конструктивной критике, issue и пулл-реквестам.
FADQ (Frequently Asked Dушные Questions)
Запускать такое на рабочей тачке - опасно! Да, исполнение скриптов прямо в ОС хоста без изоляции несет риски. То, что по дефолту toolhub работает без Docker - это фича для экономии ресурсов на слабых VPS и Raspberry Pi. Заворачивать сам toolhub в Docker, LXC-контейнер или отдельную VM - это задача оператора под конкретный контур безопасности. Тебе никто этого не запрещает!
Зачем мне toolhub, если есть LangChain / LlamaIndex / AutoGen? Затем, что это тяжелые фреймворки с горой абстракций, жестко завязанные на код вашего приложения. ?️ toolhub - это самостоятельный standalone-сервис. Вы можете менять языки программирования, переключать LLM-провайдеров или переписывать агентов с нуля - ваши инструменты остаются централизованными, версионируемыми и доступными по единому REST/SDK API.
«Древовидная навигация через listTools - это же лишние RTT (Round Trip Time)! Модель тратит лишние итерации вместо того, чтобы сразу вызвать тул!» Арифметика простая:
listTools("/")уходит в системный промпт черезgetSmartPrompt()и кэшируется точно так же, как и плоский список схем. А вот когда агент дальше идёт в конкретную папку -listTools("/database")- это уже вызов внутри диалога, и вот тут дерево начинает реально экономить, потому что в контекст попадают схемы только нужной ветки, а не всех 60 тулов разом. Проверялось на синтетических тулпаках для типичного использования toolhub - один агент, личное пользование, разработка - дерево дешевле плоского списка на 60-85% уже начиная с 30+ тулов, и разрыв растёт вместе с их числом. Подробнее - выше!«Зачем писать бэкенд на Bun/TS? Почему не на Rust/Go, если мы боремся за производительность?» Потому что Bun дает идеальный баланс: стартует за миллисекунды, мгновенно исполняет JS/TS без транспиляции и не требует компиляции под каждую платформу. Если тебе нужен Rust - пиши тул на Rust, компилируй в бинарник и вызывай его через ToolHub как
runCmd: "./my_rust_binary". ToolHub - ЯП-агностичен, а оверхед на запуск тулов благодаря Fastify минимален.«Что произойдет, если 50 агентов одновременно запустят скрипты с
pip install? Все упадет от гонки зависимостей?» Каждый вызов исполняется в абсолютном изоляте/tmp/hub_run_<timestamp>_<hash>. Папки и файлы не пересекаются в файловой системе. Если тебе нужен глобальный кэш тяжелых пакетов - используй глобальный pip-кэш на хосте или нативные бинарные раннеры. Безусловно, важно понимать, что всё зависит от раннера, тула, и прямоты твоих рук.«А если скрипт зависнет в бесконечном цикле или пожрет всю память?» Для этого у каждого тула есть жестко заданный
timeoutMs. По истечении таймаута процесс жестко гасится черезSIGKILL, воркспейс подчищается черезrm -rf, а агент получает нормальную ошибку с таймаутом, а не висит намертво.«Интеграция с Sublime Text в 2026 году?! Кто вообще пользуется Sublime, когда есть Cursor / VS Code?» Всё просто - я это сделал для себя. Мне важна скорость в 2 миллисекунды на diff, а не поедание 4 Гб ОЗУ Электроном ради подсветки пары строк. Поддержка Sublime сделана для тех, кто ценит реактивность. Хочешь под VS Code/Cursor/Windsurf/etc - SDK открыт, пиши .toolpack+bridge, PRы приветствуются. Лучшие тулпаки и тулы готов курировать, тестировать и добавлять в репо.
Почему XML-теги через обычный текст? Потому что нативный Function Calling жестко привязывает к конкретным вендорам, часто ломает стриминг и плохо работает на открытых/локальных моделях. XML-формат универсален для любых сеток. В SDK toolhub встроена базовая санитаризация (игнорирование тегов внутри markdown-блоков с кодом, исправление базовых огрехов JSON вроде одинарных кавычек), но общая культура промптинга и экранирование в UI - это, как и всегда, ответственность архитектуры вашего приложения.
Как это - нет докера? Что значит это фича? Это недоработка! toolhub рассчитан на Local-First / Trusted Node сценарии (когда агент крутится на твоем компе и выполняет ТВОИ скрипты). А если нужен Untrusted режим - докерфайл пишется за 3 секунды любой LLM. Сильно нужен готовый + композ = жду в issues и PR.
А без LLM этим вообще можно пользоваться? Да! ?️ toolhub - это, по сути, сверхлегкий self-hosted FaaS (Function-as-a-Service) с древовидным REST API. Если тебе нужно из Node.js бэкенда прозрачно вызывать Python-скрипты, дергать bash-автоматизацию по вебхукам или централизованно хранить утилиты с логами и версионированием - ты просто используешь REST/SDK напрямую из обычного классического кода без всяких нейросетей.
Три коммита в гитхабе? Четыре дня от роду? И ты предлагаешь мне этим пользоваться? Да так-то нет. Разработку своих проектов я веду локально в Gitea, и делюсь только тем, что действительно заслуживает шейринга. Самому проекту около 5 месяцев, а локальный репо насчитывает на данную секунду 57 коммитов. То же касается и ?lab и всего что я ещё захочу выложить.
Комментарии (16)

gybson_63
10.09.2026 13:44И чем это сильно отличается от skill?

Talos13 Автор
10.09.2026 13:44Примерно тем же, чем идея пожарить картошку отличается от плиты и сковородки.
Покажите ваш конкретный "skill" - подробно на примере и рассмотрим чем отличается.

gybson_63
10.09.2026 13:44Да хоть такой
brave-search-skills/skills/web-search/SKILL.md at main · brave/brave-search-skills
Вообще на curl можно много скилов сделать. Т.е. такие же скилы есть для запуска из командной строки приложений служебных.
Или такое
1c-oData-skill/skills/odata/SKILL.md at main · gybson63/1c-oData-skill
Здесь обертка mcp нужна только потому, что в винде проблема с русским языком бывает в скриптах
Talos13 Автор
10.09.2026 13:44Супер примеры! Это как раз идеальная демонстрация разницы между Prompt-driven подходом и Runtime-driven. Смотрите, оба ваших скилла - это гигантские инструкции на несколько тыщ токенов каждая.
В вашем подходе:
Вы заставляете LLM держать в контексте огромную простыню документации (разницу между OData v3/v4, правила substringof, необходимость собирать Base64 для Basic Auth, URL-encoding кириллицы
%D0%...) и тд.Модель на каждом шаге сама пытается собрать длинную команду для универсального fetch/curl. Она может ошибиться в кавычках, забыть закодировать строку или сгенерировать невалидный заголовок.
Если подключить 5–10 таких интеграций (1С, Brave, GitLab, Jira, Postgres) через скиллы - агент выжрет 20-30k токенов контекста еще до начала диалога.
А сейчас мы возьмём и сделаем, к примеру, второй (потому что он посложнее и поинтереснее как по мне) ваш скилл в виде тула для тулхаба:
Код
import { readFileSync, writeFileSync } from 'fs'; interface Input { entityType: 'Catalog' | 'Document' | 'InformationRegister' | 'AccumulationRegister'; name: string; filter?: string; select?: string; top?: number; } async function run() { try { const input: Input = JSON.parse(readFileSync('input.json', 'utf-8')); const { entityType = 'Catalog', name, filter, select, top = 10 } = input; const baseUrl = process.env.ODATA_URL || 'http://localhost/base/odata/standard.odata'; const user = process.env.ODATA_USER || 'Администратор'; const pass = process.env.ODATA_PASS || 'пароль'; // 1. Авто-кодирование кириллических сущностей 1С (Catalog_Сотрудники -> Catalog_%D0%A1...) const resource = `${entityType}_${encodeURIComponent(name)}`; // 2. Сборка OData v3 Query-параметров const params = new URLSearchParams(); params.append('$format', 'json'); if (top) params.append('$top', top.toString()); if (select) params.append('$select', select); if (filter) params.append('$filter', filter); const auth = 'Basic ' + Buffer.from(`${user}:${pass}`, 'utf-8').toString('base64'); const res = await fetch(`${baseUrl}/${resource}?${params.toString()}`, { headers: { 'Authorization': auth, 'Accept': 'application/json' } }); if (!res.ok) { throw new Error(`1C OData Error ${res.status}: ${await res.text()}`); } const data = await res.json(); // 1C отдает массив записей в поле .value writeFileSync('output.json', JSON.stringify(data.value || data)); } catch (err: any) { writeFileSync('output.json', JSON.stringify({ error: err.message })); } } run();Это псевдокод, с 1C конкретно дел не имею, может потребовать адаптации под реалии, но суть - сколько тысяч токенов и минут сэкономили?)
Итог простой: В случае со SKILL.md мы перекладываем на дорогую и недетерминированную LLM работу парсера, кодировщика строк и генератора curl-команд, попутно сжигая контекст на чтение инструкций. В случае с toolhub - мы отдаём эту рутину обычному коду за 5 миллисек, а модели оставляем только высокоуровневое намерение (“дай сотрудников с фамилией Иванов”), экономя неимоверное количество токенов и своего времени в процессе самой работы, тратя лишь часть его на разработку тула/тулпака.
Вот в этом и есть фундаментальная разница: скилл учит модель, как костылить запрос в терминале, а toolhub даёт готовый атомарный микросервис, знать модели детали реализации которого для эффективной работы досконально не обязательно.
Бонусом: все ваши скиллы model-specific, а тулхабом одинаково не смогут пользоваться разве что уж совсем маленькие и глупые модельки.
Прям рекомендую попробовать в отдельном проекте, если понравится - переносить постепенно все .md на него. Разница в удобстве колоссальная.

gybson_63
10.09.2026 13:44Так в этом и смысл скила и отличие от MCP. Позволяем LLM самому написать, даже, например, запрос T-SQL адекватный именно текущему запросу. Ваш инструмент как обертка над скриптами может быть хорошей идеей. Но это надо доказать. И надо найти границу за которой ваш инструмент не станет тем же Курсором или Кодекс. Вы думаете они там ничего такого не придумали?
Я больше скажу, mcp без соответствующих ему скилов может вообще быть бесполезен полностью, его не смогут позвать.
Т.е. если человек не умеет свистеть, то ему можно дать свисток. Но ему все-равно надо будет объяснить когда, зачем и как свистеть, этого не избежать.
Talos13 Автор
10.09.2026 13:44Позволяем LLM самому написать, даже, например, запрос T-SQL адекватный именно текущему запросу.
Так toolhub ровно это и позволяет! Никто не заставляет хардкодить логику. Вы можете сделать тул
callTool("/db/execute_sql", { "query": "SELECT ... FROM ..." }), где модель сама на лету генерирует любой T-SQL под текущий контекст. Но сам коннект к СУБД, пул соединений, таймауты и отлов ошибок берет на себя рантайм, а не LLM через консольные костыли.И надо найти границу за которой ваш инструмент не станет тем же Курсором или Кодекс. Вы думаете они там ничего такого не придумали?
Именно что придумали! Но они зашили это внутрь своих закрытых, платных и проприетарных экосистем. Та же фича у Claude Code, когда модель сама пишет скрипт и крутит его во временном окружении - это ровно тот же паттерн. Смысл toolhub - дать этот же уровень удобства в виде открытого, self-hosted и ЯП-агностичного Function-as-a-service движка для любой модели (включая локальные через Ollama или в связке со своим UI).
mcp без соответствующих ему скилов может вообще быть бесполезен полностью, его не смогут позвать. Т.е. если человек не умеет свистеть, то ему можно дать свисток. Но ему все-равно надо будет объяснить когда, зачем и как свистеть...
Тут вы на 100% правы, инструмент без контекста применения бесполезен. Возможно, я недостаточно явно подсветил это в статье: в toolhub именно что уже заложен этот механизм, причем иерархически:
На уровне папки (у каждой папки есть appendPrompt - добавочный промпт, его можно как подмешивать в системный так и просто кормить им модель): Когда агент делает
listTools("/1c"), он вместе со списком тулов получает мета-инструкцию: правила предметной области, когда какой тул звать и в каком порядке.На уровне тула (описание конкретного тула + примеры few shots): У каждого инструмента есть не просто типы параметров, а текстовое описание поведения и few-shot примеры входных/выходных данных.
Разница лишь в доставке: мы не вываливаем на модель инструкции ко всем 50 "свисткам" на старте диалога (сжигая все бабки и лимиты), а отдаем объяснение к конкретному "свистку" ровно в тот момент, когда агент зашел в соответствующую категорию.

Zerrdex
10.09.2026 13:44Отличная идея - продолжайте развивать! Хотя инструменты мсп и можно (и нужно) отправлять в кеш, экономия токена, а так же ограничивать аллоу списками отсекая лишние и ненужные, итогом будет понимание, что гораздо дешевле, быстрее и качественнее вызвать короткий точечный скрипт в нужное и заранее известное место.

Talos13 Автор
10.09.2026 13:44Спасибо за поддержку!
В итоге любой инженер неизбежно приходит к пониманию, что детерминированный вызов точечного скрипта с предсказуемым входом/выходом экономит не только токены, но и тонны нервов на отладке недетерминированного поведения модели.
Будем развивать дальше, планов по тулхабу ещё вагон!

gybson_63
10.09.2026 13:44Сейчас все новое и все имеет шанс. Вот например https://github.com/refly-ai/refly

Talos13 Автор
10.09.2026 13:44Согласен! да, на рефли тоже натыкался какое-то время назад. Кстати, они тоже пришли к той же мысли что и мы с вами выше - Skills are not prompts. They are durable infrastructure. Выходит, тоже что-то знают)) правда, рефли это больше про тяжелый энтерпрайз, n8n like графы, очень много интеграций под капотом. Тулхаб таки что-то вроде минималистичный unix-way рантайм, но общая суть безусловно схожа - отделить слой тулинга от слоя мышления.

gybson_63
10.09.2026 13:44Мне, например, в первую очередь было бы важно как можно более точное определение нужного скила. И чтобы в одном месте лежали. Т.е. опять куда-то в сторону MCP это все смещается. Т.е. поверх этой файловой системы скилов еще семантический поиск и тонкая CLI обертка. Примерно как код индексируют.

Talos13 Автор
10.09.2026 13:44Так они сейчас и так лежат в одном месте - единая база, рантайм и админка, а не размазаны по файлам проекта) в том и удобство
А насчёт семантического поиска - мысль отличная. Если тулов наберётся под сотню, эмбеддинги по описаниям категорий как надстройка над деревом прямо напрашиваются, чтобы агент не блуждал по веткам, а сразу прыгал в нужную папку.
Про тонкую CLI/MCP-обёртку - ровно об этом в статье и написал) Stdio-мост на 50 строк, чтобы тот же Claude Code или Cursor видели весь тулхаб как один MCP-сервер - это идеальный юзкейс. Пока в статье возложил это на сообщество, подожду немного - если никто не накидает PR, сам за вечер оформлю. Просто не хотелось с первого же дня превращать ToolHub в очередной обслуживающий адаптер под Claude Code - важнее было показать и обкатать саму концепцию дерева и рантайма в чистом виде.

gybson_63
10.09.2026 13:44у меня свой агент, которого я сделал чтобы мультиагентные системы делать и поэтому мне любое упрощение управления харнесом в тему
r_o_m_k_o_l_a
К разделу про зависшие скрипты: если внутри Python-инструмента тоже запускаются процессы, у Popen.communicate(timeout=...) есть неочевидная особенность. По таймауту он выбрасывает TimeoutExpired, но оставляет процесс работать. В документации для этого случая показаны proc.kill() и повторный proc.communicate(), чтобы дочитать вывод и дождаться завершения. У subprocess.run(timeout=...) завершение дочернего процесса уже встроено. Это полезно учитывать при переносе консольной утилиты в инструмент: иначе агент уже получил ошибку, а запущенная утилита ещё выполняет свою работу. Рецепт: https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate
Talos13 Автор
Ценное предостережение, спасибо!
Если внутри самого Python-скрипта запускаются вложенные сабпроцессы через голый
Popenбезsubprocess.runили обвязкиtry/finallyсproc.kill(), они могут остаться зомби в ОС даже после падения основного скрипта.Со стороны рантайма ToolHub внешний вызов глушится по жесткому таймауту на уровне ОС (через PID родительского процесса и последующую зачистку воркспейса), но чистоплотность внутренних форков внутри самого скрипта - это зона ответственности автора конкретного тула, и об этом важно помнить.
Подождём ещё подобных edge case’ов, и в ридми их в дальнейшем добавлю обязательно.
r_o_m_k_o_l_a
Раз собираете edge cases — два наших, оба про то же место.