Skip to main content
Glama

Kyno

멀티 에이전트 시스템을 위한 일관성 제어 평면(coherence control plane): 시스템의 미션과 원칙(즉, 헌법)에 대한 하나의 버전 관리된 진실 공급원(source of truth)으로, 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가 행동할 당시의 방향은 무엇이었는가"에 항상 답할 수 있습니다.

헌법 작성하기

한 줄짜리 원칙은 핸들이지 규칙이 아닙니다. 헌법에 필요한 만큼만 부여하고 그 이상은 부여하지 마십시오 — 다음 각 항목은 선택 사항입니다:

  • 선언문(declaration), 미션이 헤드라인인 긴 형식의 문서;

  • 모든 원칙 아래의 설명(description), 핸들이 무엇을 의미하는지에 대한 논쟁을 해결하는 단락.

둘 다 산문(prose)이며, 명령줄 플래그를 통한 산문은 고통스럽기 때문에 헌법은 파일에 작성됩니다:

# 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"

선언문은 마크다운이며, 게시된 페이지는 이를 렌더링합니다: 제목, 목록, 강조, 인용, 링크. 내부의 원시 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"

계약(Contract)

MCP 또는 Python을 통해:

  • get_constitution — 현재 적용되는 방향(미션, 원칙, 버전).

  • get_changes_since(known_version) — 에이전트가 단계 전에 수행하는 풀(pull): 현재 방향과 마지막으로 본 버전 이후의 변경 노트. 놓친 알림은 무해합니다 — 다음 풀은 자체 설명적입니다.

  • get_mission, get_declaration, get_principles, get_principle(title) — 각각 문서의 한 부분으로, 간결한 읽기가 생략된 경우에 사용합니다.

  • set_direction(mission?, declaration?, principles?, change_note) — 다음 버전을 추가합니다. 생략된 필드는 이월됩니다; ""는 필드를 지웁니다. HTTP에서는 베어러 토큰이 필요합니다.

모든 읽기는 기본적으로 가능한 한 작습니다 — 핸들만, 긴 텍스트는 없습니다 — 에이전트가 각 단계 전에 풀을 수행하고 그렇지 않으면 매번 전체 문서를 구매해야 하기 때문입니다. 실제로 필요할 때 더 많은 것을 요청하십시오: 두 풀에 detail="full", get_principlesdetail="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) 또는 그래프를 하나의 명명된 헌법에 바인딩하고, 다음 단계마다 현재 적용되는 버전으로 다시 바인딩합니다:

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에 연결할 수 없거나 읽을 수 없는 응답을 반환하면 풀이 저하됩니다: 단계는 바인더가 보유한 마지막 방향으로 실행되며, 오래됨(staleness)은 텔레메트리로 방출됩니다. "방향 없음, 작업 없음" 자세를 취할 때는 DirectionBinder(source, policy=PullPolicy(fail_closed=True))로 바인딩하십시오: 단계는 진행 대신 예외를 발생시킵니다.

  • 푸시 소비BackgroundSubscriber는 MCP resources/updated 알림을 이름별 재풀로 전환합니다. 이미 실행 중인 단계는 중단되지 않습니다; 다음 단계는 새 방향을 바인딩합니다.

  • 재정렬 게이트(Realignment gate) — 모델이 없으며, 완료된 작업당 검토됩니다(CrewAI의 작업 완료 콜백), 모든 LLM 호출 후가 아닙니다 — 실제 판사가 연결되면 더 저렴하고 덜 시끄럽습니다. 완료된 작업은 이미 검토 가능한 단위입니다. 사용자가 제공한 VerdictSource를 호출하고 DRIFTED 시 (CrewAI에서는 task_callback에서) 예외를 발생시키거나 (LangGraph에서는) 결정을 위해 interrupt()합니다. 사용 가능한 판사가 없으면 작업은 unchecked로 표시되어 진행되며, 이벤트는 텔레메트리로 방출됩니다: 기본값은 중단되지 않은 실행을 위해 검사 건너뛰기를 선택합니다. 중단해야 하는 게이트에는 GatePolicy(fail_closed=True)를 설정하십시오.

  • 어댑터는 읽기 전용입니다 — 풀하고 구독합니다; set_direction은 Kyno에 대한 운영자/CLI 작업으로 유지되며, 어댑터가 크루나 그래프를 대신하여 호출하지 않습니다.

