Kyno
Kyno
Плоскость согласованности для мультиагентных систем: один версионированный источник истины для миссии и принципов вашей системы (ее конституции), предоставляемый через MCP, чтобы каждый агент мог действовать в соответствии с направлением, действующим прямо сейчас — даже если это направление меняется на лету.
Зачем
Когда цели мультиагентной системы меняются, агенты, хранящие устаревшую копию старого направления, продолжают работать для него — и что хуже, проверки качества по устаревшей копии активно возвращают работу обратно к устаревшей цели. Kyno устраняет устаревшую копию: направление хранится в одном версионированном хранилище, агенты получают текущую версию на каждой границе шага, а подписчики уведомляются в момент ее изменения.
Быстрый старт
pip install . # from a clone; CLI: kyno
kyno init-db
kyno set --mission "Ship a lending product people trust" \
--note "initial constitution"
kyno current
kyno serve --transport stdio # or --transport httpКонституция — это миссия (основная цель — решающий фактор при конфликте принципов) плюс упорядоченные принципы. Каждое изменение добавляет новую неизменяемую версию с примечанием об изменении на простом языке; ничего не редактируется на месте, поэтому на вопрос "каким было направление, когда действовал агент X" всегда можно ответить.
Написание конституции
Принцип в одну строку — это идентификатор, а не правило. Дайте конституции столько, сколько нужно, и не больше — каждый из этих пунктов необязателен:
декларация, полный документ, заголовком которого является миссия;
описание под любым принципом, абзац, разрешающий спор о значении идентификатора.
И то, и другое — проза, а проза через флаги командной строки — мучение, поэтому конституция пишется в файле:
# constitution.yaml
mission: Ship a lending product people trust with their worst month
declaration: |
## What we are for
Lending is a promise about somebody's worst month. We would rather lose
the deal than make a promise we cannot keep.
## What that costs us
- We say no early, in plain words, rather than late in a maze.
- We publish the number before the story that softens it.
principles:
- Say the hard number first
- title: Refuse quietly
description: |
A refusal is a sentence, not a maze. If we cannot lend, say so on the
first screen and say why.
note: the constitution as written
by: camilokyno set --file constitution.yaml
kyno set --file constitution.yaml --constitution eu --note "the EU edit"Декларация — это markdown, и опубликованная страница отображает его: заголовки,
списки, выделение, цитаты, ссылки. Необработанный HTML внутри экранируется, а не
пропускается, а ссылки javascript: отклоняются — страница предоставляется
анонимным посетителям, поэтому ваш собственный текст никогда не может достичь их
в виде исполняемой разметки. Изображения также не отображаются, что сохраняет
страницу как единый самодостаточный ответ.
Во всех остальных местах декларация остается точно в том виде, в котором вы ее
написали: конечная точка JSON, инструменты MCP и kyno export предоставляют
исходный код, а не отрисованный документ.
--note, --by и --constitution могут переопределять файл, потому что они
относятся к этому редактированию, а не к конституции; флаги полей
(--mission, --declaration, --principle) не могут быть объединены с --file,
потому что два источника для одного поля — это вопрос, на который никто не должен
отвечать. Поля, пропущенные в файле, переносятся из предыдущей версии — очистка
обозначается как declaration: "".
Флаги все еще доступны для быстрого редактирования:
kyno set --mission "Ship a lending product people trust" --note "sharpen the mission"Контракт
Через MCP или Python:
get_constitution— направление, действующее сейчас (миссия, принципы, версия).get_changes_since(known_version)— запрос, который агент делает перед шагом: текущее направление плюс примечания об изменениях с момента последней увиденной версии. Пропущенное уведомление безвредно — следующий запрос самодостаточен.get_mission,get_declaration,get_principles,get_principle(title)— по одной части документа, когда компактное чтение их опустило.set_direction(mission?, declaration?, principles?, change_note)— добавить следующую версию. Пропущенные поля переносятся;""очищает поле. По HTTP это требует токена-носителя.
Каждое чтение по умолчанию настолько мало, насколько это возможно —
идентификаторы, а не длинный текст — потому что агент запрашивает перед каждым
шагом и иначе каждый раз получал бы весь документ. Запрашивайте больше, когда это
действительно нужно: detail="full" для двух запросов, detail="full" для
get_principles или одно из целевых чтений. Каждый ответ содержит версию, из
которой он получен, поэтому клиент, смешивающий их, может определить, когда они
разошлись.
Клиенты также могут подписаться на ресурс kyno://constitution/current и
получать стандартное уведомление MCP resources/updated при каждом увеличении
версии. Он предоставляет компактную форму: ресурс не принимает параметров, а весь
документ находится на расстоянии одного вызова инструмента.
Несколько конституций
Один Kyno может содержать несколько конституций одновременно — например, по одной
на линейку продуктов или на юрисдикцию. Каждая операция принимает необязательное
имя constitution, через MCP и в CLI (--constitution eu), и по умолчанию
использует "default", поэтому одноконституционная установка никогда не должна
его упоминать. Каждое имя имеет свою собственную последовательность версий:
увеличение eu до v2 оставляет default на той версии, на которой он был. Имя,
в которое вы никогда не записывали, читается как то же состояние версии 0, что и
нетронутое хранилище. Подписываемый ресурс — это конституция по умолчанию;
агенты, работающие с другой, запрашивают ее по имени с помощью get_changes_since.
Адаптеры (CrewAI, LangGraph)
pip install "kyno[crewai]" # or: pip install "kyno[langgraph]"Адаптер привязывает группу или граф к одному именованному конституции и перепривязывает каждый следующий шаг к версии, действующей прямо сейчас:
from kyno.adapters.core import (
DirectionBinder,
KynoBinding,
McpDirectionSource,
SessionRunner,
http_session,
)
from kyno.adapters.crewai import CrewAiKyno
binding = KynoBinding.from_env(constitution="eu") # KYNO_URL, KYNO_TOKEN
runner = SessionRunner(http_session(binding))
runner.start()
binder = DirectionBinder(McpDirectionSource(runner))
adapter = CrewAiKyno(binder, constitution=binding.constitution)
adapter.register() # injects the current direction before each model call
crew = Crew(..., task_callback=adapter.task_callback) # gates each finished taskВстраиваете Kyno в тот же процесс? Замените источник:
DirectionBinder(LocalDirectionSource(control_plane)).
Запрос перед каждым шагом — текущая миссия и заголовки принципов внедряются в следующий вызов модели, помеченные конституцией и версией, из которой они получены. Этот блок присутствует в каждом вызове модели, поэтому по умолчанию он остается небольшим. Привяжите с помощью
DirectionBinder(source, context="full"), когда вы предпочтете потратить токены: декларация и описания принципов также внедряются, и запрос получает их, а не только идентификаторы. Когда Kyno недоступен — или отвечает чем-то нечитаемым — запрос деградирует: шаг выполняется с последним направлением, которое хранит связка, а устаревание передается как телеметрия. Привяжите с помощьюDirectionBinder(source, policy=PullPolicy(fail_closed=True)), когда ваша позиция — "нет направления, нет работы": шаг вызывает исключение вместо продолжения.Push-потребление —
BackgroundSubscriberпревращает уведомление MCPresources/updatedв повторный запрос по имени. Уже выполняющийся шаг никогда не прерывается; следующий привязывает новое направление.Шлюз перестройки — без модели и проверяется для каждой завершенной задачи (обратный вызов завершения задачи CrewAI), а не после каждого вызова LLM — дешевле и менее шумно, когда подключен реальный судья, и завершенная задача уже является проверяемой единицей. Он вызывает предоставленный вами
VerdictSourceи вызывает исключение (CrewAI, изtask_callback) илиinterrupt()для принятия решения (LangGraph) приDRIFTED. При отсутствии судьи работа продолжается, помеченная какunchecked, и событие передается как телеметрия: по умолчанию пропущенная проверка обменивается на бесперебойный запуск. УстановитеGatePolicy(fail_closed=True)на шлюзе, который должен остановиться.Адаптеры доступны только для чтения — они запрашивают и подписываются;
set_directionостается действием оператора/CLI против Kyno, и никогда не вызывается адаптером от имени группы или графа.
В LangGraph унаследуйте KynoState в схеме состояния вашего графа. LangGraph
несет только ключи, объявленные схемой, поэтому без него направление, полученное
узлом, никогда не достигает узла-шлюза, который оценивает его:
from kyno.adapters.langgraph import KynoState, direction_node, gate_node
class State(KynoState, total=False):
output: strХранилище
SQLite из коробки; PostgreSQL для продакшена через KYNO_DATABASE_URL.
Хранилище подключаемо: передайте SqlConstitutionStore свой собственный Engine
SQLAlchemy для работы внутри существующей базы данных или реализуйте небольшой
протокол хранилища, чтобы полностью использовать собственное постоянство.
Конкурентные писатели безопасны — версии сериализуются уникальным индексом и
повтором, никогда не теряются и не дублируются.
Чтение никогда не завершается ошибкой в пустом хранилище: до установки любого направления потребители получают пустое состояние версии 0, поэтому интеграция Kyno до его внедрения ничего не стоит.
Публикация вашей конституции
Если вы хотите показать людям принципы, которыми, по вашим словам, вы руководствуетесь, Kyno может сам предоставить эту страницу — чтобы опубликованная страница и та, которой подчиняются ваши агенты, были одной и той же записью, а не двумя копиями, которые расходятся.
kyno publish # the default constitution
kyno publish --constitution eu --with-history
kyno unpublish --constitution euПока kyno serve --transport http работает, опубликованная конституция доступна
для чтения любому по адресу:
GET /constitutions/{name}— самодостаточная HTML-страница (без скриптов, без внешних ресурсов, светлая и темная). Декларация является ее телом, отрисованным из markdown, а описанный принцип несет свой абзац.GET /constitutions/{name}.json— то же содержимое, машиночитаемое.GET /constitutions/иGET /constitutions.json— индекс того, что вы опубликовали.
Две вещи, которые стоит знать:
Опубликованное имя должно быть слагом — строчные буквы, цифры и одиночные дефисы (
acme,acme-eu). Это одновременно URL и имя, которое используют ваши агенты, поэтому Kyno отказывается от всего остального, а не молча переписывает. Имена, которые вы никогда не публикуете, не ограничены.Ничто не является публичным, пока вы его не опубликуете, и публикация осуществляется по имени. Один Kyno может содержать вашу внутреннюю конституцию и вашу публичную конституцию бок о бок; публикация второй никак не влияет на первую.
Публикация показывает только текущее направление — миссию, декларацию, принципы, версию, дату последнего изменения. История версий остается приватной, если вы не добавите
--with-history, потому что примечания об изменениях написаны для ваших операторов и обычно объясняют, почему вы изменили курс. Опубликованная история показывает 100 последних версий — это контракт страницы; полная история остается доступной аутентифицированным вызывающим через MCP иkyno export.
Все, что вы не опубликовали, отвечает 404, точно так же, как имя, которое не
существует. Ничто на публичной стороне не раскрывает, какой из двух вариантов это
был.
Настройка под себя
Для изменения цвета — шесть переменных окружения. Установите те, которые вас интересуют, и оставьте остальные:
Переменная | По умолчанию | Что окрашивает |
|
| подчеркивания ссылок, номера принципов |
|
| страница |
|
| основной текст |
|
| метки, даты, отметка версии |
|
| тонкие линии между элементами |
| системный sans |
|
Не установлены — вы получаете встроенный вид с автоматическим темным режимом. Установите любой цвет, и Kyno перестает переключать палитру для темного режима — инвертирование выбранных вами цветов дало бы страницу, которую вы никогда не одобряли, поэтому после этого момента палитра ваша. Установка только шрифта сохраняет темное переключение.
Правильная настройка под себя
Страницы, которые предоставляет Kyno, являются файлами шаблонов, и он передаст вам настоящие:
kyno page export ./pages # constitution.html, index.html, page.cssОтредактируйте их, затем укажите Kyno на ваши копии — он выведет эти две строки для вас:
export KYNO_CONSTITUTION_TEMPLATE=/srv/pages/constitution.html
export KYNO_INDEX_TEMPLATE=/srv/pages/index.html # optionalЭто весь рабочий процесс. То, что вы экспортировали, это то, что Kyno уже отображал — те же файлы, заполненные тем же способом — поэтому вы редактируете рабочую страницу, а не восстанавливаете ее, и все, что вы оставите без изменений, продолжит работать.
kyno page export отказывается перезаписывать файлы, которые уже существуют, и
ничего не записывает, когда должен был бы.
Экспортированный page.css — это отправная точка для ваших собственных стилей:
свяжите его, встройте или выбросьте. Заполнитель $stylesheet ниже всегда
предоставляет стили, встроенные в Kyno, а не вашу их копию — поэтому шаблон,
сохраняющий $stylesheet, остается на стандартном виде (и следует указанным выше
цветовым переменным), а тот, который его удаляет, полностью ваш.
Заполнители
constitution.html
Placeholder | Что это |
| весь блок |
| название конституции |
| миссия, или название, если миссии нет |
| декларация, отрендеренная из markdown, обёрнутая в свой |
| раздел принципов, заголовок и список — пустой, если принципов нет |
| номер версии, например |
| дата последнего изменения, например |
| блок истории версий — пустой, если вы не публиковали историю |
index.html
Placeholder | Что это |
| как выше |
| список опубликованных конституций или строка "ничего не опубликовано" |
| сколько опубликовано |
Каждый блочный плейсхолдер приносит свою обёртку и полностью исчезает, когда ему нечего сказать, поэтому шаблону никогда не приходится спрашивать «а что, если нет декларации». Это сделано намеренно: это плейсхолдеры, а не язык шаблонов — никаких циклов, условий, выражений — и значения по умолчанию подчиняются тому же ограничению, поэтому они являются теми же файлами, которые вы только что экспортировали.
Свойство безопасности, которое это даёт: Kyno экранирует вашу миссию, принципы и заметки об изменениях до того, как они попадут в ваш файл, и рендерит markdown декларации с отключённым HTML, так что никакой шаблон не может превратить текст, введённый кем-то в конституцию, в разметку, которая выполняется. Плейсхолдер, который вы написали с ошибкой, остаётся нетронутым, а не ломает страницу, и если ваш файл отсутствует или не читается при поступлении запроса, Kyno отдаёт свою собственную страницу и записывает предупреждение — плохой шаблон никогда не обрушит вашу публичную страницу.
Аутентификация
stdio: открыто. Процесс, который может запустить сервер, уже владеет файлом базы данных под ним; токен там был бы церемонией, а не границей.
HTTP: общий bearer-токен (
KYNO_TOKEN) защищает каждый запрос к конечной точке MCP (/mcp). Сервер отказывается запускаться без токена по HTTP, если вы явно не согласитесь (KYNO_ALLOW_INSECURE_HTTP, только для локальных экспериментов — он предупреждает), аKYNO_TOKEN, который установлен, но пуст, считается ошибкой конфигурации, а не отсутствием аутентификации. Разработчики, встраивающие приложение в код, соглашаются так же:build_http_app(..., allow_insecure=True). Опубликованные страницы конституций выше находятся за пределами этого шлюза намеренно — это та поверхность, которую вы решили открыть.
Токен на запись — это контроль направления: кто им владеет, тот управляет инструкциями каждого агента, привязанного к этому Kyno. Относитесь к нему как к учётным данным системного промпта — обслуживайте /mcp через TLS и не допускайте попадания токена в логи и контрольные точки (собственные repr Kyno никогда его не печатают). В связи с этим заголовок [kyno:direction …] во внедрённом блоке — это бухгалтерия транскрипта, а не граница подлинности: текст, поступающий от инструментов или пользователей, может его имитировать, поэтому ничто не должно доверять блоку только из-за его вида. Kyno отказывается принимать текст конституции, содержащий маркер, а адаптеры всегда заменяют только тот блок, который они сами внедрили.
Развёртывание
Используйте абсолютный
KYNO_DATABASE_URLв продакшене. Значение по умолчанию (sqlite:///kyno.sqlite3) — это удобство для разработки, которое разрешается относительно рабочей директории, в которой запускается процесс.Запускайте размещённый Kyno за обратным прокси, который применяет ограничение скорости; публичные страницы отвечают на анонимный трафик, и ограничение скорости — это задача прокси, а не Kyno.
Размеры полей являются частью контракта API: миссия ≤ 4 000 символов, декларация ≤ 200 000, заметка об изменении ≤ 2 000, до 100 принципов с заголовками ≤ 300 и описаниями ≤ 4 000, названия конституций ≤ 200.
set_directionотклоняет всё, что больше, а тела запросов/mcpограничены 5 МБ.Установленный через pip Kyno содержит собственные скрипты миграции:
kyno init-dbсоздаёт свежую схему с отметкой текущей головы, аkyno upgrade-dbобновляет существующую базу данных после обновления.
Тестирование
python -m pytest -q # SQLite, no network
KYNO_TEST_POSTGRES_URL=postgresql+psycopg://… python -m pytest -q # + PostgresСвязанный проект: Canon проверяет, действительно ли результаты вашей системы согласуются с конституцией, которую обслуживает Kyno.
См. CONTRIBUTING.md для стиля и ожиданий по тестированию.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Agent-native collaboration network: orchestrate a team of long-running agents from any MCP client.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/cizambra/kyno'
If you have feedback or need assistance with the MCP directory API, please join our Discord server