TrendHackergeeknews intel
live
← 블로그 목록
TECH NOTE · 2026-06-19

프롬프트 대신 명세로: ouroboros 리뷰 — AI 코딩을 위한 명세 우선 Agent OS 해부

GitHub: Q00/ouroboros
AI AgentAgent OSSpec-FirstEvent SourcingLLM Workflow
▶ YouTube에서 보기

들어가며: AI 코딩은 출력이 아니라 입력에서 실패한다

대부분의 AI 코딩 실패는 모델 능력의 문제가 아니라 입력의 모호함에서 옵니다. "할 일 관리 CLI를 만들어줘"라고 던지면 모델은 빈칸을 추측으로 메우고, 그 추측이 PR 리뷰 단계에서야 어긋난 것으로 드러나 재작업이 발생합니다. Q00/ouroboros는 이 지점을 정면으로 겨냥합니다. 코드를 한 줄 쓰기 전에 숨은 가정을 먼저 드러내자는 것입니다.

ouroboros는 자신을 "AI 코딩을 위한 Agent OS"로 규정합니다. 비결정적인 에이전트 작업을 재현 가능하고(replayable) 관찰 가능하며(observable) 정책에 묶인(policy-bound) 실행 계약으로 바꾸는 로컬 우선 런타임 레이어입니다. 즉흥적 프롬프팅을 다섯 단계의 명세 우선 워크플로로 대체합니다. interview(인터뷰) → crystallize(결정화) → execute(실행) → evaluate(평가) → evolve(진화). 이 글은 ouroboros 저장소(Python 3.12+ 패키지 ouroboros-ai, MIT, Claude Code 플러그인)를 직접 읽고, 문서가 약속하는 동작이 실제 코드로 구현돼 있는지 검증하는 코드 리뷰입니다. 핵심 알고리즘 대부분은 코드에서 정확히 확인됐고, 일부 문서-코드 불일치도 함께 짚습니다.

ouroboros란 무엇인가

한 문장으로, ouroboros는 "모호한 아이디어를 검증된 코드베이스로 바꾸는 명세 우선 워크플로 엔진"입니다. 이름이 가리키는 우로보로스(자기 꼬리를 무는 뱀)는 장식이 아니라 아키텍처 그 자체입니다. 평가의 출력이 다음 세대 명세의 입력으로 되먹임되는 진화 루프를 형상화합니다.

    Interview → Seed → Execute → Evaluate
        ^                           |
        +---- Evolutionary Loop ----+

ouroboros는 더 큰 스택의 커널에 해당합니다. 저장소 README는 셋으로 나눈 OS 비유를 제시합니다. 터미널 셸 ourocode, 도메인 워크플로를 담는 UserLevel 플러그인 ouroboros-plugins, 그리고 이 저장소인 커널 ouroboros(Seed·Ledger·Runtime·MCP·안전 경계)입니다. 사용자는 두 갈래로 씁니다. AI 코딩 세션 안에서 슬래시 명령 스킬로 부르는 ooo(권장 경로)와, 독립 실행 CLI인 ouroboros(Typer 기반, pip install ouroboros-ai)입니다.

아키텍처: OS처럼 나뉜 레이어

docs/product/architecture.md는 시스템을 OS의 은유로 설명합니다. 안정적인 OS 레이어의 원시 요소 (primitive)와 그 위에 얹히는 도메인 워크플로의 응용 레이어, 그리고 사람이 마주하는 셸로 나뉩니다. 커널 내부는 다시 여섯 단계의 파이프라인으로 동작합니다.

Phase 0: BIG BANG        → 요구사항을 Seed로 결정화
Phase 1: PAL ROUTER      → 모델 티어 선택(비용 최적화)
Phase 2: 실행            → AC를 분해해 에이전트 런타임으로 실행
Phase 3: RESILIENCE      → 정체 감지 + 측면 사고(lateral thinking)
Phase 4: EVALUATION      → 3단계 검증 게이트
Phase 5: SECONDARY LOOP  → 보류된 TODO 처리 (필요 시 순환)