LangGraph에서는 그래프의 상태 스키마에 KynoState를 상속하십시오. LangGraph는 스키마가 선언한 키만 전달하므로, 이것이 없으면 노드가 풀한 방향이 이를 기준으로 판단하는 게이트 노드에 도달하지 않습니다:

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


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

저장소

기본적으로 SQLite; 프로덕션에서는 KYNO_DATABASE_URL을 통해 PostgreSQL을 사용합니다. 저장소는 플러그 가능합니다: SqlConstitutionStore에 사용자 고유의 SQLAlchemy Engine을 전달하여 기존 데이터베이스 내에 위치시키거나, 작은 저장소 프로토콜을 구현하여 완전히 자체적인 지속성을 가져올 수 있습니다. 동시 쓰기는 안전합니다 — 버전은 고유 인덱스와 재시도에 의해 직렬화되며, 손실되거나 중복되지 않습니다.

읽기는 빈 저장소에서 절대 실패하지 않습니다: 방향이 설정되기 전에 소비자는 버전 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 페이지(스크립트 없음, 외부 자산 없음, 라이트 및 다크 모드). 선언문은 본문이며, 마크다운에서 렌더링되고, 설명이 있는 원칙은 해당 단락을 포함합니다.

  • GET /constitutions/{name}.json — 동일한 내용, 기계 판독 가능.

  • GET /constitutions/GET /constitutions.json — 게시한 내용의 인덱스.

