opt-shell
opt-ui 테마만으로는 고정되지 않는 제품 화면의 구조, 상태 UX, 작업 흐름을 code-first 규약으로 묶는 design harness engineering layer입니다.
reopt designUpdated
opt-ui 위에서 app shell, page rhythm, state boundary, datagrid/editor adapter처럼 제품 화면의 구조적 일관성을 담당합니다.
Internal-first: opt-shell는 공개 컴포넌트 카탈로그가 아니라 제품 품질 프레임입니다. 첫 적용은 Builder와 playground adapter demo에 한정하지만, 목표는 에이전트와 사람이 같은 규약으로 제품급 화면을 반복 생산하게 만드는 것입니다.
Entry points: @reopt-ai/opt-shell은 React runtime, @reopt-ai/opt-shell/core는 server-safe factory와 정책 해석, @reopt-ai/opt-shell/meta는 docs metadata입니다. 하네스 검사 명령과 authoring audit helper는 현재 @reopt-ai/opt-cli / @reopt-ai/opt-cli/audit에서 소유합니다.
1. 북극성
opt-ui가 무엇으로 화면을 만들지 제공한다면, 루트 `DESIGN.md`는 어떻게 보여야 하는지 정하고, opt-shell는 제품급 화면을 어떤 규율로 만들지 제공합니다. 그래서 이 문서 묶음도 단순 API 안내가 아니라 visual contract, mission, recipe, agent contract, rollout evidence 순으로 읽히게 구성합니다.
최근에는 여기에 운영 관점이 추가됐습니다. 이제 opt-shell는 code layer만이 아니라, managed harness draft를 preview, review, approval, activation으로 다루는 사용자-facing workflow까지 포함합니다. 즉, 제품 품질 규약과 그 규약을 적용하는 거버넌스 surface를 함께 봐야 전체 그림이 맞습니다.
2. 왜 opt-shell인가
opt-ui는 토큰과 컴포넌트의 일관성을 잘 해결하지만, 실제 제품 화면에서 반복되는 문제는 별도였습니다. 페이지 폭이 흔들리고, loading/empty/error 상태 copy가 화면마다 달라지고, DataGrid와 Editor 주변의 toolbar, inspector, footer chrome이 제각각 생기기 시작했습니다. opt-shell는 그 문제를 "새 컴포넌트를 더 만드는 것"이 아니라 "제품 화면의 틀을 고정하는 것"으로 해결합니다.
여기서 끝나지 않습니다. 실제 팀은 후보 harness가 active baseline과 어떻게 다른지 즉시 이해해야 하고, review note와 actor evidence를 남긴 뒤, 승인된 후보만 runtime으로 올려야 합니다. 그래서 Builder Harness Manager는 부가 기능이 아니라 opt-shell의 운영 면을 증명하는 핵심 surface입니다.
import {
DashboardWorkspace,
ShellAppShell,
ShellCollapsibleNav,
ShellProvider,
ShellSection,
ShellStateBoundary,
} from "@reopt-ai/opt-shell";
import { builderHarness } from "@/lib/harness";
import type { ReactNode } from "react";
export function BuilderFrame({
nav,
children,
}: {
nav: ReactNode;
children: ReactNode;
}) {
return (
<ShellProvider manifest={builderHarness}>
<ShellAppShell nav={<ShellCollapsibleNav>{nav}</ShellCollapsibleNav>}>
<DashboardWorkspace
header={<div>Builder Header</div>}
toolbar={<div>Primary Actions</div>}
aside={<div>Inspector</div>}
>
<ShellStateBoundary loading={false}>
<ShellSection
title="Overview"
description="핵심 지표와 작업 상태를 한 리듬으로 묶습니다."
frame="card"
>
{children}
</ShellSection>
</ShellStateBoundary>
</DashboardWorkspace>
</ShellAppShell>
</ShellProvider>
);
}3. 동작 원리
opt-shell는 "선언 → 해석 → 주입 → 레이아웃 → 상태 정규화 → 관찰" 순서로 동작합니다. 아래 다이어그램은 이 파이프라인의 전체 흐름입니다.
Architecture Pipeline
1. Manifest
id, label, audience
defaults, contract
2. Policy Resolution
framework → manifest → runtime
3-layer override merge
3. ShellProvider
Context 주입
useShell() 노출
4. Workspace Recipe
list / detail / editor / dashboard / landing
slot layout + width + gap
5. State Boundary
loading / empty / error
입력 정규화 + fallback
6. Inspect Loop
snapshot + diff + staleness
opt-devtool devtools
3계층 정책 해석
모든 정책 필드는 runtime ?? manifest ?? framework 순서로 해석됩니다. 결과는 모든 필드가 확정된 ResolvedShellPolicy입니다.
| 정책 필드 | 역할 | 기본값 |
|---|---|---|
| density | 패딩, 폰트 크기 (compact: 13px) | comfortable |
| contentWidth | max-width (narrow~full) | wide |
| navigationMode | 사이드바 vs 스택 네비게이션 | sidebar |
| motionPolicy | 전체 모션 vs 최소 모션 | reduced |
| stateLabels | loading/empty/error 기본 문구 | 영문 기본 세트 |
| panelBehavior | aside/toolbar sticky 여부 | aside sticky, toolbar 아님 |
| adapters | DataGrid/Editor chrome 스타일 | card |
| theme | preset/generated 테마와 적용 scope | preset default |
워크스페이스 슬롯 레이아웃
5가지 레시피는 슬롯 모델을 공유하지만, width/gap/aside 기본값과 허용 슬롯이 다릅니다. 특히 filters는 list 전용이고 landing은 aside를 갖지 않습니다.
| 레시피 | 기본 width | aside sticky | gap | 주요 용도 |
|---|---|---|---|---|
| list | wide | Yes | gap-5 | 검색, 필터, 목록, 미리보기 |
| detail | normal | Yes | gap-6 | 리소스 상세, 요약, 섹션 |
| editor | wide | No | gap-4 | 편집, 리뷰, 저장 상태 |
| dashboard | full | No | gap-6 | 개요, 지표, 다음 작업 |
| landing | full | No | gap-0 | 공개 랜딩, 히어로, CTA |
Inspect Loop (상태 관찰)
하위 컴포넌트(StateBoundary, DataGridAdapter, EditorAdapter)가 자기 상태를 Provider로 보고하면, Provider는 스냅샷을 조립해서 opt-devtool 패널로 전달합니다.
StateBoundary
loading, empty, error
DataGridAdapter
active, chrome, loading
EditorAdapter
active, inspector, loading
ShellProvider useEffect
version++ → snapshot 조립 → diff 계산 → staleness 부착
opt-devtool Panel
policy diff 시각화 / staleness 경고 / adapter 상태 모니터링
상태 경계 정규화
ShellStateBoundary는 다양한 입력 형태를 받아 통일된 UI로 변환합니다.
| 입력 | 변환 결과 | 렌더링 |
|---|---|---|
| error: "서버 오류" | { title: "Something went wrong", description: "서버 오류" } | Alert (error) |
| error: new Error() | { title: error.name, description: error.message } | Alert (error) |
| empty: "항목 없음" | { title: "항목 없음", description: 기본문구 } | EmptyState |
| loading: true | 그대로 전달 | LoadingOverlay |
| 모두 false/null | 패스스루 | children 그대로 |
전체 조립 순서
// layout.tsx — 앱 프레임
<ShellProvider manifest={builderManifest}>
<ShellAppShell nav={<Nav />} header={<Header />}>
{children}
</ShellAppShell>
</ShellProvider>
// page.tsx — 목록 화면 예시
<ListWorkspace
header={<PageHeader title="프로젝트" />}
toolbar={<FilterBar />}
aside={<PreviewPanel />}
>
<ShellStateBoundary loading={isLoading} error={error}>
<ShellDataGridAdapter
columns={cols} rows={rows}
getRowId={(row) => row.id}
/>
</ShellStateBoundary>
</ListWorkspace>요약하면: 매니페스트(정적 선언) → 정책 해석(3계층 merge) → 프로바이더(Context 주입) → 레시피(슬롯 기반 레이아웃) → 상태 경계(loading/empty/error 정규화) → 어댑터(DataGrid/Editor 래핑) → Inspect(snapshot diff + staleness) 순서로 동작합니다.
4. 책임 경계
| 패키지 | 주요 소유 영역 | 대표 예시 |
|---|---|---|
| opt-ui | 토큰, primitive, shell, surface | Theme, AppShell, SidebarNav, Form/Surface 조합 |
| opt-shell | 제품 frame, recipe, page rhythm, state UX, adapter chrome, inspect snapshot | ShellProvider, workspace recipes, ShellStateBoundary, adapters, Builder rollout integration |
| opt-datagrid | 편집형 그리드 엔진, selection, virtualization, remote protocol | DataGrid, hooks, remote datasource contract |
| opt-editor | 문서 엔진, block catalog, streaming, markdown 변환 | Editor, store, stream compiler, custom blocks |
5. 문서에서 코드까지
opt-shell는 설명과 구현이 분리되면 금방 흐려집니다. visual intent는 루트 `DESIGN.md`에, 역할 정의는 mission 문서에, 화면 유형은 recipes 문서에, 실행 규칙은 agent contract 문서에 둡니다. 실제 구현과 검사 도구는 그 언어를 그대로 사용해야 합니다. 현재 runtime은 workspace component를 primary API로 사용하고, `ShellPage recipe="..."`는 low-level escape hatch로 남습니다.
DESIGN.md
루트 visual contract로 색, 타이포, component styling, responsive tone을 정의합니다.
Mission
왜 이 레이어가 필요한지, 무엇을 소유하고 무엇을 소유하지 않는지 정의합니다.
Recipes
화면 유형을 List, Detail, Editor, Dashboard, Landing recipe로 고정하고 runtime 기본값의 출발점으로 사용합니다.
Runtime
workspace component와 adapters로 구현하고, ShellPage는 low-level escape hatch로 남깁니다.
Audit
opt-cli의 `opt harness check/doctor`와 lint가 workspace first, adapter before engine, fullscreen-tool surface contract, scaffold/docs drift 규칙을 검사합니다.
Proof
Builder 실화면과 fresh design proof, smoke + visual proof로 recipe screen과 fullscreen tool 계약을 실제 제품 화면에 연결합니다.
Management UI
Builder Harness Manager가 workspace-owned draft/active lifecycle, approval review, live preview를 사용자 수준에서 노출합니다.
Scaffold
새 화면은 scaffold에서 시작해 raw page composition이 아닌 harness-owned skeleton 위에서 발전시킵니다.
Operational guards
- Save before review: Preview proof와 review request는 저장된 draft definition을 기준으로만 평가합니다.
- Meaningful diff required: active baseline과 의미 있는 차이가 없으면 review request와 approval이 409로 막힙니다.
- Edits reset review: review 이후 저장된 수정이 생기면 status는 다시 DRAFT로 내려가고 audit evidence가 남습니다.
- APPROVED required: activate는 APPROVED draft만 통과시키며, active runtime 반영 전 review state를 다시 확인합니다.
- Design alignment required: alignment score가 review 상태면 APPROVED여도 activate가 409 design_review_required로 막힙니다.
- Fresh design proof required: Preview에서 현재 draft hash와 일치하는 PASS proof를 다시 캡처해야 activate readiness가 닫힙니다.
- Bootstrap bundle required: 새 route는 entry, contract, preview fixture, docs, test, guard matrix를 같이 유지해야 bootstrap-ready로 간주합니다.
Scaffold bundle
- Entry `page.tsx`: workspace recipe 또는 fullscreen-tool surface를 시작하는 실제 route entry입니다.
- Contract `.harness-contract.ts`: route kind, required slots, artifact graph, verification scenario를 선언합니다.
- Preview fixture `.harness-preview.fixture.ts`: candidate/default/proof drift 상태를 preview와 review loop에서 재현하는 bootstrap fixture입니다.
- Docs note `.harness-doc.md`: route-specific rollout note와 artifact 연결 상태를 소스 옆에서 유지합니다.
- Test stub `.harness.test.ts`: generated bundle이 aligned 상태로 시작하는지 확인하고 route 전용 scenario test로 확장합니다.
- Guard matrix `.harness-guard-matrix.md`: review, design proof, activation blocker, verification matrix를 sidecar 문서로 유지합니다.
6. 핵심 런타임 블록
지금 구현은 recipe-aware runtime을 넘어 workspace-first API, fresh design proof gate, generated docs, `opt harness check/doctor`, searchable activity intelligence까지 함께 닫혀 있습니다. fullscreen tool 예외도 이제 `ShellFullscreenToolSurface`로 공통 shell을 공유합니다. 현재의 초점은 기반 guard를 만드는 일이 아니라, 이 운영 기준선을 더 많은 rollout 대상과 scaffold 산출물에 반복 적용하는 것입니다.
ShellProvider
manifest와 policy를 주입해 density, content width, state labels를 앱 단위로 고정합니다.
ShellAppShell
sidebar, header, mobile chrome, utilities를 한 앱 셸 리듬으로 묶습니다.
ShellPage
현재 low-level escape hatch입니다. header, toolbar, filters, content, aside, footer 슬롯과 recipe 기본값을 고정합니다.
Runtime Recipes
list, detail, editor, dashboard, landing recipe가 width, gap, aside behavior 기본값과 audit 기준을 제공합니다.
ShellFullscreenToolSurface
blocks, theme, uxflow, page builder 같은 fullscreen tool 예외 화면을 위한 공통 runtime shell입니다.
ShellSection
섹션 제목, 보조 설명, 액션, card frame을 반복 가능하게 표준화합니다.
ShellStateBoundary
loading, empty, error copy와 layout fallback을 화면 전반에서 통일합니다.
Harness Adapters
DataGrid와 Editor 엔진은 유지한 채 toolbar, status, inspector, footer chrome만 감쌉니다.
Workspace Components
ListWorkspace, DetailWorkspace, EditorWorkspace, DashboardWorkspace, LandingWorkspace가 현재 primary API입니다.
Scaffold CLI
workspace와 fullscreen-tool skeleton을 생성해 새 화면이 harness ownership에서 시작되게 만듭니다.
Harness Manager
Builder `/harnesses`에서 workspace 1:N harness를 생성하고 approval review, preview, 활성화를 관리할 수 있습니다.
Review Gate
draft는 preview, review evidence, fresh design proof를 거쳐 APPROVED 상태가 된 뒤에만 active runtime으로 승격됩니다.
Design Proof
Preview에서 현재 draft hash와 연결된 PASS proof를 저장하고, stale proof는 activate를 막습니다.
7. Adapter Demo 경로
opt-shell의 adapter 개념은 설명보다 실제 화면에서 더 명확합니다. 아래 경로에서 엔진은 그대로 두고 harness가 주변 chrome만 가져가는 현재 데모를 확인할 수 있습니다.
Data Console
LandingWorkspace + DashboardWorkspace + ListWorkspace + DetailWorkspace
Story Landing
Stacked shell + proof-driven editorial landing
Briefing Landing
Sidebar shell + compact briefing-style landing
Campaign Landing
Full-width shell + immersive campaign motion layout
Adapters 문서
DataGrid와 Editor를 harness frame 안에 넣는 연결 방식을 설명합니다.
DataGrid Playground
엔진은 그대로 두고 harness가 toolbar/status/footer를 소유하는 데모입니다.
Editor Playground
editor engine 주위로 harness toolbar/inspector/footer를 감싼 데모입니다.
Builder Rollout
Builder recipe rollout, harness manager, proof-aware governance loop를 확인합니다.
Builder Harness Manager
Builder `/harnesses`를 기준으로 draft 생성, preview, review, approval, activation 흐름을 실제 사용법으로 설명합니다.
Builder Harness Manager
workspace 아래 여러 draft harness를 만들고 approval review와 candidate vs active preview를 비교하는 실제 관리 UI입니다.
8. 권장 읽기 순서
- Mission전에 루트 `DESIGN.md`로 visual intent를 먼저 읽고, 그다음 역할과 비목표를 고정합니다.
- 시작하기와 provider 예제로 앱 수준 정책을 연결합니다.
- Recipes와 핵심 개념으로 화면 유형과 state boundary를 맞추고, 현재는 workspace-first abstraction을 기준으로 삼습니다.
- Adapters와 Agent Contract로 engine 경계와 실행 규칙을 확정합니다.
- Builder Rollout과 Rollout Playbook으로 실제 적용 증거, project screen rollout, fullscreen tool 예외, smoke proof 순서를 확인합니다.