src/ouroboros/ 아래는 단계별 모듈로 갈라집니다. bigbang/(인터뷰·모호성), evaluation/ (3단계 평가), evolution/(진화·수렴), resilience/(정체·측면 사고), observability/(드리프트), persistence/(이벤트 소싱), orchestrator/(런타임 추상화), core/(Seed·AC 트리·보안), mcp/(MCP 서버·클라이언트), cli/·tui/(표현 계층) 등입니다.

핵심 자료구조: Seed와 AC 트리, 그리고 이벤트 소싱

ouroboros의 모든 것은 Seed라는 불변 명세에서 출발합니다. core/seed.pySeedfrozen=True Pydantic 모델로, 한 번 생성되면 수정할 수 없습니다. 필드는 goal(목표), constraints(제약), acceptance_criteria(수용 기준), ontology_schema(출력 구조), evaluation_principles, exit_conditions(종료 조건), 그리고 metadata입니다. 메타데이터에는 ambiguity_score와 생성 모드·열화(degraded) 여부까지 기록됩니다. 시드는 워크플로의 "헌법"이며, 방향은 고정되고 그 방향에 이르는 경로만 적응합니다.

수용 기준은 core/ac_tree.pyAC 트리로 분해됩니다. ACNode는 frozen dataclass이고 상태는 ACStatus enum으로 PENDING / ATOMIC / DECOMPOSED / EXECUTING / COMPLETED / FAILED를 가집니다(문서의 단순 표현보다 실제 enum이 더 세분돼 있습니다). 각 노드는 깊이(depth)와 부모/자식 ID를 들고, with_status()·with_children()처럼 새 노드를 반환하는 불변 갱신 메서드로만 바뀝니다.

상태 변경은 모두 이벤트 소싱으로 영속화됩니다. persistence/schema.py는 단일 events 테이블을 SQLAlchemy Core로 정의하며, 컬럼은 id(UUID)·aggregate_type·aggregate_id· event_type·payload(JSON)·timestamp·consensus_id이고, 조회 성능을 위한 인덱스가 여섯 개 걸려 있습니다. event_typeorchestrator.session.started처럼 점 표기 과거형을 따릅니다. 테이블은 추가 전용(append-only)이라 이벤트는 수정·삭제되지 않고, 그래서 과거 어느 시점의 상태든 재생(replay)으로 복원할 수 있습니다. 체크포인트는 checkpoint.py에서 SHA-256으로 무결성을 검증하며 최대 3단계 롤백을 지원합니다. ooo ralph가 세션 경계를 넘어 이어질 수 있는 이유가 여기 있습니다. 모든 단계가 무상태(stateless)이고 전체 계보는 EventStore에서 재구성되기 때문입니다.

Phase 0 — Big Bang: 소크라테스식 인터뷰와 모호성 게이트

워크플로의 첫 단계는 모호한 아이디어를 질문으로 깎아내 명세로 만드는 것입니다. bigbang/interview.py의 인터뷰 엔진이 명료화 질문을 던지고, 매 응답마다 bigbang/ambiguity.py가 모호성 점수를 다시 계산합니다. 흥미로운 점은 인터뷰가 "이제 됐다"는 느낌이 아니라 수치로 끝난다는 것입니다. 모호성은 가중 명료도의 여집합으로 정의됩니다.

Ambiguity=1iclarityiweighti\text{Ambiguity} = 1 - \sum_i \text{clarity}_i \cdot \text{weight}_i

코드에서 그대로 확인됩니다. ambiguity.py는 greenfield 가중치를 Goal 0.40 / Constraint 0.30 / Success 0.30으로, brownfield는 여기에 Context 0.15를 더해 0.35 / 0.25 / 0.25 / 0.15로 두고, 임계값 상수 AMBIGUITY_THRESHOLD = 0.2, 채점 온도 SCORING_TEMPERATURE = 0.1(재현성을 위해 낮게)을 정의합니다. 각 차원을 LLM이 0.0~1.0으로 채점한 뒤 가중합한 명료도를 1에서 빼서 모호성을 냅니다. 모호성이 0.2 이하로 떨어져야 비로소 Seed를 생성할 수 있습니다. 80% 가중 명료도면 남은 미지수는 코드 수준 결정으로 해소될 만큼 작다는 판단입니다.

