Kyno
Kyno
Un plano de control de coherencia para sistemas multiagente: una única fuente de verdad versionada para la misión y los principios de tu sistema (su constitución), servida a través de MCP para que cada agente pueda actuar según la dirección vigente ahora mismo — incluso cuando esa dirección cambia en pleno vuelo.
Por qué
Cuando los objetivos de un sistema multiagente cambian, los agentes que tienen una copia obsoleta de la dirección anterior siguen produciendo trabajo para ella — y peor aún, las comprobaciones de calidad contra la copia obsoleta empujan activamente el trabajo hacia atrás, hacia el objetivo obsoleto. Kyno elimina la copia obsoleta: la dirección reside en un almacén versionado, los agentes obtienen la versión actual en cada límite de paso, y los suscriptores son notificados en el momento en que cambia.
Inicio rápido
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 httpUna constitución es una misión (el propósito general — el desempate cuando los principios entran en conflicto) más principios ordenados. Cada cambio añade una nueva versión inmutable con una nota de cambio en lenguaje sencillo; nada se edita en su lugar, por lo que siempre se puede responder a "¿cuál era la dirección cuando actuó el agente X?".
Redactar una
Un principio de una línea es un identificador, no una regla. Dale a una constitución todo lo que necesite y nada más — cada uno de estos es opcional:
una declaración, el documento extenso del cual la misión es el titular;
una descripción bajo cualquier principio, el párrafo que resuelve una discusión sobre lo que significa el identificador.
Ambos son prosa, y la prosa a través de banderas de línea de comandos es un suplicio, por lo que una constitución se escribe en un archivo:
# 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"La declaración es markdown, y la página publicada la renderiza: encabezados, listas, énfasis, citas, enlaces. El HTML sin procesar dentro de ella se escapa en lugar de pasarse, y los enlaces javascript: son rechazados — la página se sirve a visitantes anónimos, por lo que tu propio texto nunca puede llegar a ellos como marcado que se ejecuta. Las imágenes tampoco se renderizan, lo que mantiene la página como una única respuesta autocontenida.
En todos los demás lugares, la declaración permanece exactamente como el markdown que escribiste: el endpoint JSON, las herramientas MCP y kyno export sirven la fuente, no el documento renderizado.
--note, --by y --constitution pueden anular el archivo, porque se refieren a esta edición y no a la constitución; las banderas de campo (--mission, --declaration, --principle) no se pueden combinar con --file, porque dos fuentes para un mismo campo es una pregunta que nadie debería tener que responder. Los campos que el archivo omite se trasladan de la versión anterior — borrar uno se escribe declaration: "".
Las banderas siguen ahí para una edición rápida:
kyno set --mission "Ship a lending product people trust" --note "sharpen the mission"El contrato
A través de MCP o Python:
get_constitution— la dirección vigente ahora (misión, principios, versión).get_changes_since(known_version)— la extracción que hace un agente antes de un paso: la dirección actual más las notas de cambio desde la versión que vio por última vez. Una notificación perdida es inofensiva — la siguiente extracción se describe a sí misma.get_mission,get_declaration,get_principles,get_principle(title)— una pieza del documento cada una, para cuando una lectura compacta la omitió.set_direction(mission?, declaration?, principles?, change_note)— añade la siguiente versión. Los campos omitidos se trasladan;""borra uno. En HTTP esto requiere el token de portador.
Cada lectura es tan pequeña como puede ser por defecto — identificadores, no el texto largo — porque un agente extrae antes de cada paso y de otro modo compraría el documento completo cada vez. Pide más cuando algo realmente lo necesite: detail="full" en las dos extracciones, detail="full" en get_principles, o una de las lecturas específicas. Cada respuesta lleva la versión de la que proviene, por lo que un cliente que las mezcla puede saber cuándo se han desviado.
Los clientes también pueden suscribirse al recurso kyno://constitution/current y recibir una notificación estándar de MCP resources/updated en cada incremento de versión. Sirve la forma compacta: un recurso no toma parámetros, y el documento completo está a una llamada de herramienta de distancia.
Múltiples constituciones
Un solo Kyno puede contener varias constituciones simultáneamente — por ejemplo, una por línea de producto o por jurisdicción. Cada operación toma un nombre de constitution opcional, tanto en MCP como en la CLI (--constitution eu), y por defecto es "default", por lo que una configuración de una sola constitución nunca tiene que mencionarlo. Cada nombre tiene su propia secuencia de versiones: incrementar eu a v2 deja default en la versión que tuviera. Un nombre al que nunca has escrito se lee como el mismo estado vacío de versión 0 que un almacén no tocado. El recurso suscribible es la constitución predeterminada; los agentes en otra la obtienen por nombre con get_changes_since.
Adaptadores (CrewAI, LangGraph)
pip install "kyno[crewai]" # or: pip install "kyno[langgraph]"Un adaptador vincula un crew o un grafo a una constitución nombrada y lo re-vincula en cada siguiente paso a la versión vigente en ese momento:
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¿Integrar Kyno en el mismo proceso en su lugar? Cambia la fuente: DirectionBinder(LocalDirectionSource(control_plane)).
Extraer antes de cada paso — la misión actual y los títulos de los principios se inyectan en la siguiente llamada al modelo, etiquetados con la constitución y la versión de la que provienen. Ese bloque viaja en cada llamada al modelo, por lo que se mantiene pequeño por defecto. Vincula con
DirectionBinder(source, context="full")cuando prefieras gastar los tokens: la declaración y las descripciones de los principios también se inyectan, y la extracción las obtiene en lugar de solo los identificadores. Cuando Kyno no está disponible — o responde con algo ilegible — la extracción se degrada: el paso se ejecuta con la última dirección que tiene el binder, y la obsolescencia se emite como telemetría. Vincula conDirectionBinder(source, policy=PullPolicy(fail_closed=True))cuando tu postura sea "sin dirección, sin trabajo": el paso lanza una excepción en lugar de continuar.Consumo push —
BackgroundSubscriberconvierte una notificación de MCPresources/updateden una re-extracción por nombre. Un paso que ya se está ejecutando nunca se interrumpe; el siguiente vincula la nueva dirección.Puerta de realineación — sin modelo, y revisada por tarea finalizada (callback de finalización de tarea de CrewAI), no después de cada llamada LLM — más barato y menos ruidoso una vez que se adjunta un juez real, y la tarea finalizada ya es la unidad revisable. Llama a un
VerdictSourceque tú proporcionas y lanza una excepción (CrewAI, desdetask_callback) ointerrupt()para una decisión (LangGraph) enDRIFTED. Con ningún juez disponible, el trabajo continúa, marcado comounchecked, y el evento se emite como telemetría: el valor predeterminado cambia una verificación omitida por una ejecución ininterrumpida. EstableceGatePolicy(fail_closed=True)en una puerta que debería detenerse en su lugar.Los adaptadores son de solo lectura — extraen y se suscriben;
set_directionsigue siendo una acción de operador/CLI contra Kyno, nunca algo que un adaptador llame en nombre de un crew o un grafo.
En LangGraph, hereda KynoState en el esquema de estado de tu grafo. LangGraph solo lleva las claves que declara un esquema, por lo que sin él, la dirección que extrae un nodo nunca llega al nodo de puerta que juzga contra ella:
from kyno.adapters.langgraph import KynoState, direction_node, gate_node
class State(KynoState, total=False):
output: strAlmacenamiento
SQLite de serie; PostgreSQL para producción a través de KYNO_DATABASE_URL. El almacenamiento es conectable: entrega SqlConstitutionStore tu propio Engine de SQLAlchemy para vivir dentro de una base de datos existente, o implementa el pequeño protocolo de almacenamiento para traer tu propia persistencia por completo. Los escritores concurrentes son seguros: las versiones se serializan mediante un índice único y un reintento, nunca se pierden ni duplican.
Las lecturas nunca fallan en un almacén vacío: antes de establecer cualquier dirección, los consumidores obtienen un estado vacío de versión 0, por lo que integrar Kyno antes de adoptarlo no cuesta nada.
Publicar tu constitución
Si quieres mostrar a la gente los principios por los que dices operar, Kyno puede servir esa página por sí mismo — así la página publicada y la que obedecen tus agentes son el mismo registro, no dos copias que se desvían.
kyno publish # the default constitution
kyno publish --constitution eu --with-history
kyno unpublish --constitution euMientras kyno serve --transport http se está ejecutando, una constitución publicada es legible por cualquiera en:
GET /constitutions/{name}— una página HTML autocontenida (sin scripts, sin activos externos, claro y oscuro). La declaración es el cuerpo de la misma, renderizada a partir de markdown, y un principio descrito lleva su párrafo.GET /constitutions/{name}.json— el mismo contenido, legible por máquina.GET /constitutions/yGET /constitutions.json— un índice de lo que has publicado.
Dos cosas que vale la pena saber:
Un nombre publicado debe ser un slug — letras minúsculas, dígitos y guiones simples (
acme,acme-eu). Es tanto la URL como el nombre que usan tus agentes, por lo que Kyno rechaza cualquier otra cosa en lugar de reescribirlo silenciosamente. Los nombres que nunca publicas no tienen restricciones.Nada es público hasta que lo publicas, y la publicación es por nombre. Un solo Kyno puede contener tu constitución interna y tu constitución pública una al lado de la otra; publicar la segunda no afecta a la primera.
Publicar muestra solo la dirección actual — misión, declaración, principios, versión, fecha del último cambio. El historial de versiones permanece privado a menos que añadas
--with-history, porque las notas de cambio están escritas para tus operadores y explican rutinariamente por qué cambiaste de rumbo. Un historial publicado muestra las 100 versiones más recientes — ese es el contrato de la página; el historial completo permanece disponible para llamantes autenticados a través de MCP ykyno export.
Cualquier cosa que no hayas publicado responde 404, exactamente como lo haría un nombre que no existe. Nada en el lado público revela cuál de los dos era.
Personalizarlo
Para un cambio de color, seis variables de entorno. Establece las que te importen y deja el resto:
Variable | Valor por defecto | Qué colorea |
|
| subrayados de enlaces, números de principios |
|
| la página |
|
| texto del cuerpo |
|
| etiquetas, fechas, el sello de versión |
|
| las líneas finas entre elementos |
| sans-serif del sistema |
|
Sin establecer, obtienes el aspecto incorporado, con su modo oscuro automático. Establece cualquier color y Kyno deja de intercambiar la paleta para el modo oscuro — invertir colores que elegiste te daría una página que nunca aprobaste, por lo que a partir de ese punto la paleta es tuya. Establecer solo la fuente mantiene el intercambio oscuro.
Personalizarlo correctamente
Las páginas que Kyno sirve son archivos de plantilla, y te entregará las reales:
kyno page export ./pages # constitution.html, index.html, page.cssEdítalos, luego apunta Kyno a tus copias — imprime estas dos líneas por ti:
export KYNO_CONSTITUTION_TEMPLATE=/srv/pages/constitution.html
export KYNO_INDEX_TEMPLATE=/srv/pages/index.html # optionalEse es todo el flujo de trabajo. Lo que exportaste es lo que Kyno ya estaba renderizando — los mismos archivos, rellenados de la misma manera — por lo que estás editando una página funcional en lugar de reconstruir una, y cualquier cosa que dejes intacta sigue funcionando.
kyno page export se niega a sobrescribir archivos que ya están ahí, y no escribe nada en absoluto cuando tendría que hacerlo.
El page.css exportado es un punto de partida para tus propios estilos: enlácelo, incrústalo o tíralo. El marcador de posición $stylesheet a continuación siempre sirve los estilos integrados en Kyno, no tu copia de ellos — por lo que una plantilla que conserva $stylesheet se mantiene en el aspecto de la casa (y sigue las variables de color anteriores), y una que lo elimina es completamente tuya.
Marcadores de posición
constitution.html
Marcador de posición | Qué es |
| todo el bloque |
| el nombre de la constitución |
| la misión, o el nombre cuando no hay misión |
| la declaración renderizada desde markdown, envuelta en su |
| la sección de principios, encabezado y lista — vacía cuando no hay |
| el número de versión, ej. |
| la fecha de última modificación, ej. |
| el bloque de historial de versiones — vacío a menos que hayas publicado el historial |
index.html
Marcador de posición | Qué es |
| como arriba |
| la lista de constituciones publicadas, o la línea "nada publicado aún" |
| cuántas están publicadas |
Cada marcador de posición de bloque trae su propio envoltorio y desaparece por completo cuando no tiene nada que decir, por lo que una plantilla nunca tiene que preguntar "¿y si no hay declaración?". Esto es deliberado: son marcadores de posición, no un lenguaje de plantillas — sin bucles, sin condiciones, sin expresiones — y los valores predeterminados se mantienen bajo el mismo límite, por lo que son los mismos archivos que acabas de exportar.
La propiedad de seguridad que esto aporta: Kyno escapa tu misión, principios y notas de cambio antes de que lleguen a tu archivo, y renderiza el markdown de tu declaración con HTML deshabilitado, por lo que ninguna plantilla puede convertir texto escrito por alguien en una constitución en marcado que se ejecute. Un marcador de posición mal escrito se deja intacto en lugar de romper la página, y si tu archivo falta o es ilegible cuando llega una solicitud, Kyno sirve su propia página y registra una advertencia — una plantilla defectuosa nunca derriba tu página pública.
Autenticación
stdio: abierto. Un proceso que puede iniciar el servidor ya posee el archivo de base de datos bajo él; un token allí sería ceremonia, no un límite.
HTTP: un token portador compartido (
KYNO_TOKEN) protege cada solicitud al endpoint MCP (/mcp). El servidor se niega a iniciarse sin token sobre HTTP a menos que optes explícitamente (KYNO_ALLOW_INSECURE_HTTP, solo para experimentación local — advierte), y unKYNO_TOKENque está configurado pero en blanco es un error de configuración en lugar de una ausencia silenciosa de autenticación. Los integradores que construyen la aplicación en código optan de la misma manera:build_http_app(..., allow_insecure=True). Las páginas de constitución publicadas arriba están fuera de esa puerta a propósito — son la superficie que elegiste abrir.
El token de escritura es control de dirección: quien lo posee dirige las instrucciones de cada agente vinculado a este Kyno. Trátalo como una credencial de aviso del sistema — sirve /mcp sobre TLS y mantén el token fuera de registros y puntos de control (las representaciones de Kyno nunca lo imprimen). Relacionadamente, el encabezado [kyno:direction …] en el bloque inyectado es contabilidad de transcripción, no un límite de autenticidad: el texto que llega de herramientas o usuarios puede imitarlo, por lo que nada debería confiar en un bloque por parecerse a uno. Kyno rechaza el texto de la constitución que contenga el marcador, y los adaptadores solo reemplazan el bloque que ellos mismos inyectaron.
Despliegue
Usa una
KYNO_DATABASE_URLabsoluta en producción. El valor predeterminado (sqlite:///kyno.sqlite3) es una conveniencia de desarrollo que se resuelve contra el directorio de trabajo en el que se inicia el proceso.Ejecuta un Kyno alojado detrás de un proxy inverso que aplique límites de tasa; las páginas públicas responden a tráfico anónimo, y la limitación de tasa es trabajo del proxy, no de Kyno.
Los tamaños de campo son parte del contrato de la API: misión ≤ 4,000 caracteres, declaración ≤ 200,000, nota de cambio ≤ 2,000, hasta 100 principios con títulos ≤ 300 y descripciones ≤ 4,000, nombres de constitución ≤ 200.
set_directionrechaza cualquier cosa más grande, y los cuerpos de solicitud/mcpestán limitados a 5 MB.Un Kyno instalado con pip lleva sus propios scripts de migración:
kyno init-dbcrea un esquema nuevo sellado en la cabecera actual, ykyno upgrade-dbactualiza una base de datos existente después de una actualización.
Pruebas
python -m pytest -q # SQLite, no network
KYNO_TEST_POSTGRES_URL=postgresql+psycopg://… python -m pytest -q # + PostgresProyecto hermano: Canon prueba si las salidas de tu sistema realmente cohesionan con la constitución que Kyno sirve.
Consulta CONTRIBUTING.md para expectativas de estilo y pruebas.
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