opt-harness를 활용한 Agent Catalog 아키텍처 구현
Case Study — 사례 연구
Eric Han
설계 거버넌스 하네스 패키지 @reopt-ai/opt-harness를 사용하여 Agent Catalog의 아키텍처 원칙을 실제 제품 구현으로 옮기는 실전 사례.
개요 — 설계 거버넌스 하네스란
reopt architecture는 에이전트 단위의 책임, 모듈 계약, 운영 거버넌스를 통해 AI 네이티브 시스템을 설계하는 아키텍처 방법론이다. 그런데 방법론은 그 자체로는 코드가 아니다. 원칙이 제품 코드에 스며들려면, 원칙을 강제하고 측정하는 인프라가 필요하다.
opt-harness는 이 간극을 메우는 설계 거버넌스 하네스(harness) 패키지다. CSS 토큰만으로는 해결할 수 없는 문제—앱 셸 구조, 워크스페이스 레시피, 페이지 리듬, 상태 UX 일관성, 엔진 어댑터 통합—를 선언적 매니페스트와 정책 시스템으로 해결한다.
이 글에서는 opt-harness의 핵심 개념을 reopt architecture의 아키텍처 원칙에 매핑하며, 실제 코드와 함께 구현 사례를 살펴본다.
Manifest-Driven Architecture
opt-harness의 출발점은 HarnessManifest다. 이것은 하나의 제품 표면(product surface)을 선언적으로 기술하는 정적 디스크립터다. reopt architecture의 Module Contract 패턴이 '모듈의 입출력과 책임을 명시적으로 정의하라'고 말하는 것처럼, HarnessManifest는 앱 전체의 계약을 하나의 객체로 선언한다.
interface HarnessManifest {
id: string; // 고유 앱 식별자
label: string; // 사람이 읽는 이름
description?: string;
audience?: "internal" | "external";
routeGroups?: readonly HarnessRouteGroup[];
defaults?: HarnessPolicy; // 정책 기본값
contract?: HarnessContractRegistry; // 감사 규칙
}
HarnessManifest — 앱 전체의 구조적 계약을 선언하는 디스크립터
매니페스트는 createHarnessApp 팩토리 함수로 컴파일된다. 이 과정에서 정책 기본값이 해석되고, 계약 레지스트리가 검증되며, 테마 토큰이 생성된다. 결과물인 CompiledHarnessManifest는 런타임에서 HarnessProvider에 주입된다.
import { createHarnessApp } from "@reopt-ai/opt-harness/core";
const app = createHarnessApp({
id: "agent-catalog",
label: "reopt architecture",
audience: "external",
defaults: {
density: "comfortable",
contentWidth: "normal",
navigationMode: "stacked",
},
contract: {
designDocument: { requiredSections: ["Overview", "Recipes"] },
rolloutTargets: [
{ kind: "layout", relativePath: "app/layout.tsx" },
{
kind: "recipe-screen",
relativePath: "app/patterns/page.tsx",
expectedWorkspace: "ListWorkspace",
expectedRecipe: "list",
},
],
},
});
createHarnessApp — 매니페스트를 컴파일하여 런타임에서 사용할 수 있는 형태로 변환
이 구조는 reopt architecture의 4계층 모델에서 Governance 계층이 하위 계층을 조직하고 통제하는 원리와 같다. 매니페스트가 앱 전체의 거버넌스 경계를 선언하고, 하위 레시피와 슬롯이 그 경계 안에서 동작한다.
5가지 Canonical Workspace Recipes
opt-harness는 모든 제품 화면을 5가지 정규 레시피(canonical recipe) 중 하나로 분류한다. 레시피는 화면의 의미적 목적(intent)을 정의하고, 그에 맞는 레이아웃 계약을 강제한다. 이것은 reopt architecture의 Responsibility Partitioning 패턴의 구현체다—'역할과 경계 없이 기능을 쌓지 말라.'
- list — 데이터 행을 스캔, 필터, 대량 조작하는 화면. 기본 너비: wide. 필수 슬롯: header, content.
- detail — 단일 리소스를 검사하는 화면. 기본 너비: normal. 필수 슬롯: header, content.
- editor — 문서 작성과 리뷰. 저장/초안 상태가 일급 관심사. 기본 너비: wide.
- dashboard — 개요, 트리아지, 메트릭, 다음 행동. 기본 너비: full.
- landing — 퍼블릭 페이지. 히어로, CTA 스택. 기본 너비: full.
레시피 선택은 프로그래밍적으로도 가능하다. selectRecipe 함수는 화면의 시그널을 입력받아 최적 레시피를 반환한다.
import { selectRecipe } from "@reopt-ai/opt-harness/core";
selectRecipe({ hasDataGrid: true }); // → "list"
selectRecipe({ hasEditor: true }); // → "editor"
selectRecipe({ primaryAction: "inspect" }); // → "detail"
selectRecipe({ isPublicFacing: true }); // → "landing"
selectRecipe({}); // → "dashboard" (fallback)
selectRecipe — 시그널 기반 레시피 자동 선택 휴리스틱
각 레시피는 AI 에이전트를 위한 메타데이터도 포함한다. intent(이 레시피가 존재하는 이유), selectionHeuristics(이 레시피를 선택해야 하는 신호), antiPatterns(이 레시피에서 흔한 실수). 에이전트가 화면 설계를 자동화할 때, 이 메타데이터가 잘못된 선택을 방지한다.
Phase-Aware AI Agent Protocol
opt-harness의 가장 독특한 설계는 에이전트 프로토콜이 개발 단계(phase)를 인식한다는 점이다. reopt architecture의 OCLS 루프(Own → Contract → Layer → Sharpen)가 거버넌스 설계의 순환 모델이듯, opt-harness는 scaffold → implement → polish → audit 4단계를 정의한다.
핵심은 각 단계에서 에이전트가 볼 수 있는 정보를 제한한다는 것이다. scaffold 단계에서는 레시피 선택만, implement 단계에서는 잠긴 레시피의 슬롯과 어댑터만, polish 단계에서는 정책 옵션만, audit 단계에서는 감사 결과만 노출된다.
import { generateHarnessContext } from "@reopt-ai/opt-harness/core";
// scaffold 단계: 레시피 정보만 노출
const scaffoldCtx = generateHarnessContext(manifest, {
phase: "scaffold",
});
// implement 단계: 선택된 레시피의 슬롯만 노출
const implCtx = generateHarnessContext(manifest, {
phase: "implement",
lockedRecipe: "list",
});
// audit 단계: 감사 결과와 교정 패턴만 노출
const auditCtx = generateHarnessContext(manifest, {
phase: "audit",
});
generateHarnessContext — 단계별 에이전트 컨텍스트 생성
이 설계는 OCLS 루프의 핵심 통찰을 반영한다. 모든 정보를 한꺼번에 제공하면 에이전트의 결정 정확도가 떨어진다. 단계별로 관련 정보만 제공하면, 토큰 오버헤드를 줄이고, 결정 노이즈를 낮추며, 할루시네이션 위험을 최소화한다.
Policy Resolution System
opt-harness에서 정책(Policy)은 거버넌스 제약의 구현체다. reopt architecture의 Evaluation & Guardrails 패턴이 '에이전트가 해야 할 것뿐 아니라 절대 하면 안 되는 것을 설계 단계에서 명시하라'고 하듯, HarnessPolicy는 UI의 허용 범위를 선언적으로 제한한다.
interface HarnessPolicy {
density: "comfortable" | "compact";
contentWidth: "narrow" | "normal" | "wide" | "full";
navigationMode: "sidebar" | "stacked";
motionPolicy: "full" | "reduced";
stateLabels: HarnessStateLabels;
panelBehavior: HarnessPanelBehavior;
adapters: {
datagrid: { chrome: "card" | "plain" };
editor: { chrome: "card" | "plain" };
};
theme: HarnessThemeConfig;
}
HarnessPolicy — UI 동작의 허용 범위를 선언적으로 정의
정책 해석은 계층적이다. 매니페스트의 defaults가 기본값을 제공하고, 런타임 오버라이드가 이를 덮어쓴다. resolveHarnessPolicy 함수가 두 입력을 병합하여 최종 ResolvedHarnessPolicy를 생산한다. 이것은 CSS의 cascade와 유사하지만, 타입 안전하고 검증 가능하다.
- density — 간격/크기 스케일. comfortable(기본)은 넓은 여백, compact는 밀도 높은 데이터 뷰.
- contentWidth — 페이지 최대 폭. 레시피별 기본값이 있지만 정책으로 재정의 가능.
- navigationMode — sidebar(사이드바) 또는 stacked(상단 고정). 앱 규모에 따라 결정.
- motionPolicy — 애니메이션 강도. reduced는 접근성을 위해 전환을 최소화.
- stateLabels — 로딩/빈 상태/에러 상태의 문구를 전역에서 통일.
ESLint 규칙이 정책 우회를 방지한다. 예를 들어, max-w-* 같은 Tailwind 클래스를 직접 사용하면 경고가 발생한다. 모든 페이지 폭은 반드시 policy.contentWidth를 통해야 한다. 이것이 '구조가 곧 거버넌스'의 실천이다.
Slot-Based Composition
레시피는 네임드 슬롯(named slot)의 계약을 정의한다. 6가지 슬롯—header, toolbar, filters, content, aside, footer—이 존재하며, 레시피마다 필수 슬롯과 선택 슬롯이 다르다. 이 구조는 에이전트가 렌더링 없이도 레이아웃을 추론할 수 있게 한다.
<ListWorkspace
header={<PageHeader title="패턴 카탈로그" />}
toolbar={<FilterBar categories={categoryOrder} />}
filters={<ActiveFilters selected={selectedCategory} />}
content={
<HarnessDataGridAdapter
loading={isLoading}
empty={patterns.length === 0 ? { title: "패턴 없음" } : null}
error={error}
>
<PatternGrid patterns={patterns} />
</HarnessDataGridAdapter>
}
aside={<PatternPreview selected={selectedPattern} />}
footer={<BulkActions />}
/>
슬롯 기반 조합 — 각 슬롯에 독립적인 컴포넌트를 배치
슬롯 계약은 reopt architecture의 핵심 질문 '이 결과를 누가 소유하는가?'에 대한 UI 수준의 답이다. header 슬롯은 페이지 정체성을 소유하고, content 슬롯은 핵심 데이터를 소유하며, aside 슬롯은 보조 컨텍스트를 소유한다. 소유자가 명확하면, 변경의 영향 범위도 명확해진다.
MCP Handlers — 읽기와 쓰기를 모두 갖춘 에이전트 인터페이스
opt-harness는 15개 이상의 서버사이드 MCP(Model Context Protocol) 핸들러를 제공한다. 초기에는 읽기 전용 핸들러만 있었지만, 거버넌스 개선을 거치며 결정 기록, 승인 요청, 에이전트 등록 등 쓰기 핸들러가 추가되었다. reopt architecture의 Module Contract 패턴이 '모듈 간 통신은 명시적 계약으로'라고 말하는 것처럼, MCP 핸들러는 에이전트와 하네스 사이의 양방향 계약이다.
- listHarnessManifests — 등록된 모든 앱 매니페스트의 요약 목록을 반환.
- getHarnessRecipes — 5가지 정규 레시피의 전체 정의를 반환.
- getHarnessRecipeDetail — 특정 레시피의 상세 메타데이터를 반환.
- resolveHarnessPolicyMCP — 매니페스트와 오버라이드로 최종 정책을 해석.
- getHarnessCompletenessScore — 감사 결과에서 0-100 점수를 산출.
- getStructuredHarnessContext — 단계별 에이전트 컨텍스트를 JSON으로 반환.
- getHarnessCoverage — 라우트 커버리지 비율을 반환.
- searchHarnessPatternsHandler — 50+ 패턴에서 키워드 검색.
- recordHarnessDecision — 거버넌스 결정을 감사 로그에 기록 (쓰기).
- getHarnessDecisionLog — 결정 이력을 에이전트/코드로 필터링하여 조회.
- getHarnessScoreHistory — 점수 시계열과 추세/회귀 정보를 반환.
- requestHarnessApproval — 가드 코드에 대한 승인을 요청 (쓰기).
- resolveHarnessApproval — 대기 중인 승인을 수락 또는 거부 (쓰기).
- registerHarnessAgent — 에이전트 세션을 등록하고 충돌을 보고 (쓰기).
- detectHarnessConflicts — 등록된 에이전트 간 충돌을 감지.
쓰기 핸들러의 추가는 핵심적인 전환이다. 에이전트가 하네스의 상태를 읽기만 하던 수동적 관계에서, 결정을 기록하고 승인을 요청하며 자신을 등록하는 능동적 참여자로 바뀌었다. 이것이 reopt architecture의 Decision Traceability 패턴이 요구하는 '모든 결정은 추적 가능해야 한다'의 인프라 수준 실현이다.
Completeness Scoring — 확장 가능한 거버넌스 정량화
reopt architecture는 '측정할 수 없으면 거버넌스가 아니다'라고 말한다. opt-harness의 Completeness Scoring은 이 원칙의 구현이다. 감사 결과(audit findings)를 입력받아 카테고리별 가중 점수(0-100)를 산출한다. 기본 7개 카테고리가 제공되며, HarnessCompletenessConfig를 통해 도메인별 커스텀 카테고리와 가중치를 주입할 수 있다.
- layout (20%) — HarnessProvider 존재, 매니페스트 바인딩, 레이아웃 규칙 준수.
- recipe-contract (25%) — 올바른 워크스페이스 컴포넌트 사용, 필수 슬롯 존재.
- adapter-ownership (15%) — DataGrid/Editor 및 커스텀 어댑터의 올바른 래핑.
- state-ux (10%) — 로딩/빈 상태/에러 상태 처리 일관성.
- design-document (10%) — DESIGN.md 존재 및 필수 섹션 포함.
- scaffold-bundle (10%) — 스캐폴딩 산출물 완성도.
- accessibility (10%) — ARIA 랜드마크, 제목 계층, 스킵 링크.
import { computeCompletenessScore } from "@reopt-ai/opt-harness/core";
const score = computeCompletenessScore(auditFindings, totalCheckCount);
// → {
// score: 78,
// categories: {
// layout: { score: 100, weight: 20, findings: [] },
// "recipe-contract": { score: 60, weight: 25, findings: [...] },
// "adapter-ownership": { score: 85, weight: 15, findings: [...] },
// ...
// }
// }
computeCompletenessScore — 7개 카테고리 가중 점수 산출
이 점수는 에이전트의 교정 우선순위를 결정한다. 가중치가 높은 recipe-contract(25%)이 낮으면 먼저 수정하고, accessibility(10%)는 나중에 처리한다.
// 커스텀 카테고리를 매니페스트에서 주입
const config: HarnessCompletenessConfig = {
categories: [
{
category: "security",
weight: 30,
codes: ["missing-auth-check", "exposed-api-key"],
},
],
replaceDefaults: false, // 기본 7개에 추가 (true면 커스텀만 사용)
};
const score = computeCompletenessScore(findings, totalChecks, config);
HarnessCompletenessConfig — 도메인별 커스텀 카테고리와 가중치 주입
Pattern Index & Contract Registry
opt-harness는 50개 이상의 설계 패턴을 인덱싱한다. 레시피, 슬롯, 어댑터, 정책, 안티패턴, 감사 규칙이 모두 검색 가능한 형태로 색인되어 있다. 에이전트가 '데이터 그리드와 필터가 있는 화면은 어떻게 만드는가?'라고 질문하면, 패턴 인덱스가 관련 레시피와 슬롯 계약을 반환한다.
import { searchHarnessPatterns } from "@reopt-ai/opt-harness/core";
const patterns = searchHarnessPatterns("datagrid filter", 3);
// → [
// { tag: "recipe", name: "list", description: "Scan, filter, ..." },
// { tag: "slot", name: "filters", description: "Active filter chips ..." },
// { tag: "adapter", name: "HarnessDataGridAdapter", description: "..." },
// ]
searchHarnessPatterns — 50+ 설계 패턴 키워드 검색
Contract Registry는 감사 타겟의 집합이다. 각 타겟은 '이 파일이 이 워크스페이스를 사용해야 한다', '이 라우트에 이 코드 스니펫이 있어야 한다'는 기계 판독 가능한 규칙이다.
- layout — HarnessProvider와 매니페스트 바인딩이 루트 레이아웃에 존재하는지.
- recipe-screen — 특정 라우트가 기대하는 워크스페이스 컴포넌트를 사용하는지.
- fullscreen-tool — 전체 화면 도구가 HarnessFullscreenToolSurface를 래핑하는지.
- a11y — ARIA 랜드마크, 제목 계층, 스킵 링크 등 접근성 규칙.
이 규칙들은 빌드 타임(ESLint), 런타임(Completeness Scoring), CI/CD(SARIF 출력, PR 리뷰 코멘트)에서 모두 사용된다. reopt architecture의 Decision Traceability 패턴이 요구하는 '모든 설계 결정은 추적 가능해야 한다'를 인프라 수준에서 실현한다.
Decision Traceability — 결정 추적의 구현
reopt architecture의 Decision Traceability 패턴은 '이 에이전트의 판단을 사후에 설명할 수 있는가?'를 요구한다. opt-harness는 append-only Decision Log로 이를 구현했다. 모든 결정은 누가(agentId), 언제(decidedAt), 왜(rationale) 내렸는지 기록되며, 사후에 에이전트별·코드별로 조회할 수 있다.
import { createDecisionLog } from "@reopt-ai/opt-harness/core";
const log = createDecisionLog();
// 에이전트가 레시피 선택 결정을 기록
log.record({
code: "accept-recipe",
kind: "accept",
attribution: {
agentId: "architect-agent",
decidedAt: new Date().toISOString(),
rationale: "데이터 그리드가 주요 콘텐츠이므로 list 레시피 선택",
},
findingCode: "missing-workspace-component",
context: { recipe: "list", screen: "/orders" },
});
// 사후 조회
log.findByAgent("architect-agent"); // 특정 에이전트의 모든 결정
log.findByCode("accept-recipe"); // 특정 코드의 모든 결정
log.latestForCode("missing-workspace-component"); // 최신 결정
createDecisionLog — append-only 결정 로그로 거버넌스 감사 추적
HarnessDecisionRecord는 4가지 결정 유형(accept, override, defer, reject)을 지원한다. 에이전트가 감사 결과를 수용할 수도, 근거를 붙여 재정의할 수도, 나중으로 미룰 수도, 거부할 수도 있다. 이 구조화된 기록이 reopt architecture의 Observability Gap—'에이전트 추론 경로와 결정 근거가 기록되지 않아 사후 분석이 불가능한 상태'—을 해소한다.
Multi-Agent Governance — 충돌 감지와 승인
단일 에이전트 모델에서 멀티에이전트 환경으로의 전환은 reopt architecture 진화 단계의 핵심 전환점이다. opt-harness는 Agent Registry와 Approval Gate로 이 전환을 지원한다.
import { createAgentRegistry } from "@reopt-ai/opt-harness/core";
const registry = createAgentRegistry();
// 에이전트 세션 등록
registry.register("architect", "scaffold", "list");
registry.register("implementer", "implement", "list");
// 충돌 감지 — 같은 레시피에 scaffold + implement 동시 진행
const conflicts = registry.detectConflicts();
// → [{ agents: ["architect", "implementer"],
// conflictType: "recipe",
// message: "Agents have conflicting phases on recipe \"list\"." }]
// 명령 실행 전 충돌 확인
const check = registry.checkInstruction("new-agent", {
action: "configure-policy",
agentId: "new-agent",
});
// → polish 단계 에이전트와의 정책 충돌 경고
createAgentRegistry — 멀티에이전트 세션 관리와 충돌 감지
충돌 규칙은 세 가지다. 같은 레시피를 두 에이전트가 implement하면 충돌, scaffold와 implement가 같은 레시피에서 동시 진행되면 충돌, 두 에이전트가 동시에 polish(정책 튜닝)하면 충돌. 이 규칙들은 경고(warning)로 발행되어 에이전트의 판단을 보조한다.
import { createApprovalGate } from "@reopt-ai/opt-harness/core";
const gate = createApprovalGate({
requireApproval: ["bootstrap_bundle_required", "design_alignment_required"],
});
// 고위험 행동 시 승인 요청
const req = gate.requestApproval(
"bootstrap_bundle_required",
"implementer-agent",
);
// → { id: "approval-1", status: "pending", ... }
// 인간이 검토 후 승인
gate.approve(req.id, "human-reviewer");
// validateAgentInstruction에서 승인 여부 자동 검증
const result = validateAgentInstruction(
{ action: "create-screen", recipe: "list", approvalId: req.id },
manifest, "implement", gate, registry,
);
createApprovalGate — 인간 승인 워크플로와 검증 통합
Approval Gate는 reopt architecture의 Human Approval 패턴을 구현한다. 기본 설정은 requireApproval: []로, 승인이 필요 없다(후방 호환). 위험 등급이 높은 가드 코드를 등록하면 해당 행동에 인간 승인이 강제된다. validateAgentInstruction이 phase 게이팅, approval 검증, 에이전트 충돌 감지를 하나의 검증 파이프라인으로 통합한다.
Temporal Scoring — 거버넌스의 시간 축
reopt architecture의 OCLS 루프에서 SHARPEN 단계는 '운영 데이터가 계약을 갱신한다'고 말한다. opt-harness의 Score Tracker는 이 피드백 루프의 구현이다. 점수를 시계열로 추적하고, 회귀(regression)를 감지하며, 개선 추세를 보고한다.
import { createScoreTracker } from "@reopt-ai/opt-harness/core";
const tracker = createScoreTracker();
// 점수 기록 — scoredAt, previousScore, delta 자동 생성
tracker.record(computeCompletenessScore(findings1, 20), "audit-agent");
// → { score: 72, scoredAt: "2026-04-14T...", previousScore: undefined }
tracker.record(computeCompletenessScore(findings2, 20), "audit-agent");
// → { score: 85, delta: 13, previousScore: 72 }
tracker.record(computeCompletenessScore(findings3, 20), "audit-agent");
// → { score: 78, delta: -7, previousScore: 85 }
// 추세 분석
tracker.trend(); // → "regressing"
tracker.hasRegression(); // → true
tracker.latest(); // → { score: { score: 78, ... }, scoredAt: "..." }
createScoreTracker — 점수 시계열 추적과 회귀 감지
Score Tracker가 회귀를 감지하면 다음 개선 사이클이 촉발된다. 이것이 OCLS 루프의 SHARPEN→OWN 피드백이다. '점수가 85에서 78로 하락했다'는 시그널이 '어떤 변경이 레시피 계약을 위반했는가?'라는 질문으로 이어지고, 새로운 소유자 지정과 계약 재검토가 시작된다.
Completeness Scoring의 커스텀 카테고리, Decision Log의 결정 근거, Agent Registry의 충돌 기록, Score Tracker의 시계열 추적이 결합되면, reopt architecture가 정의한 4가지 Agentic Debt(Authority Sprawl, Contract Gap, Observability Gap, Validation Gap) 모두를 구조적으로 감지하고 해소할 수 있는 인프라가 완성된다.
결론 — 구조가 곧 거버넌스, 그리고 거버넌스는 진화한다
opt-harness는 reopt architecture의 핵심 테제 'Agents Scale by Structure'를 제품 인프라로 구현한 사례다. 초기 버전에서 설계 시점의 거버넌스(매니페스트, 레시피, 슬롯, 정책)를 확보한 뒤, 운영 시점의 거버넌스(결정 추적, 멀티에이전트 조율, 승인, 시계열 점수)로 진화했다. 이 진화 자체가 OCLS 루프의 실천이다.
- 매니페스트가 앱의 거버넌스 경계를 선언한다 (Module Contract).
- 레시피가 화면의 책임을 분류한다 (Responsibility Partitioning).
- 슬롯이 컴포넌트의 소유권을 정의한다 (Own Every Outcome).
- 정책이 허용 범위를 제한한다 (Evaluation & Guardrails).
- Phase-Aware Protocol이 에이전트의 판단 범위를 단계별로 좁힌다 (Contract First).
- Decision Log가 모든 결정을 추적 가능하게 만든다 (Decision Traceability).
- Agent Registry가 멀티에이전트 충돌을 감지한다 (Context Routing).
- Approval Gate가 고위험 행동에 인간 승인을 강제한다 (Human Approval).
- Score Tracker가 거버넌스 회귀를 감지하고 피드백 루프를 완성한다 (Sharpen in Operation).
에이전트가 폭발적으로 늘어나는 시대에, 에이전트가 만들어내는 제품 UI에도 같은 수준의 거버넌스가 필요하다. opt-harness는 그 거버넌스를 인프라 수준에서 강제하여, 에이전트가 늘어나도 시스템이 설명 가능하고 운영 가능한 상태를 유지할 수 있게 한다. 구조가 곧 거버넌스이고, 거버넌스는 운영에서 진화한다.
태그