실행: 런타임 추상화와 재귀 AC 분해

ouroboros의 핵심 공학적 결정 하나는 워크플로 오케스트레이션을 실행 런타임과 분리한 것입니다. orchestrator/adapter.pyAgentRuntime 프로토콜은 두 메서드만 요구합니다. 스트리밍 실행 execute_task()와 결과 수집 execute_task_to_result()입니다. 오케스트레이터는 백엔드의 내부를 들여다보지 않고, 정규화된 AgentMessage·RuntimeHandle·TaskResult 타입으로만 소통합니다. 그래서 같은 워크플로 명세를 두고 실행 엔진만 갈아끼울 수 있습니다. runtime_factory.pycreate_agent_runtime()이 백엔드 이름을 해석해 어댑터를 돌려주는데, 저장소에는 Claude Code(ClaudeAgentAdapter), Codex CLI(CodexCliRuntime), OpenCode, Hermes, Gemini, Kiro, Copilot, Pi 어댑터가 실재합니다. 다만 README도 "런타임마다 도구·권한·스트리밍 의미가 달라 기능 동등성(feature parity)은 보장되지 않는다"고 명시합니다.

실행 단위인 AC는 기본적으로 원자적(atomic)으로 다뤄집니다. 한 AC가 프로파일의 축을 따라 독립 검증 가능한 여러 단위로 진짜 갈라질 때만 하위 AC로 분해됩니다. orchestrator/parallel_executor.pyMIN_SUB_ACS = 2, MAX_SUB_ACS = 5, DEFAULT_MAX_DECOMPOSITION_DEPTH = 2를 상수로 둡니다. 분해를 보수적으로 하는 이유는 하위 AC 하나가 곧 한 번의 전체 에이전트 세션 비용이기 때문입니다. 깊이 상한에 닿으면 비원자 단위라도 원자적으로 실행하고 깊이 경고를 기록하며, 실패는 더 깊이 미리 쪼개는 대신 "시도 후 되튕기기(attempt-then-bounce)" 식 제한 재시도 + 평가 피드백으로 처리합니다.

평가: 비용을 점증시키는 3단계 게이트

evaluation/pipeline.py는 싼 검사부터 비싼 검사 순으로 품질을 거릅니다.

1단계 Mechanical($0): lint·build·test·정적분석·커버리지입니다. mechanical.pycoverage_threshold = 0.7로 커버리지 70%를 요구합니다. 한 가지 문서-코드 불일치가 여기 있습니다. 아키텍처 문서는 "마커 파일로 언어 자동 감지(uv.lock→Python 등)"라고 적지만, 실제 evaluation/languages.py는 더 이상 언어별 프리셋을 들고 있지 않고, 대신 AI 호출로 저장소를 살펴 .ouroboros/mechanical.toml을 생성하며, 그 명령들은 실행 파일 허용목록(allowlist)으로 검증됩니다. 즉 마커 파일 정규식이 아니라 AI가 쓴 설정 파일 + 허용목록이 진실 소스입니다.

2단계 Semantic($$): AC 준수·목표 정합·드리프트·불확실성을 점수화합니다. semantic.py는 온도 0.2를 쓰고, pipeline.pystage2_result.ac_compliance and stage2_result.score >= 0.8일 때 합의 없이 승인합니다.

3단계 Consensus($$$): 여섯 조건 중 하나가 켜질 때만 도는 다중 모델 투표입니다. config/loader.py의 기본 합의 모델은 GPT-4o, Claude Opus, Gemini 2.5 Pro 세 가지이고, consensus.pymajority_threshold = 0.66으로 3분의 2 다수결을 요구합니다. 더 깊은 심의 모드(DeliberativeConsensus)에서는 Advocate(옹호자)·Devil's Advocate(악마의 변호인)· Judge(판사) 역할이 라운드로 나뉘어 존재론적 질문을 주고받습니다.

