Skip to main content
Glama

Kyno

一个用于多智能体系统的一致性控制平面:为系统的使命和原则(即其宪法)提供单一版本化的事实来源,通过 MCP 提供服务,使每个智能体能够按照当前生效的方向行动——即使该方向在运行过程中发生变化。

为什么

当多智能体系统的目标发生变化时,持有旧方向副本的智能体会继续为旧目标产出工作——更糟的是,基于旧副本的质量检查会主动将工作推回过时的目标。Kyno 消除了旧副本:方向存储在一个版本化的仓库中,智能体在每个步骤边界拉取当前版本,订阅者会在方向变化时立即收到通知。

Related MCP server: Gigabrain

快速开始

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: camilo
kyno set --file constitution.yaml
kyno set --file constitution.yaml --constitution eu --note "the EU edit"

宣言是 markdown 格式,发布的页面会渲染它:标题、列表、强调、引用、链接。其中的原始 HTML 会被转义而非直接传递,javascript: 链接会被拒绝——页面是提供给匿名访问者的,因此你的文本不能作为可执行的标记到达他们。图片也不会被渲染,这保持了页面作为单个自包含响应的特性。

在其他地方,宣言保持你编写的 markdown 原样: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 上,这需要 bearer token。

每次读取默认尽可能小——只返回标识,而非长文本——因为智能体在每个步骤前都会拉取,否则每次都要获取整个文档。当真正需要时再请求更多内容:在两个拉取中使用 detail="full",在 get_principles 中使用 detail="full",或者使用定向读取。每个响应都包含来源的版本号,因此混合使用不同响应的客户端可以判断它们是否已经不一致。

客户端还可以订阅 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]"

适配器将 crew 或 graph 绑定到一个命名宪法,并在每个下一步骤重新绑定到当前生效的版本:

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))。

  • 每个步骤前拉取 — 当前使命和原则标题被注入到下一个模型调用中,并带有来源的宪法名称和版本号。该块会随每个模型调用一起发送,因此默认保持较小。当你愿意花费更多 token 时,使用 DirectionBinder(source, context="full") 绑定:宣言和原则描述也会被注入,拉取会获取它们而不仅仅是标识。当 Kyno 不可达时——或者返回无法读取的内容时——拉取会降级:步骤使用绑定器持有的最后方向运行,并且过时性作为遥测数据发出。当你的姿态是“没有方向,没有工作”时,使用 DirectionBinder(source, policy=PullPolicy(fail_closed=True)) 绑定:步骤会抛出异常而不是继续执行。

  • 推送消费 — BackgroundSubscriber 将 MCP resources/updated 通知转换为按名称的重新拉取。已经正在运行的步骤不会被中断;下一个步骤会绑定新方向。

  • 重新对齐门控 — 无模型,并且按已完成任务(CrewAI 的任务完成回调)审查,而不是在每个 LLM 调用后——更便宜,在附加了真正的评判者后噪声更少,并且已完成的任务已经是可审查的单位。它调用你提供的 VerdictSource,并在 DRIFTED 时抛出异常(CrewAI,从 task_callback)或interrupt() 以等待决策(LangGraph)。当没有可用的评判者时,工作继续进行,标记为 unchecked,并且事件作为遥测数据发出:默认情况下,用跳过的检查换取不间断的运行。在应该停止的门控上设置 GatePolicy(fail_closed=True)。

  • 适配器是只读的 — 它们拉取和订阅;set_direction 仍然是针对 Kyno 的操作员/CLI 操作,适配器永远不会代表 crew 或 graph 调用它。

在 LangGraph 上,在你的 graph 状态模式中继承 KynoState。LangGraph 只携带模式声明的键,因此如果没有它,节点拉取的方向永远不会到达对其进行评判的门控节点:

from kyno.adapters.langgraph import KynoState, direction_node, gate_node


class State(KynoState, total=False):
    output: str

存储

开箱即用 SQLite;生产环境通过 KYNO_DATABASE_URL 使用 PostgreSQL。存储是可插拔的:将你自己的 SQLAlchemy Engine 交给 SqlConstitutionStore 以在现有数据库中使用,或者实现小型存储协议以完全自行实现持久化。并发写入是安全的——版本通过唯一索引和重试序列化,不会丢失或重复。

读取永远不会在空存储上失败:在任何方向设置之前,消费者会获得版本 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 — 已发布内容的索引。