알아야 할 두 가지 사항:

  • 게시된 이름은 슬러그여야 합니다 — 소문자, 숫자 및 단일 하이픈(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

Placeholder

What it is

$stylesheet

전체 <style> 블록: 색상 변수 + Kyno의 페이지 스타일

$name

헌법의 이름

$mission

미션, 또는 미션이 없을 때는 이름

$declaration

마크다운에서 렌더링된 선언문, 해당 <div>로 감싸짐 — 없으면 비어 있음

$principles

원칙 섹션, 제목 및 목록 — 없으면 비어 있음

$version

버전 번호, 예: 3

$updated

마지막 변경 날짜, 예: 2026-08-13

$history

버전 기록 블록 — 기록을 게시하지 않으면 비어 있음

index.html

Placeholder

What it is

$stylesheet

위와 동일

$items

게시된 헌법 목록, 또는 "아직 게시된 항목 없음" 줄

$count

게시된 개수

각 블록 플레이스홀더는 자체 래퍼를 가져오며, 할 말이 없으면 완전히 사라집니다. 따라서 템플릿은 "선언문이 없으면 어떻게 하지?"라고 묻지 않아도 됩니다. 이는 의도적인 것입니다. 이들은 플레이스홀더이지 템플릿 언어가 아닙니다 — 루프, 조건, 표현식이 없으며 — 기본값도 동일한 제한을 따릅니다. 그래서 방금 내보낸 파일과 동일한 파일인 것입니다.

이로 인해 얻는 안전 속성: Kyno는 미션, 원칙 및 변경 노트를 파일에 도달하기 전에 이스케이프 처리하고, 선언문의 마크다운을 HTML 비활성화 상태로 렌더링합니다. 따라서 어떤 템플릿도 누군가가 헌법에 입력한 텍스트를 실행 가능한 마크업으로 바꿀 수 없습니다. 철자가 틀린 플레이스홀더는 페이지를 망가뜨리지 않고 그대로 남겨지며, 요청이 도착했을 때 파일이 없거나 읽을 수 없는 경우 Kyno는 자체 페이지를 제공하고 경고를 기록합니다 — 잘못된 템플릿이 공개 페이지를 다운시키는 일은 없습니다.

Auth

  • stdio: 열려 있음. 서버를 생성할 수 있는 프로세스는 이미 그 아래의 데이터베이스 파일을 소유하고 있습니다. 거기에 토큰을 추가하는 것은 의례일 뿐 경계가 아닙니다.

  • HTTP: 공유 베어러 토큰(KYNO_TOKEN)이 MCP 엔드포인트(/mcp)에 대한 모든 요청을 제어합니다. 서버는 명시적으로 옵트인하지 않는 한(KYNO_ALLOW_INSECURE_HTTP, 로컬 실험 전용 — 경고 표시) HTTP에서 토큰 없이 시작을 거부하며, 설정되었지만 비어 있는 KYNO_TOKEN은 조용히 인증 없음으로 처리되지 않고 구성 오류로 간주됩니다. 코드로 앱을 빌드하는 임베더도 동일한 방식으로 옵트인합니다: build_http_app(..., allow_insecure=True). 위에 있는 게시된 헌법 페이지는 의도적으로 그 게이트 밖에 있습니다 — 이는 여러분이 열기로 선택한 표면입니다.

쓰기 토큰은 방향 제어입니다: 이를 보유한 사람은 이 Kyno에 바인딩된 모든 에이전트의 지침을 조종합니다. 시스템 프롬프트 자격 증명처럼 취급하세요 — TLS를 통해 /mcp를 제공하고 토큰을 로그와 체크포인트에서 제외하세요 (Kyno 자체 repr은 절대 출력하지 않습니다). 관련하여, 주입된 블록의 [kyno:direction …] 헤더는 대화 기록용 북키핑일 뿐, 진위 경계가 아닙니다: 도구나 사용자로부터 도착한 텍스트가 이를 모방할 수 있으므로, 블록이 그렇게 보인다고 해서 신뢰해서는 안 됩니다. Kyno는 해당 마커를 포함하는 헌법 텍스트를 거부하며, 어댑터는 자신이 주입한 블록만 교체합니다.

Deploying

  • 프로덕션에서는 **절대 경로의 KYNO_DATABASE_URL**을 사용하세요. 기본값(sqlite:///kyno.sqlite3)은 프로세스가 시작되는 작업 디렉터리를 기준으로 해석되는 개발 편의용입니다.

  • 호스팅된 Kyno를 속도 제한을 적용하는 리버스 프록시 뒤에서 실행하세요. 공개 페이지는 익명 트래픽에 응답하며, 속도 제한은 Kyno가 아닌 프록시의 역할입니다.

  • 필드 크기는 API 계약의 일부입니다: 미션 ≤ 4,000자, 선언문 ≤ 200,000자, 변경 노트 ≤ 2,000자, 최대 100개의 원칙 (제목 ≤ 300자, 설명 ≤ 4,000자), 헌법 이름 ≤ 200자. set_direction은 더 큰 것을 거부하며, /mcp 요청 본문은 5MB로 제한됩니다.

  • pip으로 설치된 Kyno는 자체 마이그레이션 스크립트를 포함합니다: kyno init-db는 현재 헤드에 스탬프된 새 스키마를 생성하고, kyno upgrade-db는 업그레이드 후 기존 데이터베이스를 최신 상태로 업데이트합니다.

Testing

python -m pytest -q                      # SQLite, no network
KYNO_TEST_POSTGRES_URL=postgresql+psycopg://… python -m pytest -q   # + Postgres

자매 프로젝트: Canon은 시스템의 출력이 Kyno가 제공하는 헌법과 실제로 일관성을 가지는지 테스트합니다.

스타일 및 테스트 기대 사항은 CONTRIBUTING.md를 참조하세요.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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.

View all MCP Connectors

Latest Blog Posts

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