합의를 촉발하는 여섯 트리거는 evaluation/trigger.pyTriggerType enum에 그대로 있습니다. 시드 수정(시드는 불변이라 어떤 변경도 합의 필요), 온톨로지 진화, 목표 재해석, 시드 드리프트

0.3, 2단계 불확실성 > 0.3, 측면 사고 채택입니다. 드리프트·불확실성 임계값 0.3도 코드 상수로

확인됩니다.

회복탄력성: 정체 감지와 측면 사고

실행이 막히면 resilience/가 개입합니다. stagnation.pyStagnationPattern enum은 네 가지 정체 패턴을 정의합니다. SPINNING(같은 출력 해시가 3회 반복), OSCILLATION(A→B→A→B 2주기), NO_DRIFT(드리프트 변화 epsilon < 0.01이 3회), DIMINISHING_RETURNS(개선율 < 0.01)입니다. 감지는 무상태로, 모든 상태는 ExecutionHistory로 전달됩니다.

정체가 잡히면 lateral.py의 다섯 페르소나가 해답이 아니라 사고 프롬프트를 생성합니다. HACKER(비관습적 우회)·RESEARCHER(정보 탐색)·SIMPLIFIER(복잡도 축소)·ARCHITECT(구조 재편)·CONTRARIAN(가정 도전)입니다. suggest_persona_for_pattern()이 각 페르소나의 친화 패턴(예: HACKER↔SPINNING, ARCHITECT↔OSCILLATION/NO_DRIFT)을 보고 적합한 페르소나를 추천하며, CONTRARIAN은 네 패턴 모두에 친화적입니다.

진화 루프와 수렴: 뱀이 멈추는 순간

평가가 끝나면 그 출력이 다음 세대 시드의 입력이 됩니다. 이 진화 루프는 영원히 돌지 않고, 연속 세대가 존재론적으로 동일한 스키마를 낼 때 멈춥니다. core/lineage.pyOntologyDelta가 유사도를 계산하는데, 코드가 문서 공식과 정확히 일치합니다.

Similarity=0.5name_overlap+0.3type_match+0.2exact_match\text{Similarity} = 0.5 \cdot \text{name\_overlap} + 0.3 \cdot \text{type\_match} + 0.2 \cdot \text{exact\_match}

evolution/convergence.pyconvergence_threshold = 0.95max_generations = 30을 두고, 주기-2 진동(oscillation)과 정체(stagnation)도 감지합니다. 한편 실행이 시드에서 얼마나 벗어났는지는 observability/drift.py가 잽니다. 여기서도 공식이 코드와 일치합니다. 드리프트는 목표 0.5 + 제약 0.3 + 온톨로지 0.2의 가중합이고, DRIFT_THRESHOLD = 0.3을 넘으면 허용되지 않습니다. 두 수학적 게이트가 하나의 철학을 떠받칩니다. 명료해질 때까지(모호성 ≤ 0.2) 짓지 말고, 안정될 때까지(유사도 ≥ 0.95) 진화를 멈추지 말라.

ooo ralph는 이 진화 루프를 수렴까지 끈질기게 돌리는 모드입니다. 각 스텝이 무상태이고 EventStore가 계보를 재구성하므로, 기계가 재시작돼도 뱀은 멈춘 자리에서 이어집니다.

ooo auto: 목표에서 A등급 시드까지