有两件事值得了解:

  • 发布名称必须是 slug — 小写字母、数字和单个连字符(acme、acme-eu)。它既是 URL 也是你的智能体使用的名称,因此 Kyno 会拒绝任何其他内容,而不是静默重写。从未发布的名称没有限制。

  • 在发布之前,没有任何内容是对外公开的,发布是按名称进行的。一个 Kyno 可以同时保存你的内部宪法和公开宪法;发布第二个不会影响第一个。

  • 发布只显示当前方向 — 使命、宣言、原则、版本、最后更改日期。版本历史保持私有,除非你添加 --with-history,因为变更说明是为你的操作员编写的,并且通常会解释为什么你改变了方向。已发布的历史显示最近的 100 个版本——这是页面的契约;完整历史仍可通过 MCP 和 kyno export 对经过身份验证的调用者可用。

你未发布的任何内容都会返回 404,就像不存在的名称一样。公共方面不会透露它是两者中的哪一个。

个性化设置

对于颜色调整,有六个环境变量。设置你关心的变量,其余保持默认:

变量

默认值

作用域

KYNO_PAGE_ACCENT

#6d6d66

链接下划线、原则编号

KYNO_PAGE_BACKGROUND

#fbfbf9

页面背景

KYNO_PAGE_TEXT

#1b1b19

正文文本

KYNO_PAGE_MUTED

#6d6d66

标签、日期、版本戳

KYNO_PAGE_RULE

#e4e3de

项目之间的分隔线

KYNO_PAGE_FONT

系统无衬线体

页面的 font-family

未设置时,你会得到内置外观,并自动切换暗色模式。设置任何颜色后,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

占位符

含义

$stylesheet

整个 <style> 块:颜色变量 + Kyno 的页面样式

$name

章程的名称

$mission

使命,若无使命则为名称

$declaration

从 Markdown 渲染的声明,包裹在其 <div> 中——若无则为空

$principles

原则部分,包含标题和列表——若无原则则为空

$version

版本号,例如 3

$updated

最后修改日期,例如 2026-08-13

$history

版本历史块——除非您发布了历史,否则为空

index.html

占位符

含义

$stylesheet

同上

$items

已发布章程的列表,或“尚未发布任何内容”行

$count

已发布的数量

每个块占位符都会自带其包装,并在无内容时完全消失,因此模板永远无需询问“如果没有声明怎么办”。这是有意为之:这些是 占位符,而非模板语言——没有循环、无条件判断、无表达式——默认值也遵循同样的限制,这就是为什么它们与您刚刚导出的文件相同。

由此获得的安全性:Kyno 会在您的使命、原则和变更说明到达文件之前对其进行转义,并以禁用 HTML 的方式渲染您声明的 Markdown,因此任何模板都无法将某人在章程中输入的文本转换为可运行的标记。您拼写错误的占位符会被原样保留,不会导致页面崩溃;如果请求到达时您的文件缺失或不可读,Kyno 会提供自己的页面并记录警告——糟糕的模板绝不会让您的公共页面下线。

认证

  • stdio:开放。能够启动服务器的进程已经拥有其下的数据库文件;在此处增加令牌只会是形式,而非边界。

  • HTTP:共享的 Bearer 令牌(KYNO_TOKEN)对 MCP 端点(/mcp)的每个请求进行门控。除非您明确选择加入(KYNO_ALLOW_INSECURE_HTTP,仅限本地实验——它会发出警告),否则服务器拒绝在没有令牌的情况下通过 HTTP 启动;设置为空的 KYNO_TOKEN 会被视为配置错误,而不是静默地不启用认证。以代码方式构建应用的嵌入者以相同方式选择加入:build_http_app(..., allow_insecure=True)。上述已发布的章程页面有意位于该门控之外——它们是您选择公开的表面。

写入令牌是方向控制:持有它的人能够引导绑定到此 Kyno 的每个代理的指令。请将其视为系统提示凭据——通过 TLS 提供 /mcp 服务,并将令牌排除在日志和检查点之外(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 MB。

  • 通过 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。

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP+HTTP control plane for routing work to multiple coding-agent CLIs through a normalized contract, enabling multi-agent coding pipelines with planning, implementation, review, and revision.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A durable MCP control plane for starting, observing, steering, continuing, cancelling, and handing off long-running coding agents, with bounded MCP calls and persistent worktrees.
    5 npm
    MIT