auto/pipeline.pyAutoPipeline은 "목표 → A등급 시드 → 실행 핸드오프"를 제한된 루프로 자동화합니다. 단계는 INTERVIEW → SEED_GENERATION → REVIEW → RUN → RALPH_HANDOFF → EVALUATE → UNSTUCK_LATERAL로 이어지며, 막히면 BLOCKED/FAILED로 정직하게 멈춥니다. 인터뷰는 곧바로 시드를 만들지 않고 SeedDraftLedger(가변 작업대)를 채웁니다. 이 원장(ledger)은 목표·액터·입출력·제약· 비목표·수용기준·검증계획·실패모드·런타임컨텍스트 등 필수 섹션을 가지며, 각 항목에 출처 (USER_GOAL·REPO_FACT·ASSUMPTION·INFERENCE 등)와 상태(MISSING/WEAK/CONFIRMED/CONFLICTING 등), 신뢰도를 달아 둡니다.

품질 게이트는 auto/grading.pyGradeGate입니다. SeedGrade enum은 A/B/C이고, 실행 허용 (may_run)은 grade == A and not blockers일 때만 참입니다. 채점은 커버리지·모호성·테스트 가능성·실행 타당성·위험 같은 축을 결정론적으로 계산하고, LLM이 보고한 모호성 점수는 열린 갭·충돌·가정 비율로 만든 결정론적 하한(deterministic floor)과 비교해 더 큰 값으로 고정됩니다. 모델이 낙관적으로 점수를 낮춰도 구조적 결함은 바닥을 깔아 막는 셈입니다. 루프는 상한 없이 돌지 않습니다. 최상위 데드라인(기본 2시간), 단계별 타임아웃, Ralph 반복당 상한 (30초~7200초)이 걸려 있고, 인터뷰 단계가 타임아웃되면 하드 실패 대신 증거 기반 부분 시드 (partial seed)를 합성합니다.

설치와 사용

설치는 한 줄 스크립트 또는 패키지 매니저로 합니다.

curl -fsSL https://raw.githubusercontent.com/Q00/ouroboros/main/scripts/install.sh | bash
# 또는
pip install ouroboros-ai[all]   # claude + litellm + mcp + tui
ouroboros setup                 # 런타임 백엔드 등록

Claude Code 플러그인만 쓰려면 claude plugin marketplace add Q00/ouroborosclaude plugin install ouroboros@ouroboros로 설치합니다. 이후 AI 코딩 세션 안에서 ooo 명령을 씁니다.

ooo interview "할 일 관리 CLI를 만들고 싶어"   # 소크라테스식 인터뷰 → 시드 자동 생성
ooo auto "..."     # 목표 → A등급 시드 → 실행 핸드오프(제한 루프)
ooo run            # 시드를 실행
ooo evaluate       # 3단계 검증 게이트
ooo evolve         # 온톨로지가 수렴할 때까지 진화
ooo ralph          # 검증될 때까지 지속 루프
ooo status         # 세션 추적 + 드리프트 측정
ooo unstuck        # 막혔을 때 측면 사고 페르소나

터미널에서는 ouroboros interview/run/status/cancel/mcp/tui 같은 Typer 하위 명령을 씁니다. 다만 evaluate·evolve·unstuck·ralph처럼 일부 기능은 직접적인 셸 하위 명령이 아니라 스킬·MCP 도구로만 노출됩니다. ouroboros는 양방향 MCP 허브로도 동작해, 서버 모드로는 ouroboros_execute_seed·session_status·query_events·evolve_step 같은 도구를 노출하고 클라이언트 모드로는 외부 MCP 서버를 소비합니다.

한계와 주의점

코드를 직접 읽으며 드러난 경계는 다음과 같습니다. 가장 주목할 점은 문서가 코드보다 앞서간 부분입니다.

첫째, 아키텍처 문서가 Phase 1로 비중 있게 설명하는 PAL Router(복잡도 = 0.30·토큰 + 0.30·도구 + 0.40·깊이로 FRUGAL/STANDARD/FRONTIER 티어를 고르고, 실패 2회에 escalate·성공 5회에 downgrade)는 문서가 지목한 routing/ 모듈들(router.py·complexity.py·tiers.py 등)이 제가 읽은 main 소스 트리에 존재하지 않았습니다. 모델·역량 선택과 관련된 코드는 backends/· providers/에 흩어져 있으나, 문서가 그린 형태의 3티어 복잡도 라우터는 현재 소스에서 그대로 확인되지 않습니다. 명세 우선을 표방하는 프로젝트에서도 문서와 코드의 드리프트는 생기며, 이 리뷰의 다른 수치들이 코드로 정확히 검증된 것과 대비됩니다.

둘째, 앞서 본 대로 평가 1단계의 언어 감지는 문서의 "마커 파일" 설명과 달리 AI가 쓰는 .ouroboros/mechanical.toml + 실행 파일 허용목록으로 동작합니다.

셋째, 다중 런타임을 지원하지만 README 스스로 밝히듯 백엔드 간 기능 동등성은 보장되지 않습니다. 도구·권한·스트리밍 의미가 어댑터 경계에서 정규화될 뿐입니다.

넷째, 평가 3단계 합의와 의미 평가는 외부 LLM(기본 GPT-4o·Opus·Gemini 2.5 Pro)에 의존하므로 비용과 모델 품질에 좌우됩니다. ouroboros의 설계 철학은 이를 "싼 검사 먼저, 비싼 합의는 게이트 에서만"으로 통제할 뿐 제거하지는 않습니다. 입력 길이 상한(core/security.py의 인터뷰 5만 자, 응답 1만 자, 시드 파일 100만 바이트 등)으로 DoS를 방어하는 점은 긍정적입니다.

결론

ouroboros는 "프롬프트를 멈추고 명세를 시작하라"는 구호를 추상이 아니라 측정 가능한 게이트와 이벤트 소싱으로 구현한 Agent OS입니다. 핵심을 정리하면 다음과 같습니다.

  • 명세 우선: 모든 작업은 불변 Seed(frozen Pydantic)에 묶이고, 모호성이 0.2 이하로 떨어진 뒤에야 시드를 만들 수 있습니다(Ambiguity = 1 - Σ clarity·weight, 코드로 검증됨).
  • 재현 가능한 실행: 상태 변경은 단일 events 테이블에 추가 전용으로 쌓여, 어느 시점이든 재생으로 복원되고 세션 경계를 넘어 이어집니다.
  • 런타임 중립: AgentRuntime 프로토콜로 Claude·Codex·Gemini·Copilot 등 백엔드를 갈아끼우며 같은 워크플로를 돌립니다(기능 동등성은 비보장).
  • 점증하는 검증: Mechanical($0) → Semantic → 다중 모델 Consensus의 3단계 게이트, 여섯 트리거가 켜질 때만 비싼 합의를 돕니다.
  • 두 수학적 게이트: 모호성 ≤ 0.2에서 시작하고 온톨로지 유사도 ≥ 0.95에서 멈춥니다. 그 사이를 stagnation 감지와 측면 사고 페르소나가 메웁니다.
  • 정직한 드리프트: 문서가 코드보다 앞선 부분(PAL Router, 마커 파일 언어 감지)이 있으나, 핵심 수식·임계값 대부분은 소스에서 정확히 확인됩니다.

grep과 즉흥 프롬프팅이 입력의 모호함을 코드 단계로 떠넘긴다면, ouroboros는 그 모호함을 인터뷰와 모호성 게이트에서 먼저 태웁니다. 뱀은 반복하지 않고 진화한다는 표어는, 평가 출력을 다음 세대 시드로 되먹이는 진화 루프의 코드로 뒷받침됩니다.

이 글에서 다루지 못한 부분

분량상 다음 영역은 깊게 다루지 못했습니다. tui/(Textual 대시보드·AC 트리·드리프트 미터·병렬 그래프 위젯)와 crates/ouroboros-tui(Rust TUI 크레이트), bigbang/brownfield.py (브라운필드 저장소 탐색), docs/agentos/의 Agent OS 커널 계약(ControlPlane·Directive· IOJournal 등 런타임 컨트랙트), plugin/의 UserLevel 플러그인 매니페스트 스키마, pm/(PRD 생성), evolution/reflect.py의 Reflect 단계 변이 제안, 그리고 각 런타임 어댑터별 스트리밍 정규화 세부입니다.