bada-terminal / guide.html
VanyaJ's picture
Upload guide.html with huggingface_hub
f668c74 verified
Raw
History Blame Contribute Delete
139 kB
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BADA Terminal Suite — Documentation & Guide</title>
<meta name="description" content="Claude Code CLI 기반 루프 엔지니어링 플랫폼 BADA Terminal의 메뉴 가이드, 기능 설명 및 사용 설명서">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<!-- Styling -->
<style>
:root {
--bg: #1e1e2e;
--mantle: #181825;
--crust: #11111b;
--text: #cdd6f4;
--subtext: #a6adc8;
/* Accent Colors (Catppuccin Mocha) */
--mauve: #cba6f7;
--blue: #89b4fa;
--lavender: #b4befe;
--green: #a6e3a1;
--yellow: #f9e2af;
--red: #f38ba8;
--peach: #fab387;
--teal: #94e2d5;
/* UI Elements */
--surface0: #313244;
--surface1: #45475a;
--surface2: #585b70;
--overlay0: #6c7086;
--border: rgba(255, 255, 255, 0.06);
--glass-bg: rgba(24, 24, 37, 0.7);
--glass-border: rgba(255, 255, 255, 0.05);
--card-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
--transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Light Theme Overrides */
body.light-theme {
--bg: #eff1f5;
--mantle: #e6e9ef;
--crust: #dce0e8;
--text: #4c4f69;
--subtext: #5c5f77;
--mauve: #8839ef;
--blue: #1e66f5;
--lavender: #7287fd;
--green: #40a02b;
--yellow: #df8e1d;
--red: #d20f39;
--peach: #fe640b;
--teal: #179287;
--surface0: #ccd0da;
--surface1: #bcc0cc;
--surface2: #acb0be;
--overlay0: #8c8fa1;
--border: rgba(0, 0, 0, 0.06);
--glass-bg: rgba(230, 233, 239, 0.85);
--glass-border: rgba(0, 0, 0, 0.08);
--card-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.08);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
background-color: var(--bg);
color: var(--text);
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
overflow: hidden;
transition: background-color 0.3s ease, color 0.3s ease;
}
/* Layout Structure */
#app-layout {
display: flex;
width: 100vw;
height: 100vh;
overflow: hidden;
}
/* Sidebar Navigation */
#sidebar {
width: 300px;
height: 100%;
background: var(--mantle);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
flex-shrink: 0;
transition: background 0.3s ease, border-color 0.3s ease;
}
#sidebar-header {
padding: 24px;
border-bottom: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 12px;
}
.brand-title {
font-size: 22px;
font-weight: 800;
background: linear-gradient(135deg, var(--mauve), var(--blue));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -0.5px;
display: flex;
align-items: center;
gap: 8px;
}
.brand-subtitle {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--subtext);
}
#search-box {
position: relative;
margin-top: 8px;
}
#search-input {
width: 100%;
background: var(--crust);
border: 1px solid var(--surface0);
color: var(--text);
padding: 10px 14px 10px 36px;
border-radius: 8px;
font-size: 13px;
font-family: inherit;
outline: none;
transition: var(--transition);
}
#search-input:focus {
border-color: var(--mauve);
box-shadow: 0 0 0 2px rgba(203, 166, 247, 0.2);
}
.search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--overlay0);
font-size: 14px;
pointer-events: none;
}
#sidebar-menu {
flex: 1;
overflow-y: auto;
padding: 16px 12px;
}
#sidebar-menu::-webkit-scrollbar {
width: 4px;
}
#sidebar-menu::-webkit-scrollbar-thumb {
background: var(--surface0);
border-radius: 2px;
}
.menu-group {
margin-bottom: 20px;
}
.menu-group-title {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--overlay0);
padding-left: 12px;
margin-bottom: 8px;
}
.menu-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 8px;
color: var(--subtext);
text-decoration: none;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: var(--transition);
margin-bottom: 2px;
}
.menu-item:hover {
background: var(--surface0);
color: var(--text);
}
.menu-item.active {
background: rgba(203, 166, 247, 0.15);
color: var(--mauve);
font-weight: 600;
}
.menu-item-icon {
font-size: 16px;
width: 20px;
text-align: center;
}
#sidebar-footer {
padding: 16px 20px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--crust);
}
.theme-toggle-btn {
background: var(--surface0);
border: 1px solid var(--surface1);
color: var(--text);
width: 32px;
height: 32px;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: var(--transition);
}
.theme-toggle-btn:hover {
background: var(--surface1);
border-color: var(--mauve);
color: var(--mauve);
}
.version-tag {
font-size: 11px;
font-family: 'JetBrains Mono', monospace;
color: var(--overlay0);
background: var(--surface0);
padding: 3px 8px;
border-radius: 4px;
}
/* Main Content Container */
#content-container {
flex: 1;
height: 100%;
overflow-y: auto;
background: var(--bg);
padding: 40px 60px;
scroll-behavior: smooth;
}
#content-container::-webkit-scrollbar {
width: 8px;
}
#content-container::-webkit-scrollbar-track {
background: var(--bg);
}
#content-container::-webkit-scrollbar-thumb {
background: var(--surface0);
border-radius: 4px;
}
#content-container::-webkit-scrollbar-thumb:hover {
background: var(--surface1);
}
/* Content Typography & Elements */
.doc-section {
display: none;
animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
max-width: 900px;
margin: 0 auto;
}
.doc-section.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.section-header {
margin-bottom: 32px;
border-bottom: 1px solid var(--border);
padding-bottom: 20px;
}
.section-badge {
display: inline-block;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--mauve);
background: rgba(203, 166, 247, 0.12);
padding: 4px 10px;
border-radius: 99px;
margin-bottom: 12px;
}
h1 {
font-size: 36px;
font-weight: 800;
color: var(--text);
letter-spacing: -1px;
}
p.section-desc {
font-size: 16px;
color: var(--subtext);
margin-top: 8px;
line-height: 1.5;
}
h2 {
font-size: 22px;
font-weight: 700;
color: var(--text);
margin-top: 40px;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 10px;
}
h2::before {
content: '';
display: inline-block;
width: 4px;
height: 18px;
background: var(--mauve);
border-radius: 2px;
}
p {
font-size: 15px;
line-height: 1.7;
color: var(--subtext);
margin-bottom: 16px;
}
/* Grid layout for cards */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 20px;
margin: 24px 0;
}
.feature-card {
background: var(--mantle);
border: 1px solid var(--border);
padding: 24px;
border-radius: 12px;
box-shadow: var(--card-shadow);
transition: var(--transition);
display: flex;
flex-direction: column;
gap: 12px;
}
.feature-card:hover {
transform: translateY(-4px);
border-color: var(--mauve);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.card-icon {
font-size: 28px;
color: var(--mauve);
background: rgba(203, 166, 247, 0.1);
width: 52px;
height: 52px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.card-title {
font-size: 17px;
font-weight: 700;
color: var(--text);
}
.card-text {
font-size: 13px;
color: var(--subtext);
line-height: 1.5;
}
.card-badge {
display: inline-block;
align-self: flex-start;
font-size: 10px;
font-weight: 700;
font-family: 'JetBrains Mono', monospace;
padding: 2px 6px;
border-radius: 4px;
text-transform: uppercase;
}
.badge-primary { background: rgba(137, 180, 250, 0.15); color: var(--blue); }
.badge-secondary { background: rgba(166, 227, 161, 0.15); color: var(--green); }
.badge-tertiary { background: rgba(249, 226, 175, 0.15); color: var(--yellow); }
.badge-quaternary { background: rgba(243, 139, 168, 0.15); color: var(--red); }
/* Code Blocks */
pre {
background: var(--crust);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 20px;
overflow-x: auto;
margin: 20px 0;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.5;
position: relative;
}
code {
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
background: var(--mantle);
color: var(--peach);
padding: 2px 6px;
border-radius: 4px;
border: 1px solid var(--border);
}
pre code {
background: transparent;
color: var(--text);
padding: 0;
border: none;
border-radius: 0;
}
.code-header {
background: var(--mantle);
border: 1px solid var(--border);
border-bottom: none;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
padding: 8px 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--subtext);
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: -20px;
margin-top: 20px;
}
.code-header + pre {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
/* Lists */
ul.doc-list {
list-style-type: none;
margin: 16px 0;
}
ul.doc-list li {
position: relative;
padding-left: 24px;
font-size: 15px;
color: var(--subtext);
line-height: 1.7;
margin-bottom: 12px;
}
ul.doc-list li::before {
content: '✦';
position: absolute;
left: 4px;
color: var(--mauve);
font-size: 12px;
}
/* Alerts / Callouts */
.callout {
border-left: 4px solid var(--mauve);
background: rgba(203, 166, 247, 0.04);
padding: 20px;
border-radius: 0 12px 12px 0;
margin: 24px 0;
display: flex;
gap: 16px;
}
.callout.info {
border-left-color: var(--blue);
background: rgba(137, 180, 250, 0.04);
}
.callout.warning {
border-left-color: var(--yellow);
background: rgba(249, 226, 175, 0.04);
}
.callout.danger {
border-left-color: var(--red);
background: rgba(243, 139, 168, 0.04);
}
.callout-icon {
font-size: 22px;
line-height: 1;
margin-top: 2px;
}
.callout-content {
flex: 1;
}
.callout-title {
font-size: 15px;
font-weight: 700;
color: var(--text);
margin-bottom: 6px;
}
.callout-text {
font-size: 14px;
color: var(--subtext);
margin: 0;
line-height: 1.5;
}
/* Interactive tabs inside sections */
.tab-container {
margin: 24px 0;
}
.tab-headers {
display: flex;
border-bottom: 1px solid var(--border);
gap: 4px;
}
.tab-header {
padding: 10px 18px;
border: 1px solid transparent;
border-bottom: none;
border-radius: 8px 8px 0 0;
cursor: pointer;
font-size: 14px;
font-weight: 600;
color: var(--subtext);
transition: var(--transition);
margin-bottom: -1px;
}
.tab-header:hover {
color: var(--text);
}
.tab-header.active {
background: var(--mantle);
border-color: var(--border);
color: var(--mauve);
border-bottom: 1px solid var(--mantle);
}
.tab-content {
background: var(--mantle);
border: 1px solid var(--border);
border-top: none;
padding: 24px;
border-radius: 0 0 12px 12px;
display: none;
}
.tab-content.active {
display: block;
}
/* Steps Layout */
.step-container {
position: relative;
padding-left: 40px;
margin: 24px 0;
}
.step-container::before {
content: '';
position: absolute;
left: 17px;
top: 0;
width: 2px;
height: 100%;
background: var(--surface0);
z-index: 1;
}
.step-item {
position: relative;
margin-bottom: 32px;
}
.step-item:last-child {
margin-bottom: 0;
}
.step-badge {
position: absolute;
left: -40px;
top: 0;
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--surface1);
border: 2px solid var(--bg);
color: var(--text);
font-weight: 700;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
transition: var(--transition);
}
.step-item:hover .step-badge {
background: var(--mauve);
color: var(--crust);
transform: scale(1.1);
}
.step-title {
font-size: 17px;
font-weight: 700;
color: var(--text);
margin-bottom: 8px;
}
.step-desc {
font-size: 14px;
color: var(--subtext);
line-height: 1.6;
}
/* Database Schema Table Styling */
table.schema-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 13.5px;
text-align: left;
background: var(--mantle);
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--border);
}
table.schema-table th {
background: var(--surface0);
color: var(--mauve);
font-weight: 600;
padding: 10px 14px;
border-bottom: 1px solid var(--border);
}
table.schema-table td {
padding: 10px 14px;
border-bottom: 1px solid var(--border);
color: var(--subtext);
}
table.schema-table tr:last-child td {
border-bottom: none;
}
table.schema-table code {
background: var(--crust);
padding: 2px 4px;
border-radius: 4px;
color: var(--peach);
border: none;
font-size: 12px;
}
/* Sticky Content Header Navigation */
#content-header {
position: sticky;
top: 0;
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
padding: 14px 40px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 100;
margin: -40px -60px 40px -60px;
}
#current-section-title {
font-weight: 700;
color: var(--text);
}
#header-toc-select {
background: var(--crust);
color: var(--text);
border: 1px solid var(--surface1);
padding: 6px 14px;
border-radius: 6px;
font-size: 13px;
outline: none;
cursor: pointer;
font-family: inherit;
transition: var(--transition);
}
#header-toc-select:hover {
border-color: var(--mauve);
}
/* Responsive SVG Diagram Styling */
.diagram-container {
background: var(--mantle);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin: 28px 0;
box-shadow: var(--card-shadow);
display: flex;
justify-content: center;
align-items: center;
overflow-x: auto;
}
.diagram-svg {
width: 100%;
height: auto;
max-width: 800px;
user-select: none;
}
/* Interactive Highlights for Diagrams */
.diagram-svg .node {
cursor: pointer;
transform: var(--translate);
}
.diagram-svg .node rect {
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), fill 0.2s ease, stroke 0.2s ease;
transform-box: fill-box;
transform-origin: center;
}
.diagram-svg .node:hover rect {
transform: scale(1.03);
fill: var(--surface0);
stroke: var(--mauve);
}
.diagram-svg .flow-line {
stroke-dasharray: 8;
animation: dash 30s linear infinite;
}
@keyframes dash {
to {
stroke-dashoffset: -1000;
}
}
</style>
</head>
<body>
<div id="app-layout">
<!-- Sidebar Navigation -->
<aside id="sidebar">
<div id="sidebar-header">
<div class="brand-title">
<span>🐚 BADA Terminal</span>
</div>
<div class="brand-subtitle">Loop Engineering Suite</div>
<div style="font-size: 11px; font-family: 'JetBrains Mono', monospace; color: var(--subtext); margin-top: 4px; display: flex; align-items: center; gap: 6px;">
<span style="background: var(--surface0); padding: 2px 6px; border-radius: 4px; color: var(--mauve); font-weight: 600;">v1.4.0</span>
<span>Updated: 2026-06-21</span>
</div>
<div id="search-box">
<span class="search-icon">🔍</span>
<input type="text" id="search-input" placeholder="문서 검색..." autocomplete="off">
</div>
</div>
<nav id="sidebar-menu">
<div class="menu-group">
<div class="menu-group-title">시작하기</div>
<div class="menu-item active" data-target="intro">
<span class="menu-item-icon">💡</span> 소개 및 아키텍처
</div>
<div class="menu-item" data-target="prerequisites-install">
<span class="menu-item-icon">🛠️</span> 필수 도구 설치 가이드
</div>
<div class="menu-item" data-target="quickstart">
<span class="menu-item-icon">🚀</span> 퀵 스타트 가이드
</div>
<div class="menu-item" data-target="usage-shortcuts">
<span class="menu-item-icon">🎹</span> 사용법 & 단축키
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">상세 메뉴 설명</div>
<div class="menu-item" data-target="menus-dashboard">
<span class="menu-item-icon">💻</span> 메인 및 터미널
</div>
<div class="menu-item" data-target="menus-workflow">
<span class="menu-item-icon">🌿</span> 워크플로우 디자이너
</div>
<div class="menu-item" data-target="menus-scheduler">
<span class="menu-item-icon"></span> 배치 스케줄러
</div>
<div class="menu-item" data-target="menus-harness">
<span class="menu-item-icon">🛡️</span> 하네스 매니저
</div>
<div class="menu-item" data-target="menus-knowledge">
<span class="menu-item-icon">📊</span> 지식 그래프 & 위키
</div>
<div class="menu-item" data-target="menus-knowledge-architecture">
<span class="menu-item-icon">🧠</span> 4대 지식 관리 체계
</div>
<div class="menu-item" data-target="knowledge-headroom-integration">
<span class="menu-item-icon">🛡️</span> 지식 RAG & Headroom 연계
</div>
<div class="menu-item" data-target="knowledge-diet">
<span class="menu-item-icon">📉</span> 지식 관리 & 토큰 다이어트
</div>
<div class="menu-item" data-target="menus-sftp-security">
<span class="menu-item-icon">🔒</span> SFTP 샌드박스 & 보안
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">핵심 루프 메커니즘</div>
<div class="menu-item" data-target="loops-engineering-guide">
<span class="menu-item-icon">🔄</span> 루프 엔지니어링 가이드
</div>
<div class="menu-item" data-target="loops-worktree">
<span class="menu-item-icon"></span> Git Worktree 격리
</div>
<div class="menu-item" data-target="loops-feedback">
<span class="menu-item-icon">🔄</span> Maker-Checker 루프
</div>
<div class="menu-item" data-target="loops-sandbox">
<span class="menu-item-icon">📦</span> JS VM 샌드박스
</div>
<div class="menu-item" data-target="docker-sandbox">
<span class="menu-item-icon">🐳</span> Docker 샌드박스 v2
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">장애 트리아지 & CLI</div>
<div class="menu-item" data-target="triage-guide">
<span class="menu-item-icon">🚨</span> AI 오토 트리아지
</div>
<div class="menu-item" data-target="cli-guide">
<span class="menu-item-icon">⚙️</span> CLI 트리거 연동
</div>
</div>
</nav>
<div id="sidebar-footer">
<button class="theme-toggle-btn" id="theme-toggle" title="다크/라이트 테마 전환">
🌓
</button>
<span class="version-tag">v1.4.0</span>
</div>
</aside>
<!-- Main Content Area -->
<main id="content-container">
<!-- Sticky Header Breadcrumb & TOC -->
<div id="content-header">
<div style="font-size: 14px; font-weight: 500; color: var(--subtext); display: flex; align-items: center; gap: 8px;">
<span>📖 Docs</span>
<span>/</span>
<span id="current-section-title">소개 및 아키텍처</span>
</div>
<div>
<select id="header-toc-select" title="빠른 이동">
<option value="intro">💡 소개 및 아키텍처</option>
<option value="quickstart">🚀 퀵 스타트 가이드</option>
<option value="menus-dashboard">💻 메인 및 터미널 (PTY/IPC)</option>
<option value="menus-workflow">🌿 워크플로우 디자이너 & 모니터</option>
<option value="menus-scheduler">⏰ 배치 스케줄러</option>
<option value="menus-harness">🛡️ 하네스 매니저 (검증/트리아지)</option>
<option value="menus-knowledge">📊 지식 그래프 & 위키 RAG</option>
<option value="menus-knowledge-architecture">🧠 4대 지식 관리 체계</option>
<option value="knowledge-headroom-integration">🛡️ 지식 RAG & Headroom 연계</option>
<option value="menus-sftp-security">🔒 SFTP 샌드박스 & 보안 설정</option>
<option value="loops-engineering-guide">🔄 루프 엔지니어링 가이드</option>
<option value="loops-worktree">⚓ Git Worktree 격리 설계</option>
<option value="loops-feedback">🔄 Maker-Checker 피드백 루프</option>
<option value="loops-sandbox">📦 JS VM 샌드박스 격리</option>
<option value="docker-sandbox">🐳 Docker 개발 샌드박스 v2</option>
<option value="triage-guide">🚨 AI 자동 장애 트리아지</option>
<option value="cli-guide">⚙️ CLI 트리거 연동 가이드</option>
</select>
</div>
</div>
<!-- Section: Intro -->
<section id="intro" class="doc-section active">
<div class="section-header">
<span class="section-badge">Introduction</span>
<h1>소개 및 아키텍처</h1>
<p class="section-desc">BADA Terminal이 지향하는 루프 엔지니어링의 기본 철학과 복합 에이전트 오케스트레이션 아키텍처를 안내합니다.</p>
</div>
<p><strong>BADA Terminal</strong>은 Anthropic사의 <strong>Claude Code CLI</strong>를 핵심 코어 엔진으로 삼고, 에이전트의 오작동 및 폭주 방지 가드레일, 상태 격리, 자동 검증(Harness Verification), 그리고 AI 기반의 장애 분류(Triage) 체계를 로컬 데이터베이스와 밀결합한 <strong>독자적 루프 엔지니어링(Loop Engineering) 플랫폼</strong>입니다.</p>
<div class="callout info">
<span class="callout-icon">💡</span>
<div class="callout-content">
<h5 class="callout-title">루프 엔지니어링 (Loop Engineering) 이란?</h5>
<p class="callout-text">프롬프트와 에이전트 실행 단계를 일회성으로 끝내지 않고, 성공/실패 여부를 코드로 검증(Verification)하여 실패 시 이전 단계로 피드백을 전달하고 자가 참조 방식으로 완료될 때까지 반복 순환시키는 자동화 제어 설계 방식입니다.</p>
</div>
</div>
<h2>BADA 터미널 하이브리드 아키텍처</h2>
<p>BADA는 로컬 데스크톱 어플리케이션(Electron)과 분리된 스케줄러 코어, 그리고 SQLite DB 영속 레이어가 유기적으로 연결되어 작동합니다.</p>
<div class="grid-container">
<div class="feature-card">
<div class="card-icon"></div>
<div class="card-title">PTY 에이전트 래퍼</div>
<div class="card-text">가상 PTY 터미널을 사용해 로컬 Claude Code CLI와 인터랙션 세션을 캡처하고, 에이전트가 수행한 변경 사항을 실시간 로깅 및 통제합니다.</div>
<span class="card-badge badge-primary">PTY Runner</span>
</div>
<div class="feature-card">
<div class="card-icon"></div>
<div class="card-title">Git 격리 레이어</div>
<div class="card-text">에이전트가 코드를 어지럽히거나 파괴하는 것을 원천 차단하기 위해 임시 Git Worktree 및 체크포인트 브랜치를 자동 빌드 및 롤백합니다.</div>
<span class="card-badge badge-secondary">Git Worktree</span>
</div>
<div class="feature-card">
<div class="card-icon">🎛️</div>
<div class="card-title">복합 스텝 엔진</div>
<div class="card-text">CLI 커맨드, PTY Claude, 샌드박스 데이터 변환기(vm), API Webhook 전송을 순차적이고 동적으로 연결해 실행합니다.</div>
<span class="card-badge badge-tertiary">Scheduler</span>
</div>
</div>
</section>
<!-- Section: Prerequisites & Installation -->
<section id="prerequisites-install" class="doc-section">
<div class="section-header">
<div class="section-title">🛠️ 개발 환경 필수 도구 설치 가이드</div>
<div class="section-subtitle">BADA Terminal을 사용하기 위한 로컬 시스템 도구 설치 및 준비 안내</div>
</div>
<div class="doc-card">
<div class="doc-card-title">1. Git (버전 관리 필수)</div>
<p style="margin-bottom: 12px; line-height: 1.6;">BADA의 자율 브랜칭 및 3-Pass Seeding 격리 엔진은 Git을 기반으로 작동하므로 반드시 설치되어 있어야 합니다.</p>
<div class="code-block-header">설치 명령</div>
<pre><code># Windows (CMD / PowerShell)
winget install Git.Git
# macOS (Homebrew)
brew install git</code></pre>
</div>
<div class="doc-card">
<div class="doc-card-title">2. Node.js (JavaScript 런타임 및 npm)</div>
<p style="margin-bottom: 12px; line-height: 1.6;">BADA Terminal은 Node.js 및 Electron 프레임워크 기반으로 작동하므로 Node.js LTS 버전 설치가 권장됩니다.</p>
<div class="code-block-header">설치 명령</div>
<pre><code># Windows (CMD / PowerShell)
winget install OpenJS.NodeJS
# macOS (Homebrew)
brew install node</code></pre>
</div>
<div class="doc-card">
<div class="doc-card-title">3. Python 3 (실시간 모니터링 훅 실행)</div>
<p style="margin-bottom: 12px; line-height: 1.6;">Claude Code의 실행 트레이스 및 Langfuse 훅을 전송하고 디버깅 로그를 후처리하기 위해 필요합니다.</p>
<div class="code-block-header">설치 명령</div>
<pre><code># Windows (CMD / PowerShell)
winget install Python.Python.3
# macOS (Homebrew)
brew install python</code></pre>
</div>
<div class="doc-card">
<div class="doc-card-title">4. Claude Code CLI 및 CodeBurn 설치</div>
<p style="margin-bottom: 12px; line-height: 1.6;">Node.js 설치 완료 후 시스템 터미널에 아래 명령을 입력하여 Anthropic의 공식 CLI 및 토큰 분석기 패키지를 설치하십시오.</p>
<div class="code-block-header">설치 명령</div>
<pre><code>npm install -g @anthropic-ai/claude-code codeburn</code></pre>
<div class="callout callout-info" style="margin-top: 16px;">
<div class="callout-title">💡 안내</div>
<p>설치가 완료된 후 BADA Terminal에서 <strong>파일 ➜ 새 세션 (Cmd/Ctrl+N)</strong>을 실행하면 래핑된 인공지능 터미널이 자동으로 활성화됩니다.</p>
</div>
</div>
</section>
<!-- Section: Quickstart -->
<section id="quickstart" class="doc-section">
<div class="section-header">
<span class="section-badge">Getting Started</span>
<h1>퀵 스타트 가이드</h1>
<p class="section-desc">BADA Terminal을 사용해 첫 번째 자동 복구 피드백 루프를 시작하는 가장 빠른 방법입니다.</p>
</div>
<h2>3단계 실행 흐름</h2>
<div class="step-container">
<div class="step-item">
<span class="step-badge">1</span>
<div class="step-title">에이전트 프로필 생성 및 가이드라인 바인딩</div>
<div class="step-desc">
에이전트 관리 화면에서 사용할 에이전트의 역할(예: <code>Maker</code>, <code>Checker</code>)에 해당하는 시스템 프롬프트(Persona)를 편집하여 지정합니다. 시스템은 <code>.clauderules</code> 및 위키 RAG 컨텍스트를 자동 빌드해 줍니다.
</div>
</div>
<div class="step-item">
<span class="step-badge">2</span>
<div class="step-title">워크플로우 다이어그램 모델링</div>
<div class="step-desc">
워크플로우 디자이너를 열고 Maker 노드(Agent), Checker 노드(Reviewer)를 드래그 앤 드롭해 연결합니다. 노드가 실패하거나 반려될 때(approved = false) 뒤로 되돌아가도록 엣지를 매핑합니다.
</div>
</div>
<div class="step-item">
<span class="step-badge">3</span>
<div class="step-title">트리거 및 실시간 모니터링</div>
<div class="step-desc">
워크플로우를 구동하고 터미널 콘솔 로그를 감상합니다. Checker가 코드를 통과시키지 못하면, 에이전트가 직전 커밋과 diff 정보를 보고 피드백을 전달받아 스스로 버그를 고치는 광경을 볼 수 있습니다.
</div>
</div>
</div>
<h2>CLI로 간편하게 구동하기</h2>
<p>배경 실행 크론 데몬이나 클로드 네이티브 루틴에서 구동할 수 있는 CLI 트리거를 기본 내장하고 있습니다.</p>
<div class="code-header">Terminal CLI</div>
<pre><code># BADA 루트 폴더로 이동 후 워크플로우 구동
NODE_PATH=./node_modules node scratch/trigger-bada-workflow.js [프로젝트 ID] [워크플로우 ID]</code></pre>
</section>
<!-- Section: Usage & Shortcuts -->
<section id="usage-shortcuts" class="doc-section">
<div class="section-header">
<div class="section-title">🎹 BADA 사용법 & 단축키</div>
<div class="section-subtitle">루프 엔지니어링 플랫폼을 효율적으로 다루기 위한 사용 가이드 및 단축키 리스트</div>
</div>
<div class="doc-card">
<div class="doc-card-title">기본 플랫폼 사용 지침</div>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>로컬 격리 루프 실행</strong>: BADA는 Claude Code CLI를 핵심 코어로 사용하는 로컬 격리형 루프 엔지니어링 플랫폼입니다.</li>
<li><strong>Maker-Checker 피드백 루프</strong>: 에이전트(Maker)가 코드 수정을 수행하고 검증기(Checker)가 이를 빌드/테스트하여 통과할 때까지 자가 교정 및 수정 루프를 반복 구동합니다.</li>
<li><strong>보안 및 자원 예산 통제</strong>: 병렬 격리(Git Worktree) 및 토큰 요금 상한제(Budget Guard)가 에이전트의 오작동 및 폭주로 인한 요금 폭탄을 원천 방지합니다.</li>
</ul>
</div>
<div class="doc-card">
<div class="doc-card-title">⌨️ 플랫폼 시스템 단축키</div>
<table style="width:100%; border-collapse:collapse; margin-top:12px;">
<thead>
<tr style="border-bottom:2px solid var(--surface0); text-align:left;">
<th style="padding:8px; font-size:13px; color:var(--subtext);">단축키</th>
<th style="padding:8px; font-size:13px; color:var(--subtext);">기능 및 설명</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + B</td>
<td style="padding:8px; font-size:13px;">CodeBurn 실시간 대시보드 토글 (토큰 사용량 및 비용 실시간 확인)</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + D</td>
<td style="padding:8px; font-size:13px;">Langfuse 원격 추적 모니터링 웹 대시보드 실행</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + T</td>
<td style="padding:8px; font-size:13px;">현재 세션의 토큰 사용량 절감 분석(Advisor) 요청</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + G</td>
<td style="padding:8px; font-size:13px;">지식 관리 시각화(D3.js 기반 지식 그래프 캔버스) 열기</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + N</td>
<td style="padding:8px; font-size:13px;">현재 폴더에 대한 새로운 터미널 CLI 세션 기동</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">Ctrl + O</td>
<td style="padding:8px; font-size:13px;">📂 폴더 선택 다이얼로그를 통해 작업 디렉토리 지정 및 세션 연결</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:8px; font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--mauve);">F12</td>
<td style="padding:8px; font-size:13px;">에디터 패널 및 소스 파일 인스펙터 사이드 패널 토글</td>
</tr>
</tbody>
</table>
</div>
<div class="doc-card">
<div class="doc-card-title">💡 알아두면 유용한 팁</div>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>지식 및 RAG 로딩</strong>: BADA Terminal은 <code>~/.claude/skills/</code> 경로에 내재된 전용 스킬(Knot, Obsidian 등)을 자동으로 기동합니다.</li>
<li><strong>링크 즉시 조작</strong>: 터미널 캔버스 및 로그 상에 파일 경로(예: <code>src/main.js</code>)나 URL이 표출되면, <strong>Ctrl + 클릭</strong>하여 연결된 로컬 에디터나 브라우저로 즉시 열어볼 수 있습니다.</li>
</ul>
</div>
</section>
<!-- Section: Menus Dashboard -->
<section id="menus-dashboard" class="doc-section">
<div class="section-header">
<span class="section-badge">Menu Guide</span>
<h1>메인 윈도우 및 터미널 (PTY / IPC)</h1>
<p class="section-desc">가상 PTY 터미널 스트림을 백엔드에서 격리 제어하고, 실시간 IPC 이벤트를 처리하는 기본 구조입니다.</p>
</div>
<h2>화면 구성 및 PTY 터미널 연계</h2>
<ul class="doc-list">
<li><strong>메인 에이전트 터미널 (Xterm.js)</strong>: 중앙 캔버스의 xterm.js는 백엔드의 <code>node-pty</code>와 실시간으로 바인딩되어 동작합니다. 사용자의 수동 개입(HITL) 입력과 에이전트 출력 스트림을 결합합니다.</li>
<li><strong>상단 에디터 및 에이전트 표시바</strong>: 현재 기동 중인 서브 에이전트 스레드 상태와 작동 예산(Cost), 경과 시간 게이지를 실시간 추적합니다.</li>
<li><strong>우측 에디터 슬라이드 패널 (Editor Panel)</strong>: <code>Ctrl+E</code> 단축키로 토글 가능하며, 에이전트가 탐색하거나 가공한 코드의 Git Diff 이력과 물리 트리 구조를 고속 렌더링합니다.</li>
</ul>
<h3>BADA Terminal 레이아웃 Mockup (화면 가이드)</h3>
<div style="background: var(--crust); border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin: 24px 0; box-shadow: var(--card-shadow);">
<!-- Window Header -->
<div style="display: flex; align-items: center; justify-content: space-between; padding-bottom: 12px; border-bottom: 1px solid var(--border); margin-bottom: 12px;">
<div style="display: flex; gap: 6px;">
<span style="width: 10px; height: 10px; background: var(--red); border-radius: 50%;"></span>
<span style="width: 10px; height: 10px; background: var(--yellow); border-radius: 50%;"></span>
<span style="width: 10px; height: 10px; background: var(--green); border-radius: 50%;"></span>
</div>
<div style="font-size: 11px; font-family: 'JetBrains Mono', monospace; color: var(--subtext);">BADA Terminal Suite v1.4.0</div>
<div style="width: 32px;"></div>
</div>
<!-- Window Content Area -->
<div style="display: flex; gap: 12px; height: 260px; font-family: sans-serif;">
<!-- Left Pane: Sidebar Mockup -->
<div style="width: 25%; background: var(--mantle); border: 1px solid var(--border); border-radius: 6px; padding: 10px; display: flex; flex-direction: column; gap: 8px;">
<div style="font-size: 10px; font-weight: 700; color: var(--mauve); text-transform: uppercase;">1. Navigation</div>
<div style="height: 14px; background: var(--surface0); border-radius: 4px; width: 85%;"></div>
<div style="height: 14px; background: var(--surface0); border-radius: 4px; width: 70%;"></div>
<div style="height: 14px; background: var(--surface1); border-radius: 4px; width: 90%;"></div>
<div style="height: 14px; background: var(--surface0); border-radius: 4px; width: 60%;"></div>
<div style="flex: 1;"></div>
<div style="font-size: 9px; color: var(--overlay0); text-align: center;">[사이드바 제어 영역]</div>
</div>
<!-- Center Pane: PTY Terminal Mockup -->
<div style="width: 50%; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 10px; display: flex; flex-direction: column; gap: 8px; position: relative;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="font-size: 10px; font-weight: 700; color: var(--blue); text-transform: uppercase;">2. Terminal Console</div>
<div style="font-size: 9px; background: rgba(166, 227, 161, 0.15); color: var(--green); padding: 2px 6px; border-radius: 4px; font-family: monospace;">RUNNING</div>
</div>
<div style="flex: 1; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--green); padding: 4px; overflow: hidden; line-height: 1.4;">
<div>$ claude-code run</div>
<div style="color: var(--text);">✔ Researching codebase...</div>
<div style="color: var(--text);">✔ Compiling dependencies...</div>
<div style="color: var(--yellow);">⚠ Found 1 validation error.</div>
<div style="color: var(--mauve); animation: blink 1s step-end infinite;">_</div>
</div>
<div style="font-size: 9px; color: var(--overlay0); text-align: center;">[Xterm.js 가상 터미널]</div>
</div>
<!-- Right Pane: Editor Panel Mockup -->
<div style="width: 25%; background: var(--mantle); border: 1px solid var(--border); border-radius: 6px; padding: 10px; display: flex; flex-direction: column; gap: 8px;">
<div style="font-size: 10px; font-weight: 700; color: var(--peach); text-transform: uppercase;">3. Editor &amp; Diff</div>
<div style="height: 14px; background: var(--surface0); border-radius: 4px; width: 95%;"></div>
<div style="height: 14px; background: rgba(243, 139, 168, 0.15); border-radius: 4px; width: 85%;"></div>
<div style="height: 14px; background: rgba(166, 227, 161, 0.15); border-radius: 4px; width: 90%;"></div>
<div style="height: 14px; background: var(--surface0); border-radius: 4px; width: 80%;"></div>
<div style="flex: 1;"></div>
<div style="font-size: 9px; color: var(--overlay0); text-align: center;">[코드/이력 슬라이드]</div>
</div>
</div>
</div>
<h2>PTY 프로세스 백엔드 스펙 (node-pty)</h2>
<p>BADA 코어는 플랫폼 비의존적인 PTY 세션을 생성하여 로컬 OS 쉘을 가상 래핑합니다. 백엔드의 생성 사양은 다음과 같습니다.</p>
<pre><code>const pty = require('node-pty');
const ptyProcess = pty.spawn(shell, [], {
name: 'xterm-color',
cols: 80,
rows: 24,
cwd: projectPath, // 작업 타겟 디렉토리
env: {
...process.env,
FORCE_COLOR: '1',
PAGER: 'cat' // Pager 대기 방지
}
});</code></pre>
<h2>실시간 IPC 통신 프로토콜</h2>
<p>Electron 메인 프로세스와 렌더러는 양방향 비동기 IPC 메시지로 통신합니다.</p>
<table class="schema-table">
<thead>
<tr>
<th>IPC 채널명</th>
<th>발신원 ➔ 수신원</th>
<th>페이로드 구조 & 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pty-data</code></td>
<td>Main ➔ Renderer</td>
<td><code>{ data: string }</code><br>가상 PTY 프로세스의 raw stdout/stderr 바이트 스트림 전달</td>
</tr>
<tr>
<td><code>pty-input</code></td>
<td>Renderer ➔ Main</td>
<td><code>{ input: string }</code><br>터미널 UI에서 입력된 사용자 키 및 승인(HITL) 커맨드 주입</td>
</tr>
<tr>
<td><code>pty-resize</code></td>
<td>Renderer ➔ Main</td>
<td><code>{ cols: number, rows: number }</code><br>터미널 레이아웃 변경 시 PTY 가상 그리드 크기 동기화</td>
</tr>
<tr>
<td><code>pty-kill</code></td>
<td>Renderer ➔ Main</td>
<td><code>void</code><br>기동 중인 PTY 프로세스 및 자식 트리 전체 강제 해제 요청</td>
</tr>
</tbody>
</table>
<h2>핵심 통제 및 프로세스 트리 수거</h2>
<div class="callout warning">
<span class="callout-icon">⚠️</span>
<div class="callout-content">
<h5 class="callout-title">프로세스 트리 SIGKILL 방어 기전</h5>
<p class="callout-text">
사용자가 단축키 <code>CmdOrCtrl+Shift+K</code> 또는 [안전 종료] 버튼을 작동하면, 백엔드는 PTY 세션의 <code>pid</code>를 기반으로 하위 자식 프로세스 트리를 탐색합니다. 단순 단일 kill이 아닌 <strong>PGID(Process Group ID) 전체에 SIGKILL</strong>을 발송함으로써, 에이전트가 기동한 컴파일러, 웹서버, 테스트 주자 등이 백그라운드에 고아(Zombie) 프로세스로 잔존하는 것을 물리적으로 완전 봉쇄합니다.
</p>
</div>
</div>
</section>
<!-- Section: Menus Workflow -->
<section id="menus-workflow" class="doc-section">
<div class="section-header">
<span class="section-badge">Menu Guide</span>
<h1>워크플로우 디자이너 & 모니터</h1>
<p class="section-desc">노드 기반의 시각적 워크플로우 드로잉 및 다중 단계 모니터 기능을 활용합니다.</p>
</div>
<h2>워크플로우 디자이너 (workflow-designer.html)</h2>
<p>Cytoscape.js를 기반으로 구축된 캔버스 영역으로, 드래그 앤 드롭을 사용해 복잡한 조건문과 에이전트 루프백 관계를 그래픽 노드로 모델링합니다.</p>
<h3>노드 유형 및 포트 결합 스펙</h3>
<ul class="doc-list">
<li><strong>Agent 노드 (Maker)</strong>: <code>input-port</code>(이전 피드백/지침 주입) 및 <code>output-port</code>(작성된 코드 파일 및 커밋 객체 전송)가 결합됩니다. 일반 지침 프롬프트를 전송받아 코드를 생성/수정하는 작업을 수행합니다.</li>
<li><strong>Reviewer 노드 (Checker)</strong>: <code>code-port</code>(Maker의 최종 산출물 전달) 및 <code>decision-port</code>를 가지며, <code>{"approved": boolean, "feedback": string}</code> 스키마의 JSON을 다음 엣지로 방출합니다.</li>
<li><strong>Harness 노드 (Verification)</strong>: <code>trigger-port</code>로 들어오는 신호에 따라 빌드/테스트 파이프라인(예: <code>npm run test</code>)을 구동하고 결과 코드(<code>0</code> 또는 <code>1</code>)를 판정 엣지로 리턴합니다.</li>
</ul>
<h2>워크플로우 모니터 (workflow-monitor.html)</h2>
<p>실시간으로 실행 상태(Idle, Running, Paused, Success, Failed)를 추적하며, 현재 활성화된 엣지와 노드를 밝은 네온 하이라이트로 보여줍니다.</p>
<p>사용자 피드백 대기(HITL) 혹은 예산 초과(Budget exceeded)로 대기 상태에 빠졌을 때 터미널 우측 제어판의 <strong>Pause / Resume / Restart / Kill</strong> 버튼이 즉각 활성화되어 조작할 수 있습니다.</p>
<h2>워크플로우 데이터 영속화 스펙 (SQLite DB)</h2>
<p>워크플로우 그래프의 노드 구조, 배치 순서, 엣지 결합 및 실시간 큐(Queue)는 다음 SQLite 스키마 테이블에 완전히 저장됩니다.</p>
<h3>1) <code>workflows</code> 테이블 (디자인 명세 정의)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 워크플로우 고유 식별자</td>
</tr>
<tr>
<td><code>project_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 연결된 대상 프로젝트 ID</td>
</tr>
<tr>
<td><code>name</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 워크플로우 이름</td>
</tr>
<tr>
<td><code>graph_json</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - Cytoscape 노드/엣지들의 JSON 명세 스트링</td>
</tr>
<tr>
<td><code>is_active</code></td>
<td>INTEGER</td>
<td><code>DEFAULT 1</code> - 활성화 여부 (0: 비활성, 1: 활성)</td>
</tr>
</tbody>
</table>
<h3>2) <code>workflow_tasks</code> 테이블 (실행 큐 상태 관리)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>task_id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 실행 큐 타스크 고유 식별자</td>
</tr>
<tr>
<td><code>run_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 해당 워크플로우 기동 ID (workflow_runs 참조)</td>
</tr>
<tr>
<td><code>node_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - Cytoscape 내의 고유 노드 ID</td>
</tr>
<tr>
<td><code>agent_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 실행을 위임받은 에이전트 식별자</td>
</tr>
<tr>
<td><code>payload</code></td>
<td>TEXT</td>
<td>노드 실행에 필요한 인자(프롬프트, 설정값) JSON</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 상태값 (<code>pending | running | success | failed | paused</code>)</td>
</tr>
<tr>
<td><code>result</code></td>
<td>TEXT</td>
<td>노드 실행 완료 후 반환한 텍스트 또는 JSON 데이터</td>
</tr>
</tbody>
</table>
<h2>그래프 JSON 구조 명세</h2>
<p><code>graph_json</code> 컬럼에 기입되는 Cytoscape 호환 JSON 구조 예시입니다.</p>
<pre><code>{
"nodes": [
{ "data": { "id": "maker_node", "label": "Code Writer", "type": "pty_agent" } },
{ "data": { "id": "checker_node", "label": "PR Reviewer", "type": "reviewer" } }
],
"edges": [
{ "data": { "id": "edge1", "source": "maker_node", "target": "checker_node", "type": "submit" } },
{ "data": { "id": "edge2", "source": "checker_node", "target": "maker_node", "type": "reject" } }
]
}</code></pre>
</section>
<!-- Section: Menus Scheduler -->
<section id="menus-scheduler" class="doc-section">
<div class="section-header">
<span class="section-badge">Menu Guide</span>
<h1>배치 스케줄러</h1>
<p class="section-desc">정기 크론 스케줄링과 복합 Sequential 스텝(Pipeline)을 관리하는 대시보드입니다.</p>
</div>
<h2>정적 검증 게이트 (Test-before-Schedule)</h2>
<p>BADA 배치 스케줄러는 보안 및 오작동 안전을 위해 **"사전 구동 테스트(Test Run)"**를 의무 통제합니다.</p>
<div class="callout danger">
<span class="callout-icon">🚫</span>
<div class="callout-content">
<h5 class="callout-title">활성 차단 락(Lock) 규칙</h5>
<p class="callout-text">새로운 배치 작업을 작성하고 즉시 스케줄링을 켤 수 없습니다. <code>Test Run</code> 버튼을 눌러 파이프라인 전체 단계가 100% 정상 구동 완료되었음이 확인되어 <code>is_tested_success = 1</code> 상태로 기록되어야 활성화 스위치를 켤 수 있습니다.</p>
</div>
</div>
<h2>비주얼 크론 생성기 & 표준 식 필드 규약</h2>
<p>복잡한 크론 식(<code>*/5 * * * *</code>)을 직접 수작업으로 적지 않고, 대시보드 편집창에서 주기(시간/일/주/월)와 설정 조건을 선택하면 자동으로 크론 파서가 안전한 포맷 식을 주입해 줍니다.</p>
<h3>크론 표현식 5필드 스펙</h3>
<pre><code>* * * * *
│ │ │ │ │
│ │ │ │ └─ 요일 (0 - 6) (0은 일요일)
│ │ │ └────── 월 (1 - 12)
│ │ └─────────── 일 (1 - 31)
│ └──────────────── 시 (0 - 23)
└───────────────────── 분 (0 - 59)</code></pre>
<p>예를 들어, 매주 월요일 새벽 3시 30분에 기동하고자 하는 경우 <code>30 3 * * 1</code> 표현식을 적용합니다.</p>
<h2>배치 스케줄러 데이터 영속화 스펙 (SQLite DB)</h2>
<p>배치 작업의 설정과 이력은 다음 SQLite 스키마 테이블에 완전히 저장됩니다.</p>
<h3><code>batch_tasks</code> 테이블 상세 정의</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 배치 태스크 고유 ID</td>
</tr>
<tr>
<td><code>project_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 소속 프로젝트 식별자</td>
</tr>
<tr>
<td><code>name</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 배치 작업 이름</td>
</tr>
<tr>
<td><code>prompt</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 구동 시 에이전트에 지입될 기본 지시문</td>
</tr>
<tr>
<td><code>cron_expr</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 크론 주기 설정 문자열 (예: <code>0 9 * * *</code>)</td>
</tr>
<tr>
<td><code>is_active</code></td>
<td>INTEGER</td>
<td><code>DEFAULT 0</code> - 활성화 토글 상태 (0: 대기, 1: 활성)</td>
</tr>
<tr>
<td><code>steps_json</code></td>
<td>TEXT</td>
<td>배치 파이프라인의 각 실행 스텝(PTY, script 등) 명세 배열 JSON</td>
</tr>
<tr>
<td><code>is_tested_success</code></td>
<td>INTEGER</td>
<td><code>DEFAULT 0</code> - 정적 검증 게이트 통과 여부 (1일 때만 활성화 가능)</td>
</tr>
<tr>
<td><code>loop_config</code></td>
<td>TEXT</td>
<td>루프 제한 예산 및 회수 설정 스냅샷 JSON</td>
</tr>
</tbody>
</table>
</section>
<!-- Section: Menus Harness -->
<section id="menus-harness" class="doc-section">
<div class="section-header">
<span class="section-badge">Menu Guide</span>
<h1>하네스 매니저 (검증 & AI 트리아지)</h1>
<p class="section-desc">로컬 에러 피드백 진화 루프의 기반이 되는 자동 검증 하네스(Harness) 도구를 구성하고 AI 진단을 연동합니다.</p>
</div>
<h2>하네스 매니저 UI (harness-manager.html)</h2>
<p>모리스(Mories) MCP 도구 및 로컬 폴더 빌드 파이프라인의 핵심 검증 명령어들을 영속 데이터베이스로 통제합니다.</p>
<div class="grid-container">
<div class="feature-card">
<div class="card-icon">🏗️</div>
<div class="card-title">검증 스크립트 결합</div>
<div class="card-text">특정 프로젝트에 바인딩할 테스트 스위트 구동 명령어(예: <code>jest</code>, <code>pytest</code>, <code>eslint</code>)를 이름별 카드로 선언해 보관합니다.</div>
</div>
<div class="feature-card">
<div class="card-icon">🧠</div>
<div class="card-title">진화 내역 리스너</div>
<div class="card-text">하네스 검사 시 에이전트가 제출한 코드의 빌드 실패 로그를 이력별로 차곡차곡 스택에 수집하여 진화(Evolve) 컨텍스트로 환원합니다.</div>
</div>
</div>
<h2>자동 검증 실행 프로토콜</h2>
<p>BADA가 에이전트 결과물에 대해 하네스를 구동할 때, 다음 프로시저를 차례대로 밟습니다.</p>
<div class="step-container">
<div class="step-item">
<span class="step-badge">1</span>
<div class="step-title">프로세스 샌드박싱 및 환경 격리</div>
<div class="step-desc">지정된 <code>validation_command</code>를 실행하기 전, PATH와 임시 파일을 샌드박스 영역에 맞춤 할당하여 실행 중인 로컬 머신의 환경 설정을 오염시키지 않도록 합니다.</div>
</div>
<div class="step-item">
<span class="step-badge">2</span>
<div class="step-title">종료 코드 캡처 & 1차 필터링</div>
<div class="step-desc">명령 실행의 <code>exitCode</code>를 캡처합니다. <code>0</code>이면 즉시 성공 엣지로 분기하고, <code>non-zero</code>인 경우 AI 장애 진단(Triage) 프로시저를 백그라운드 호출합니다.</div>
</div>
<div class="step-item">
<span class="step-badge">3</span>
<div class="step-title">AI 장애 트리아지(Triage) 및 학습 피드백 생성</div>
<div class="step-desc">트리아지 모듈이 동작해 터미널 버퍼 마지막 50라인을 해부하고 원인 분석과 처방전 마크다운을 작성하여 <code>triage_items</code> 및 에이전트 context에 적재합니다.</div>
</div>
</div>
<h2>하네스 및 트리아지 영속화 스펙 (SQLite DB)</h2>
<p>검증과 진단 정보는 아래 SQLite 스키마 컬럼에 저장되어 활용됩니다.</p>
<h3>1) <code>harnesses</code> 테이블 (검증 규칙 정의)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 하네스 고유 식별 ID</td>
</tr>
<tr>
<td><code>project_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 매핑 타겟 프로젝트 ID</td>
</tr>
<tr>
<td><code>name</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 하네스 도구명 (예: Jest Test Suite)</td>
</tr>
<tr>
<td><code>validation_command</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 실제 구동 쉘 명령어 (예: <code>npm run test</code>)</td>
</tr>
<tr>
<td><code>max_retries</code></td>
<td>INTEGER</td>
<td><code>DEFAULT 3</code> - 실패 시 허용되는 최대 재시도(루프) 횟수</td>
</tr>
<tr>
<td><code>success_criteria</code></td>
<td>TEXT</td>
<td>성공 판정 조건 문자열 (예: exit code 0 or regex matching)</td>
</tr>
</tbody>
</table>
<h3>2) <code>harness_runs</code> 테이블 (검사 실행 내역)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>run_id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 하네스 실행 고유 ID</td>
</tr>
<tr>
<td><code>harness_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 연결된 하네스 ID</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 상태 (<code>running | success | failed</code>)</td>
</tr>
<tr>
<td><code>logs</code></td>
<td>TEXT</td>
<td>검증 구동 시 캡처된 stdout/stderr 원시 텍스트 로그</td>
</tr>
</tbody>
</table>
<h3>3) <code>triage_items</code> 테이블 (AI 진단 인박스)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 의미</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 트리아지 항목 고유 ID</td>
</tr>
<tr>
<td><code>run_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 실패 원인이 된 해당 실행 ID</td>
</tr>
<tr>
<td><code>error_message</code></td>
<td>TEXT</td>
<td>터미널 스트림에서 발췌된 주요 컴파일/런타임 에러 라인</td>
</tr>
<tr>
<td><code>ai_analysis</code></td>
<td>TEXT</td>
<td>Claude가 실시간 생성한 마크다운 형식의 에러 원인 및 조치 가이드</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td><code>DEFAULT 'pending'</code> - 처리 상태 (<code>pending | resolved | ignored</code>)</td>
</tr>
</tbody>
</table>
</section>
<!-- Section: Menus Knowledge -->
<section id="menus-knowledge" class="doc-section">
<div class="section-header">
<span class="section-badge">Menu Guide</span>
<h1>지식 그래프 및 위키 RAG</h1>
<p class="section-desc">프로젝트 소스 코드와 문서의 연동 상태를 시각화하고 로컬 RAG 검색용 지식베이스를 적재합니다.</p>
</div>
<h2>지식 그래프 (knowledge-graph.html)</h2>
<p>D3.js 힘지향(Force-directed) 네트워크 그래프를 도입해 프로젝트 내 클래스, 메소드, 파일 상호 참조 관계 및 위키 문서 노드 간의 복합 엔티티를 한 눈에 파악할 수 있도록 해 줍니다. 노드 검색 및 줌, 특정 노드 더블클릭 시 세부 설명 카드가 오픈됩니다.</p>
<h2>RAGPresetManager & .clauderules 매핑</h2>
<p>BADA가 로컬 폴더에 <code>.clauderules</code> 파일 및 <code>AGENTS.md</code> 가이드를 생성할 때, 지식베이스와 위키에서 추출한 가벼운 핵심 도메인 정보와 룰 프리셋들을 임포트(Import)하여 Claude 에이전트가 로컬 디렉토리의 아키텍처 규칙을 위배하지 않도록 도메인 고정 인덱싱을 지원합니다.</p>
</section>
<!-- Section: Menus Knowledge Architecture -->
<section id="menus-knowledge-architecture" class="doc-section">
<div class="section-header">
<span class="section-badge"> 지식 아키텍처</span>
<h1>4대 지식 관리 체계</h1>
<p class="section-desc">바다 터미널이 메타데이터와 문서를 중복 없이 유기적으로 연동하여 단일 진실원(SSOT)을 유지하는 설계 구조를 설명합니다.</p>
</div>
<p>BADA Terminal은 지식의 중복(Duplication)과 모순을 예방하기 위해, 기계적 메타데이터인 <strong>지식 그래프</strong>와 인간 중심의 <strong>LLMWiki/Note</strong>, 그리고 에이전트가 상주하며 준수하는 <strong>Memory & Rules</strong>를 상호 격리하고 유기적으로 동적 바인딩합니다.</p>
<h2>1. 4대 지식 영역 비교</h2>
<div class="grid-container">
<div class="feature-card">
<div class="card-icon" style="background: rgba(166, 227, 161, 0.1); color: var(--green);">📝</div>
<div class="card-title">Note (지식 보관함)</div>
<div class="card-text">
<strong>글로벌 개인 개발 노트 및 재사용 가이드</strong><br>
프로젝트 경계를 넘어 모든 세션에서 범용적으로 공유하고 참고할 설계 원칙과 템플릿을 저장합니다. 옵시디언 Vault와 100% 호환되며 Git으로 버전 관리됩니다.
</div>
<span class="card-badge badge-secondary">Note / Knot</span>
</div>
<div class="feature-card">
<div class="card-icon" style="background: rgba(137, 180, 250, 0.1); color: var(--blue);">📚</div>
<div class="card-title">LLMWiki (프로젝트 위키)</div>
<div class="card-text">
<strong>특정 프로젝트 전용의 서술적 지식베이스</strong><br>
현재 작업 중인 폴더의 특정 API 스펙, 요구사항 정의서, 모듈 개요 등 기획과 설계의 맥락을 마크다운 문서 형식으로 보관합니다.
</div>
<span class="card-badge badge-primary">./wiki/</span>
</div>
<div class="feature-card">
<div class="card-icon" style="background: rgba(249, 226, 175, 0.1); color: var(--yellow);">🕸️</div>
<div class="card-title">지식 그래프 (DB)</div>
<div class="card-text">
<strong>코드베이스 기계적 메타데이터 네트워크</strong><br>
정적 분석기로 파싱한 함수/클래스 의존 관계와 대화 이력(Session),Provenances(실행 이력)를 SQLite DB에 노드와 엣지로 영속화합니다.
</div>
<span class="card-badge badge-tertiary">SQLite Graph DB</span>
</div>
<div class="feature-card">
<div class="card-icon" style="background: rgba(243, 139, 168, 0.1); color: var(--red);">⚙️</div>
<div class="card-title">Memory & Rules (에이전트 규칙)</div>
<div class="card-text">
<strong>에이전트 행동 법률 및 자가 학습 캐시</strong><br>
에이전트의 로컬 규율인 <code>.clauderules</code>/<code>CLAUDE.md</code>와 개발을 거치며 스스로 습득해 기록하는 <code>Auto Learnings</code> 기억 세포를 관리합니다.
</div>
<span class="card-badge badge-quaternary">Agent Core</span>
</div>
</div>
<h2>2. 바다코드에서의 지식 연동 메커니즘</h2>
<p>BADA는 정보가 파편화되는 것을 막기 위해 다음 3단계 파이프라인으로 지식을 수렴시킵니다.</p>
<div class="step-container">
<div class="step-item">
<div class="step-badge">1</div>
<div class="step-title">기계적 분석과 인간 지식의 격리</div>
<div class="step-desc">코드베이스의 물리적 구조는 <code>knowledge-db.js</code>에 의해 기계적으로 스캔되어 그래프 DB로 적재됩니다. 동시에 설계 맥락은 <code>LLMWiki</code><code>Note</code>의 마크다운 텍스트로 보존됩니다.</div>
</div>
<div class="step-item">
<div class="step-badge">2</div>
<div class="step-title">동적 심볼-위키 매핑 (Symbol-Wiki Mapping)</div>
<div class="step-desc"><code>skills-manager.js</code> 내의 매핑 엔진이 작동하여 그래프 DB 내의 함수/클래스 명칭과 LLMWiki 문서명을 실시간 대조 매칭합니다. (예: <code>startPty()</code><code>wiki/pty-architecture.md</code>)</div>
</div>
<div class="step-item">
<div class="step-badge">3</div>
<div class="step-title">CLAUDE.md 컴파일 및 Memory 로드</div>
<div class="step-desc">매핑된 링커 테이블과 위키 인덱스가 병합되어 최종 에이전트 지침인 <code>CLAUDE.md</code>로 자동 빌드됩니다. 완성된 지침은 Memory 탭에 적재되어 에이전트의 작동 규칙으로 동작합니다.</div>
</div>
</div>
<h2>3. 실전 사용자 가이드 & 활용 사례</h2>
<div class="callout info">
<div class="callout-icon">💡</div>
<div class="callout-content">
<h5 class="callout-title">사례 1: 새로운 프로젝트에서 설계 구조 파악</h5>
<p class="callout-text">
<strong>활용법:</strong> 에디터 패널의 <code>LLMWiki</code> 탭을 열어 <code>wiki/api-spec.md</code>에 API 설계를 적은 뒤 <code>CLAUDE.md 갱신</code>을 누릅니다. <br>
<strong>효과:</strong> 지식 그래프의 물리적 코드 심볼들이 사용자가 쓴 API 명세서에 동적으로 바인딩되어, 에이전트가 단 1초 만에 프로젝트 구조를 파악하고 올바른 설계의 코드를 작성하게 됩니다.
</p>
</div>
</div>
<div class="callout warning">
<div class="callout-icon">👤</div>
<div class="callout-content">
<h5 class="callout-title">사례 2: 다중 프로젝트 간 개발 지식(경험) 이식</h5>
<p class="callout-text">
<strong>활용법:</strong> 프로젝트 A에서 특정 빌드 예외를 극복했다면 <code>Note</code> 탭을 열어 <code>Note / Knot</code> 지식 보관함에 공통 해결법을 정리해 둡니다.<br>
<strong>효과:</strong> 완전히 다른 프로젝트 B를 새로 구동했을 때, 에이전트가 글로벌 Note의 해결 템플릿을 자동으로 쿼리(RAG)해와 동일한 에러 발생 시 똑같은 삽질 없이 즉각 수정안을 반영합니다.
</p>
</div>
</div>
</section>
<!-- Section: Knowledge Headroom Integration -->
<section id="knowledge-headroom-integration" class="doc-section">
<div class="section-header">
<span class="section-badge">지식 & 보안 통합</span>
<h1>지식 RAG & Headroom 프록시 연계</h1>
<p class="section-desc">바다 터미널의 지능형 지식 탐색(RAG)과 실시간 보안 마스킹(Headroom) 프록시가 이중으로 협력하여 토큰을 절감하고 보안 유출을 방지하는 원리를 설명합니다.</p>
</div>
<h2>지식 RAG & Headroom 이중 필터 메커니즘</h2>
<p>BADA Suite는 에이전트의 상황 인지(Context) 주입 시 발생하는 두 가지 중대한 비용 및 보안 문제를 <strong>물리적 RAG 필터</strong><strong>논리적 API 프록시 마스킹</strong>의 이중 파이프라인으로 해결합니다.</p>
<!-- Dynamic SVG Flow Diagram -->
<div class="diagram-container">
<svg class="diagram-svg" viewBox="0 0 800 240" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad-mauve-blue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#cba6f7" />
<stop offset="100%" stop-color="#89b4fa" />
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1.5 L 8 5 L 0 8.5 z" fill="#a6adc8" />
</marker>
</defs>
<!-- Step 1: Raw Knowledge -->
<g class="node" style="--translate: translate(20px, 30px);">
<rect width="180" height="170" rx="10" fill="#181825" stroke="#313244" stroke-width="2" />
<text x="90" y="30" font-family="'Outfit', sans-serif" font-size="14" fill="#cdd6f4" font-weight="700" text-anchor="middle">로컬 지식 소스</text>
<text x="90" y="65" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">코드베이스 (100+ 파일)</text>
<text x="90" y="85" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">옵시디언 노트 (Knot)</text>
<text x="90" y="105" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">프로젝트 LLMWiki</text>
<text x="90" y="135" font-family="'Outfit', sans-serif" font-size="12" fill="#f38ba8" font-weight="600" text-anchor="middle">⚠️ 대용량 토큰 부하</text>
<text x="90" y="152" font-family="'Outfit', sans-serif" font-size="11" fill="#f38ba8" font-weight="600" text-anchor="middle">⚠️ 보안 노출 위험</text>
</g>
<!-- Flow Line 1 -->
<line x1="200" y1="115" x2="245" y2="115" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow)" class="flow-line" />
<!-- Step 2: 1차 RAG 필터 (Relevance Engine) -->
<g class="node" style="--translate: translate(255px, 30px);">
<rect width="240" height="170" rx="10" fill="#181825" stroke="#cba6f7" stroke-width="2" />
<text x="120" y="30" font-family="'Outfit', sans-serif" font-size="14" fill="#cba6f7" font-weight="700" text-anchor="middle">1차 RAG 물리적 압축</text>
<text x="120" y="60" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" font-weight="600" text-anchor="middle">4-Signal Relevance Engine</text>
<text x="120" y="85" font-family="'JetBrains Mono', monospace" font-size="9" fill="#f9e2af" text-anchor="middle">Score = Link*3 + Overlap*4 + AA*1.5 + Type*1</text>
<text x="120" y="110" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">SQLite nodes_fts 연계 FTS 검색</text>
<line x1="15" y1="125" x2="225" y2="125" stroke="#313244" stroke-width="1" stroke-dasharray="4" />
<text x="120" y="148" font-family="'Outfit', sans-serif" font-size="12" fill="#a6e3a1" font-weight="600" text-anchor="middle">상위 12개 노드로 요약</text>
<text x="120" y="163" font-family="'Outfit', sans-serif" font-size="11" fill="#a6e3a1" font-weight="600" text-anchor="middle">(토큰 사용량 80% 감축)</text>
</g>
<!-- Flow Line 2 -->
<line x1="495" y1="115" x2="535" y2="115" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow)" class="flow-line" />
<!-- Step 3: 2차 보안 프록시 (Headroom) -->
<g class="node" style="--translate: translate(545px, 30px);">
<rect width="235" height="170" rx="10" fill="#181825" stroke="#89b4fa" stroke-width="2" />
<text x="117.5" y="30" font-family="'Outfit', sans-serif" font-size="14" fill="#89b4fa" font-weight="700" text-anchor="middle">2차 Headroom 보안 마스킹</text>
<text x="117.5" y="60" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">API 전송 전 프록시 가로채기</text>
<text x="117.5" y="85" font-family="'Outfit', sans-serif" font-size="11" fill="#f38ba8" font-weight="600" text-anchor="middle">10대 기본 기밀 마스킹 패턴</text>
<text x="117.5" y="110" font-family="'JetBrains Mono', monospace" font-size="10" fill="#fab387" text-anchor="middle">pwd123 ➔ [SECRET_PASSWORD]</text>
<text x="117.5" y="125" font-family="'JetBrains Mono', monospace" font-size="10" fill="#fab387" text-anchor="middle">api_key ➔ [SECRET_API_KEY]</text>
<line x1="15" y1="138" x2="220" y2="138" stroke="#313244" stroke-width="1" stroke-dasharray="4" />
<text x="117.5" y="158" font-family="'Outfit', sans-serif" font-size="12" fill="#a6e3a1" font-weight="600" text-anchor="middle">안전한 외부 LLM 발송</text>
</g>
</svg>
</div>
<h2>핵심 작동 구성 요소</h2>
<h3>1) 4-Signal Relevance Engine에 의한 물리적 1차 압축</h3>
<p>에이전트가 코딩 중 참조할 파일이나 노트 맵이 백 개가 넘어가도, BADA의 <strong>Relevance Engine</strong>이 아래 공식에 의거하여 노드 간의 종합 가중치 점수를 실시간 계산합니다.</p>
<div style="background: var(--crust); padding: 12px 16px; border-radius: 8px; font-family: 'JetBrains Mono', monospace; font-size: 12px; margin: 12px 0; border-left: 3px solid var(--mauve); overflow-x: auto; color: var(--mauve);">
Relevance = (Direct Link * 3.0) + (Source Overlap * 4.0) + (Adamic-Adar * 1.5) + (Type Affinity * 1.0)
</div>
<h4>Relevance Signal 세부 명세</h4>
<ul class="doc-list">
<li><strong>Direct Link (직접 엣지 가중치)</strong>: SQLite <code>edges</code> 테이블에 명시된 두 노드 간의 실시간 참조 연결 가중치입니다.</li>
<li><strong>Source Overlap (공통 소스 지수)</strong>: 노드가 속한 패키지, 소스 파일의 공통 종속성 정도를 수치화한 값입니다.</li>
<li><strong>Adamic-Adar (그래프 구조 유사도)</strong>: 그래프 내에서 두 노드가 공유하는 이웃 노드들의 차수(Degree) 역수를 합산하여 간접 유사도를 파악하는 휴리스틱 공식입니다.</li>
<li><strong>Type Affinity (노드 유형 선호도)</strong>: 호출 대상(예: 클래스-메소드 간)에 매핑된 기본 적합도 상수 가중치입니다.</li>
</ul>
<h4>SQLite FTS (Full-Text Search) 및 <code>nodes_fts</code> 결합 검색</h4>
<p>BADA는 자연어 쿼리나 에러 로그가 유입되었을 때, 텍스트 형태의 검색을 빠르게 보조하기 위해 SQLite <strong>FTS5</strong> 내장 검색 라이브러리를 결합하여 <code>nodes_fts</code> 가상 테이블을 구성하고 실시간 가중치 점수를 합산해 12개 노드로 축소시킵니다.</p>
<h3>2) Headroom API 프록시에 의한 기밀 유출 방어 및 2차 정제</h3>
<p>물리적으로 선별된 프롬프트 데이터가 외부 클라우드 LLM(OpenAI/Gemini/Anthropic 등)으로 발송되는 요청 바이트를 실시간으로 프록시 서버에서 가로챕니다. 프롬프트 본문 내부의 주민등록번호, 비밀번호, 시스템 계정, 보안 토큰키 및 DB 접속 정보와 같은 10대 기본 기밀 데이터를 안전한 대치 토큰(<code>[SECRET_...]</code>)으로 자동 마스킹 처리하여 기밀의 외부 유출을 원천 예방하고, 전송 데이터 중복을 없애 한 번 더 요금 절감을 이뤄냅니다.</p>
<h3>BADA Headroom 10대 기본 기밀 마스킹 규칙 정의</h3>
<table class="schema-table">
<thead>
<tr>
<th>순번</th>
<th>보안 항목 종류</th>
<th>정규식 매칭 패턴 예시</th>
<th>마스킹 치환 토큰명</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>주민등록번호 (RRN)</td>
<td><code>\d{6}-[1-4]\d{6}</code></td>
<td><code>[SECRET_RRN]</code></td>
</tr>
<tr>
<td>2</td>
<td>API 인증 토큰 (Bearer, API Key)</td>
<td><code>(?i)(api[-_]?key|auth|token)\s*[:=]\s*["']?[a-zA-Z0-9_\-]{16,}["']?</code></td>
<td><code>[SECRET_API_KEY]</code></td>
</tr>
<tr>
<td>3</td>
<td>데이터베이스 접속 비밀번호</td>
<td><code>postgres:\/\/[^:]+:([^@]+)@</code></td>
<td><code>[SECRET_DB_PASSWORD]</code></td>
</tr>
<tr>
<td>4</td>
<td>AWS Credentials</td>
<td><code>(?i)(aws_access_key_id|aws_secret_access_key)\s*[:=]\s*["']?[a-zA-Z0-9/+=]{16,}["']?</code></td>
<td><code>[SECRET_AWS_CREDENTIALS]</code></td>
</tr>
<tr>
<td>5</td>
<td>Private SSH Key</td>
<td><code>-----BEGIN [A-Z]+ PRIVATE KEY-----</code></td>
<td><code>[SECRET_SSH_KEY]</code></td>
</tr>
<tr>
<td>6</td>
<td>공인 IP 주소 (Public IP)</td>
<td><code>\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b</code> (사설 IP 대역 제외 필터링)</td>
<td><code>[SECRET_IP_ADDRESS]</code></td>
</tr>
<tr>
<td>7</td>
<td>이메일 주소 (Email)</td>
<td><code>[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}</code></td>
<td><code>[SECRET_EMAIL]</code></td>
</tr>
<tr>
<td>8</td>
<td>신용카드 번호 (Credit Card)</td>
<td><code>\b(?:\d{4}[-\s]?){3}\d{4}\b</code></td>
<td><code>[SECRET_CREDIT_CARD]</code></td>
</tr>
<tr>
<td>9</td>
<td>전화번호 (Phone Number)</td>
<td><code>010-\d{3,4}-\d{4}</code></td>
<td><code>[SECRET_PHONE_NUMBER]</code></td>
</tr>
<tr>
<td>10</td>
<td>시스템 환경변수 내의 기밀값</td>
<td><code>(?i)(password|passwd|secret|credential)\s*=\s*\S+</code></td>
<td><code>[SECRET_SYSTEM_CREDENTIAL]</code></td>
</tr>
</tbody>
</table>
<h2>관련 설정 및 사용 방법</h2>
<h3>⚙️ 설정 구성 (Headroom & RAG 연동)</h3>
<ol style="margin-left: 20px; line-height: 1.6; margin-bottom: 16px;">
<li><strong>보안 및 마스킹 제어</strong>: 상단 메뉴바의 <strong>[Headroom 셋업]</strong> 메뉴를 선택하여 10대 기본 기밀 항목들의 개별 활성/비활성 여부를 지정하고, 기업 고유의 도메인 단어들을 위한 정규식을 수동 추가합니다.</li>
<li><strong>사내 내부망 LLM 우회(Bypass) 셋업</strong>: 만약 사내 내부에 배포된 Local Llama나 DeepSeek API를 사용하는 경우, 마스킹으로 인한 코드 품질 저하를 예방하기 위해 [Headroom 셋업] 내 프로바이더 목록에서 해당 Ollama/vLLM 프로바이더의 <strong>'Bypass Masking'</strong>을 활성화합니다.</li>
<li><strong>RAG 참조 방식 변경</strong>: [환경설정] ➔ 지식 설정에서 RAG 컨텍스트 주입 방식을 <code>contents</code>(본문 주입) 혹은 <code>path</code>(경로만 주입)로 토큰 용량에 맞춰 조율합니다.</li>
</ol>
<h3>💡 실전 활용 시나리오</h3>
<div class="callout warning" style="margin-top: 16px;">
<div class="callout-icon">👤</div>
<div class="callout-content">
<h5 class="callout-title">사례 1: 외부 LLM 사용 시 로컬 위키 내 DB 접속 정보 자동 유출 방어</h5>
<p class="callout-text">
<strong>조건:</strong> 로컬 위키의 <code>wiki/database.md</code> 파일에 내부 테스트용 DB 주소(<code>postgres://admin:pwd123@192.168.1.10/dev_db</code>)가 적혀 있으며, 외부 Anthropic Claude를 사용해 개발 중입니다.<br>
<strong>작동:</strong> 에이전트가 DB 아키텍처 조회를 위해 이 마크다운 위키를 참고하려 할 때, RAG Compiler에 의해 추출된 문서 본문이 API 전송 직전 Headroom 프록시를 관통합니다. 외부 전송 프롬프트에서는 접속 정보가 <code>postgres://[SECRET_ID]:[SECRET_PASSWORD]@192.168.1.10/dev_db</code> 형식으로 실시간 마스킹 치환됩니다. 외부 LLM에 원본 비밀정보는 단 1글자도 노출되지 않는 상태로 안전하게 코딩 어시스턴스를 보장받습니다.
</p>
</div>
</div>
<div class="callout info" style="margin-top: 16px;">
<div class="callout-icon">💡</div>
<div class="callout-content">
<h5 class="callout-title">사례 2: 사내 내부 LLM 활용 시 무마스킹 정밀 추론</h5>
<p class="callout-text">
<strong>조건:</strong> 보안 격리가 완전하게 구현된 사내 vLLM 서버(Local DeepSeek-Coder)에 연결하여 BADA Terminal을 구동 중입니다.<br>
<strong>작동:</strong> 해당 프로바이더의 Bypass 옵션을 활성화해 둡니다. 위키 마크다운에 기재된 사내 전용 도메인 파라미터나 변수가 마스킹 변환 없이 100% 원문 그대로 내부 LLM에 직결 주입됩니다. 에이전트는 기밀 훼손으로 인한 맥락 누락 현상 없이 완벽한 자가 추론 코드를 리포지토리에 적용합니다.
</p>
</div>
</div>
</section>
<!-- Section: Knowledge Diet & Optimization -->
<section id="knowledge-diet" class="doc-section">
<div class="section-header">
<div class="section-title">🧠 지식 관리 및 토큰 절감 가이드</div>
<div class="section-subtitle">BADA Terminal에서 작업 일관성을 유지하면서 API 요금(토큰) 소비를 최소화하는 권장 기법</div>
</div>
<div class="doc-card">
<div class="doc-card-title">1. 규칙 다이어트 (.clauderules)</div>
<p style="margin-bottom: 12px; line-height: 1.6;">프로젝트 루트의 <code>.clauderules</code> 파일에 너무 크고 방대한 지식이나 개발 규칙 전체를 작성하지 마십시오. 프롬프트가 과대화되어 매 대화마다 엄청난 토큰 비용이 낭비됩니다.</p>
<div class="callout callout-info" style="margin-top: 10px;">
<div class="callout-title">💡 권장 구조</div>
<p style="font-size: 13px; line-height: 1.6;">규칙 파일에는 <strong>핵심 가이드 요약본</strong><strong>상세 위키 링크([[wiki/Home]])</strong>만 남기십시오. 에이전트가 필요할 때만 마크다운 파일을 선택적으로 조회(Selective Read)하게 만듦으로써 컨텍스트 부하를 획기적으로 낮출 수 있습니다.</p>
</div>
</div>
<div class="doc-card">
<div class="doc-card-title">2. 위키(Wiki) 및 Obsidian 노트 연동</div>
<p style="margin-bottom: 12px; line-height: 1.6;">프로젝트 상세 설계 문서나 디버깅 트러블슈팅 이력은 마크다운 파일로 나누어 관리하십시오.</p>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>지식 위키 폴더 지정</strong>: <strong>[설정]</strong> 패널에서 위키 디렉토리를 지정하면 에이전트가 해당 마크다운 문서들을 RAG 컴파일 대상으로 자동 로드합니다.</li>
<li><strong>사이드 에디터 패널 (F12)</strong>: 사이드 패널의 파일 인스펙터를 켜면 필요한 마크다운 문서를 수동으로 직접 열어 수정하거나 실시간 편집할 수 있습니다.</li>
</ul>
</div>
<div class="doc-card">
<div class="doc-card-title">3. 지식 그래프 시각화 활용</div>
<p style="margin-bottom: 12px; line-height: 1.6;">지식 관리 시각화 도구(단축키: <code>Ctrl + G</code>)를 켜서 BADA 데이터베이스의 실시간 온톨로지 상태를 점검하십시오.</p>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>세션과 소스 파일 간 연관성</strong>: 어떤 대화 세션들이 어떤 소스 파일들을 편집하고 빌드했는지 동시 수정(co-modified) 관계선으로 표현됩니다.</li>
<li><strong>수정 범위 예측</strong>: 관계선 그래프의 밀집 허브(Hub) 노드를 참고하여 코드 변경 시 파급될 수 있는 영향 범위를 사전에 시각적으로 예측하고 대처할 수 있습니다.</li>
</ul>
</div>
</section>
<!-- Section: BADA SFTP Sandbox & Security -->
<section id="menus-sftp-security" class="doc-section">
<div class="section-header">
<span class="section-badge">Security & Access Control</span>
<h1>🔒 SFTP 샌드박스 & 보안 설정</h1>
<p class="section-desc">원격 BADA 커넥터와 터미널 간 파일 전송 시 탐색 가능한 디렉토리 한도를 제한하고 접속 IP 필터를 가동합니다.</p>
</div>
<h2>Allowed Folders (샌드박스 폴더 허용 목록)</h2>
<p>원격 BADA 커넥터는 SFTP 파일 서버 역할을 겸하며, 허용 목록(Allowed Folders)에 등록되지 않은 임의의 디렉토리나 시스템 루트(`/`, `C:\` 등)로의 파일 탐색, 읽기, 쓰기 접근은 SFTP 프로토콜 레이어에서 원천적으로 차단 및 거부됩니다.</p>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>절대 경로 등록</strong>: 공유를 허용하고자 하는 디렉토리의 절대 경로(예: `/Users/jkb/Projects` 또는 `C:\workspace`)를 직접 입력하여 추가합니다.</li>
<li><strong>보안 영역 구축</strong>: 에이전트 CLI(예: Claude)가 접근해야 하는 최상위 프로젝트 작업 폴더만 등록하여, 중요 시스템 설정 파일이 탈취되거나 파괴되는 것을 근본적으로 차단합니다.</li>
</ul>
<h2>IP 필터링 (화이트리스트 & 블랙리스트)</h2>
<p>커넥터 데몬으로 원격 접속할 수 있는 클라이언트의 IP 주소를 강력하게 제어합니다.</p>
<ul class="doc-list" style="margin-left: 20px; line-height: 1.8; margin-top: 10px;">
<li><strong>화이트리스트 (허용 대역)</strong>: 인증 키나 올바른 접속 요청이라 하더라도, 지정된 IP(예: `192.168.35.175`)에서 온 접속에만 연결을 수락하고 나머지는 드롭시킵니다. 만료 시간(Expire At)을 설정하여 한시적 원격 파트너십을 허가할 때 유용합니다.</li>
<li><strong>블랙리스트 (차단 대역)</strong>: 비정상 접속 시도나 공격이 포착된 IP 주소를 영구적 혹은 기간제로 즉시 차단합니다.</li>
</ul>
<h2>보안 실시간 감사 (Audit Logs)</h2>
<p>샌드박스 폴더 내부의 모든 파일 변경 사항(생성, 수정, 삭제) 및 SFTP 세션 개시 정보, 비정상 IP 접속 시도 및 차단 내역을 실시간 감사 로그 뷰어를 통해 로깅 및 모니터링하여, 침해 위협 발생 시 즉각 대응할 수 있도록 지원합니다.</p>
</section>
<!-- Section: Loops Engineering Guide -->
<section id="loops-engineering-guide" class="doc-section">
<div class="section-header">
<span class="section-badge">Core Concept</span>
<h1>Closed-Loop 루프 엔지니어링 가이드</h1>
<p class="section-desc">에이전트가 검증을 통과할 때까지 스스로 피드백을 수용하며 자가 수정하는 완결형 자동화 아키텍처입니다.</p>
</div>
<h2>루프 엔지니어링이란?</h2>
<p>BADA Terminal의 핵심 철학은 <strong>"에이전트에게 일을 맡긴 후 방치하지 않고, 검증(Verify)을 통과할 때까지 피드백 루프를 폐쇄형(Closed-Loop)으로 반복한다"</strong>는 것입니다. 이 방식은 에이전트의 초기 실수율을 획기적으로 낮추고 최종 작업 결과물의 완성도를 극대화합니다.</p>
<p>BADA의 루프 제어 엔진(Loop Controller)은 <strong>목표 수립(Goal) ➔ 격리 실행(Execute) ➔ 검증 평가(Verify) ➔ 회류 학습(Feedback)</strong>의 4단계 라이프사이클을 반복하며 목표를 자가 달성합니다.</p>
<!-- Closed-Loop Lifecycle SVG Diagram -->
<div class="diagram-container">
<svg class="diagram-svg" viewBox="0 0 600 320" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrow-gray" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1.5 L 8 5 L 0 8.5 z" fill="#a6adc8" />
</marker>
</defs>
<!-- Step 1: Goal -->
<g class="node" style="--translate: translate(40px, 25px);">
<rect width="200" height="90" rx="8" fill="#181825" stroke="#cba6f7" stroke-width="2" />
<text x="100" y="32" font-family="'Outfit', sans-serif" font-size="13" fill="#cba6f7" font-weight="700" text-anchor="middle">1. 목표 수립 (Goal)</text>
<text x="100" y="55" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">Goal Expression JSON 지정</text>
<text x="100" y="73" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">Max Budget &amp; Iteration 한도</text>
</g>
<!-- Connector 1 -> 2 -->
<path d="M 240 70 L 350 70" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" />
<!-- Step 2: Execute -->
<g class="node" style="--translate: translate(360px, 25px);">
<rect width="200" height="90" rx="8" fill="#181825" stroke="#89b4fa" stroke-width="2" />
<text x="100" y="32" font-family="'Outfit', sans-serif" font-size="13" fill="#89b4fa" font-weight="700" text-anchor="middle">2. 격리 실행 (Execute)</text>
<text x="100" y="55" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">Git Worktree 자동 분기 생성</text>
<text x="100" y="73" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">PTY 에이전트 코드 수정 수행</text>
</g>
<!-- Connector 2 -> 3 -->
<path d="M 460 115 L 460 185" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" />
<!-- Step 3: Verify -->
<g class="node" style="--translate: translate(360px, 195px);">
<rect width="200" height="90" rx="8" fill="#181825" stroke="#a6e3a1" stroke-width="2" />
<text x="100" y="32" font-family="'Outfit', sans-serif" font-size="13" fill="#a6e3a1" font-weight="700" text-anchor="middle">3. 검증 평가 (Verify)</text>
<text x="100" y="55" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">Harness 검증 명령어 호출</text>
<text x="100" y="73" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">exitCode 0 판정 ➔ 통과/반려</text>
</g>
<!-- Connector 3 -> 4 -->
<path d="M 360 240 L 250 240" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" />
<!-- Step 4: Feedback -->
<g class="node" style="--translate: translate(40px, 195px);">
<rect width="200" height="90" rx="8" fill="#181825" stroke="#f38ba8" stroke-width="2" />
<text x="100" y="32" font-family="'Outfit', sans-serif" font-size="13" fill="#f38ba8" font-weight="700" text-anchor="middle">4. 회류 학습 (Feedback)</text>
<text x="100" y="55" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">AI 오토 트리아지 원인 분석</text>
<text x="100" y="73" font-family="'Outfit', sans-serif" font-size="11" fill="#a6adc8" text-anchor="middle">Git Diff + 피드백 재주입</text>
</g>
<!-- Connector 4 -> 1 -->
<path d="M 140 195 L 140 125" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" />
<!-- Circular Arrows Labels -->
<text x="295" y="60" font-family="'Outfit', sans-serif" font-size="10" fill="#a6adc8" text-anchor="middle">구동 지시</text>
<text x="495" y="155" font-family="'Outfit', sans-serif" font-size="10" fill="#a6adc8" text-anchor="middle">검사 시작</text>
<text x="295" y="230" font-family="'Outfit', sans-serif" font-size="10" fill="#a6adc8" text-anchor="middle">실패/반려</text>
<text x="95" y="155" font-family="'Outfit', sans-serif" font-size="10" fill="#a6adc8" text-anchor="middle">피드백 주입</text>
</svg>
</div>
<div class="card-grid" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin: 24px 0;">
<div class="info-card" style="background: var(--mantle); border: 1px solid var(--border); padding: 20px; border-radius: 12px;">
<div style="font-size: 24px; margin-bottom: 8px;">🎯</div>
<h3 style="color: var(--mauve); font-size: 16px; margin-bottom: 8px;">자가 교정 (Self-Correction)</h3>
<p style="font-size: 13px; color: var(--subtext); line-height: 1.5;">검증 실패 시 발생한 에러 로그와 소스 Diff를 수집하여 다음 이터레이션의 프롬프트에 자동으로 누적 주입, 점진적 개선을 유도합니다.</p>
</div>
<div class="info-card" style="background: var(--mantle); border: 1px solid var(--border); padding: 20px; border-radius: 12px;">
<div style="font-size: 24px; margin-bottom: 8px;">🛡️</div>
<h3 style="color: var(--blue); font-size: 16px; margin-bottom: 8px;">예산 및 자원 가드레일</h3>
<p style="font-size: 13px; color: var(--subtext); line-height: 1.5;">최대 반복 이터레이션 수(Max Iterations)와 토큰 비용 요금제 한도(Max Budget)를 두어 에이전트가 무한 루프에 빠지거나 비용이 폭주하는 것을 차단합니다.</p>
</div>
</div>
<h2>Closed-Loop 4단계 실행 흐름</h2>
<div class="tab-container" style="margin-top: 20px;">
<div class="tab-headers">
<div class="tab-header active" data-tab="flow-1">1단계: 목표 설정 (Goal)</div>
<div class="tab-header" data-tab="flow-2">2단계: 실행 격리 (Execute)</div>
<div class="tab-header" data-tab="flow-3">3단계: 검증 평가 (Verify)</div>
<div class="tab-header" data-tab="flow-4">4단계: 회류 학습 (Feedback)</div>
</div>
<div class="tab-content active" id="flow-1">
<p><strong>배치 스케줄러</strong> 또는 <strong>루프 빌더</strong>를 통해 에이전트가 최종 달성해야 할 성공 목표를 지정합니다.</p>
<ul class="doc-list" style="margin-top: 10px; padding-left: 20px;">
<li><strong>테스트 코드 통과 (Test Suite)</strong>: 지정한 테스트 사양(예: <code>npm test</code>)이 종료 코드 <code>0</code>으로 완수될 때까지 반복합니다.</li>
<li><strong>파일 검증 (File Output)</strong>: 결과 파일이 생성되었는지, 내용이 특정 포맷이나 정규식(Regex) 기준에 일치하는지 검사합니다.</li>
<li><strong>수치 지표 (Metric/Threshold)</strong>: 수집된 성능 지표값(예: <code>accuracy >= 0.95</code>)이 목표 기준을 상회할 때까지 최적화합니다.</li>
</ul>
</div>
<div class="tab-content" id="flow-2">
<p>지정된 에이전트가 활성화되어 소스 코드를 생성하거나 리팩토링합니다. 이때 개발 디렉토리 오염을 막기 위해 <strong>Git Worktree 격리 모드</strong>로 백그라운드 임시 분기에서 병렬 구동을 실행할 수 있습니다.</p>
</div>
<div class="tab-content" id="flow-3">
<p>에이전트 수정이 완료되면 루프 컨트롤러는 지정된 <strong>하네스 검증 조건</strong>을 구동하여 합격 여부를 판정합니다. 성공했다면 즉시 메인 브랜치에 코드를 머지하고 루프를 최종 승인 종료합니다.</p>
</div>
<div class="tab-content" id="flow-4">
<p>검증에 실패할 경우, 실패 사유와 컴파일 에러 메시지, Git Diff 데이터가 자동으로 에이전트의 기억(Context)에 복합 주입됩니다. 에이전트는 이 피드백을 기반으로 자가 수정을 수행하며 다음 이터레이션을 개시합니다.</p>
</div>
</div>
<h2>목표 설정 목표식(Goal Expression) 명세</h2>
<p>BADA가 루프 성공/실패 여부를 판별하기 위해 해석하는 <code>goal_expression</code> JSON 속성 정의 구조입니다.</p>
<pre><code>{
"type": "test_command", // 검증 타겟 유형: test_command | file_check | metric_limit
"command": "npm run test:auth", // 실행할 하네스 명령어
"success_criteria": {
"exit_code": 0, // 성공 종료 코드
"regex_match": "Passed:" // 로그에서 매칭되어야 할 필수 정규식 (선택)
}
}</code></pre>
<h2>BADA Closed-Loop 안전 가드레일 제약 한도</h2>
<p>루프 엔진이 무한 지출 및 프로세스 고아 방지를 위해 강제 준수하는 가드레일 제한 규칙입니다.</p>
<table class="schema-table">
<thead>
<tr>
<th>제한 변수명</th>
<th>기본 설정 한계값</th>
<th>가드레일 초과 시 강제 조치 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Max Iterations</code></td>
<td>5회 (최대 10회 조정 가능)</td>
<td>루프 강제 차단, 최종 상태 <code>circuit_broken</code>으로 강제 기록 및 OS 알림 발송</td>
</tr>
<tr>
<td><code>Max Token Budget</code></td>
<td>$2.00 USD (최대 $5.00)</td>
<td>비용 상향 한도 도달 시 PTY 프로세스 강제 종료 및 알림 발송</td>
</tr>
<tr>
<td><code>Max Wall Time</code></td>
<td>3600초 (1시간)</td>
<td>경과 시간 초과 시 모든 가상 머신 및 백그라운드 PTY 프로세스를 SIGKILL하고 트레기 정리</td>
</tr>
<tr>
<td><code>Consecutive Failures</code></td>
<td>3회 연속 에러</td>
<td>동일 에러가 3번 반복되어 개선 diff가 발견되지 않을 시 루프 차단(Triage Inbox 인계)</td>
</tr>
</tbody>
</table>
<h2>루프 관련 스키마 정보 (SQLite DB)</h2>
<p>루프의 정의와 단계별 성공 및 토큰 소모 이력은 다음 테이블에 완전히 저장됩니다.</p>
<h3>1) <code>loop_goals</code> 테이블 (루프 목표 등록)</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 루프 목표 고유 ID</td>
</tr>
<tr>
<td><code>name</code></td>
<td>TEXT</td>
<td>목표 이름 (예: API 예외 버그 픽스 루프)</td>
</tr>
<tr>
<td><code>goal_expression</code></td>
<td>TEXT</td>
<td>성공 판정 기준 규칙이 기재된 JSON 스트링</td>
</tr>
<tr>
<td><code>max_iterations</code></td>
<td>INTEGER</td>
<td>최대 허용 순환 횟수 (가드레일)</td>
</tr>
<tr>
<td><code>token_budget</code></td>
<td>REAL</td>
<td>허용 금액 한계 (USD 단위)</td>
</tr>
<tr>
<td><code>worktree_isolation</code></td>
<td>INTEGER</td>
<td>Git Worktree 격리 격하 여부 (0: 비활성, 1: 활성)</td>
</tr>
</tbody>
</table>
<h3>2) <code>loop_runs</code><code>loop_iterations</code> 테이블 (순환 상태)</h3>
<table class="schema-table">
<thead>
<tr>
<th>테이블 및 컬럼명</th>
<th>데이터 타입</th>
<th>의미 및 수집 내용</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>loop_runs.status</code></td>
<td>TEXT</td>
<td>루프 진행 상태 (<code>running | completed | failed | circuit_broken</code>)</td>
</tr>
<tr>
<td><code>loop_runs.total_cost</code></td>
<td>REAL</td>
<td>누적 소모된 토큰 비용 (USD)</td>
</tr>
<tr>
<td><code>loop_iterations.iteration_number</code></td>
<td>INTEGER</td>
<td>현재 몇 번째 피드백 순환을 밟고 있는지 식별자 (1부터 시작)</td>
</tr>
<tr>
<td><code>loop_iterations.step_outputs</code></td>
<td>TEXT</td>
<td>각 순환 시 에이전트가 제출한 diff와 하네스 원시 로그 JSON 스냅샷</td>
</tr>
</tbody>
</table>
<h2>루프 엔지니어링 4대 고급 기능 (Phase 3 & 4)</h2>
<p>BADA v3.12.0부터는 에이전트의 안정성과 다차원 검증을 위한 핵심 고급 가드레일들이 추가되었습니다.</p>
<div class="grid-container">
<div class="feature-card">
<div class="card-icon"></div>
<div class="card-title">1. Git Worktree 격리 및 스쿼시 머지</div>
<div class="card-text">
루프 이터레이션 구동 시 메인 코드베이스가 훼손되지 않도록 <code>bada-wt-[runId]-[nodeId]</code> 형태의 임시 워크트리 브랜치를 생성해 완전히 독립 실행합니다. 검증 성공 시에만 <strong>Squash Merge</strong>되어 메인 브랜치에 안전하게 귀속되며, 실패 시에는 흔적 없이 <strong>Discard/Prune</strong> 처리됩니다.
</div>
<span class="card-badge badge-primary">Worktree Isolation</span>
</div>
<div class="feature-card">
<div class="card-icon">🗳️</div>
<div class="card-title">2. 다중 Reviewer 합의 패턴 (Consensus)</div>
<div class="card-text">
중요 코드 리팩토링이나 보안성 검토 시 단일 체커의 판단을 신뢰할 수 없는 경우, 병렬 노드(Parallel Node) 하위에 다중 검토 에이전트를 배치하고 투표 합의 메커니즘을 지정할 수 있습니다. <br>
<code>consensus: "majority" (과반수) | "all" (전원 합격) | "any" (최소 1명 합격)</code> 의 룰을 따릅니다.
</div>
<span class="card-badge badge-secondary">Consensus Engine</span>
</div>
<div class="feature-card">
<div class="card-icon">🔔</div>
<div class="card-title">3. 네이티브 데스크톱 알림 (OS Push)</div>
<div class="card-text">
백그라운드에서 장시간 구동되는 루프의 진행 상황을 모니터링하지 않아도 됩니다. <strong>목표 달성 완료(Success)</strong>, <strong>회로차단기 작동(Fail)</strong>, <strong>예산 80% 경고(Warning)</strong>, <strong>사람의 개입 대기(HITL)</strong> 등 중요 시점마다 OS 네이티브 트레이 푸시 알림을 즉각 발송합니다.
</div>
<span class="card-badge badge-tertiary">Native Tray Notifier</span>
</div>
<div class="feature-card">
<div class="card-icon"></div>
<div class="card-title">4. AI Loop Wizard 프리셋 추천</div>
<div class="card-text">
"3달러 내에서 빠르게 npm test 패스해줘" 와 같은 자연어 목표 요약을 입력 창에 작성하는 것만으로, AI 프리셋 분석기가 단어들을 감지하여 <strong>가드레일 제한 설정</strong>(이터레이션 횟수, 비용 한도, 최대 대기 시간) 및 <strong>격리 모드 유무</strong>를 자동으로 매핑해 적용해 줍니다.
</div>
<span class="card-badge badge-quaternary">AI Wizard Presets</span>
</div>
</div>
<h2 style="margin-top: 32px;">상세 사용법 가이드 (Step-by-Step)</h2>
<div style="margin-top: 16px;">
<h3 style="color: var(--mauve); font-size: 15px; margin-bottom: 6px;">1. Closed-Loop 배치 작업 생성 및 설정</h3>
<p style="font-size: 14px; line-height: 1.6; color: var(--subtext);">
도구 메뉴 ➜ <strong>[스케줄/배치 작업 관리]</strong>를 열고 우측 상단의 <strong>[루프 모드 (Closed-Loop Mode)]</strong> 토글 스위치를 활성화합니다.<br>
그 다음, 검증하고자 하는 목표 검증 유형(Goal Type)을 지정하고, 타겟(명령어 혹은 파일 경로), 한계값 기준을 작성합니다. 최대 반복 횟수(기본 5회) 및 최대 예산 한계(기본 $2.00)와 샌드박스 격리 모드(Git Worktree 등)를 구성합니다.
</p>
</div>
<div style="margin-top: 20px;">
<h3 style="color: var(--mauve); font-size: 15px; margin-bottom: 6px;">2. 구동 테스트 및 모니터링</h3>
<p style="font-size: 14px; line-height: 1.6; color: var(--subtext);">
작성 완료 후 하단의 <strong>[구동 테스트]</strong> 또는 <strong>[즉시 실행]</strong> 버튼을 누르면 루프가 시작됩니다.<br>
모니터링 메뉴 ➜ <strong>[Closed-Loop 실시간 대시보드]</strong>를 실행하면, 현재 진행 중인 이터레이션(Iteration) 단계, 누적 사용 토큰과 발생 요금 게이지, 그리고 에이전트가 백그라운드 PTY 터미널에 남기는 원시 실행 로그 스트림을 실시간 시각화된 차트와 타임라인을 통해 감시할 수 있습니다.
</p>
</div>
<div style="margin-top: 20px;">
<h3 style="color: var(--mauve); font-size: 15px; margin-bottom: 6px;">3. 이력 관리 및 학습 효과 분석</h3>
<p style="font-size: 14px; line-height: 1.6; color: var(--subtext);">
도구 메뉴 ➜ <strong>[Closed-Loop 실행 이력]</strong>을 켜면 과거에 실행되었던 배치 루프의 상세 보고서를 탐색할 수 있습니다.<br>
좌측 실행 건수를 선택하면 우측 탭을 통해 <strong>[이터레이션별 소스 Diff 비교]</strong>, 에이전트가 이터레이션 간에 획득한 <strong>[교훈 요약 (Retrospective Logs)]</strong>, 단계별 토큰 소모 분석 그래프를 볼 수 있어 AI 최적화 지식 자산을 체계적으로 관리할 수 있습니다.
</p>
</div>
</section>
<!-- Section: Loops Worktree -->
<section id="loops-worktree" class="doc-section">
<div class="section-header">
<span class="section-badge">Core Loop Mechanics</span>
<h1>Git Worktree 격리 설계</h1>
<p class="section-desc">동시 에이전트 구동 시 메인 개발 트리의 오염을 막아주는 안전장치입니다.</p>
</div>
<h2>격리 작동 원리</h2>
<p>에이전트 노드가 활성화되면 BADA 워크플로우 매니저는 <code>isolation === 'worktree'</code> 설정을 검사합니다.</p>
<!-- Git Worktree Isolation SVG Diagram -->
<div class="diagram-container">
<svg class="diagram-svg" viewBox="0 0 650 260" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrow-green" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1.5 L 8 5 L 0 8.5 z" fill="#a6e3a1" />
</marker>
<marker id="arrow-red" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1.5 L 8 5 L 0 8.5 z" fill="#f38ba8" />
</marker>
</defs>
<!-- Main Repository Line -->
<line x1="40" y1="60" x2="610" y2="60" stroke="#45475a" stroke-width="4" />
<circle cx="80" cy="60" r="8" fill="#cba6f7" />
<text x="80" y="40" font-family="'Outfit', sans-serif" font-size="11" fill="#cba6f7" text-anchor="middle">Commit A</text>
<!-- Git Worktree Branch Out -->
<path d="M 80 60 Q 150 160 220 160" stroke="#89b4fa" stroke-width="2" stroke-dasharray="4" fill="none" />
<!-- Worktree Node (Isolated Directory) -->
<g class="node" style="--translate: translate(220px, 120px);">
<rect width="220" height="80" rx="6" fill="#181825" stroke="#89b4fa" stroke-width="2" />
<text x="110" y="25" font-family="'Outfit', sans-serif" font-size="12" fill="#89b4fa" font-weight="700" text-anchor="middle">격리 워크트리 디렉토리</text>
<text x="110" y="45" font-family="'JetBrains Mono', monospace" font-size="10" fill="#a6adc8" text-anchor="middle">wt-path: ../bada-temp/wt-[id]</text>
<text x="110" y="63" font-family="'Outfit', sans-serif" font-size="10" fill="#f9e2af" text-anchor="middle">에이전트 단독 파일 수정 &amp; 빌드</text>
</g>
<!-- Branch points inside worktree -->
<circle cx="220" cy="160" r="5" fill="#89b4fa" />
<circle cx="440" cy="160" r="5" fill="#89b4fa" />
<!-- Merge path (Success) -->
<path d="M 440 160 Q 510 60 580 60" stroke="#a6e3a1" stroke-width="2" marker-end="url(#arrow-green)" fill="none" />
<text x="500" y="110" font-family="'Outfit', sans-serif" font-size="11" fill="#a6e3a1" text-anchor="middle">성공 시 Squash Merge</text>
<circle cx="580" cy="60" r="8" fill="#a6e3a1" />
<text x="580" y="40" font-family="'Outfit', sans-serif" font-size="11" fill="#a6e3a1" text-anchor="middle">Commit B (Merged)</text>
<!-- Discard path (Failure) -->
<path d="M 440 160 L 510 220" stroke="#f38ba8" stroke-width="2" marker-end="url(#arrow-red)" fill="none" />
<text x="525" y="190" font-family="'Outfit', sans-serif" font-size="11" fill="#f38ba8" text-anchor="middle">실패 시 Prune &amp; Discard</text>
<g class="node" style="--translate: translate(515px, 215px);">
<rect width="90" height="30" rx="4" fill="#1e1e2e" stroke="#f38ba8" stroke-width="1" />
<text x="45" y="18" font-family="'Outfit', sans-serif" font-size="11" fill="#f38ba8" text-anchor="middle">흔적 삭제</text>
</g>
<text x="120" y="80" font-family="'Outfit', sans-serif" font-size="11" fill="#89b4fa" text-anchor="middle">Worktree 생성</text>
</svg>
</div>
<div class="tab-container">
<div class="tab-headers">
<div class="tab-header active" data-tab="wt-setup">1단계: Worktree 생성</div>
<div class="tab-header" data-tab="wt-exec">2단계: 격리 실행</div>
<div class="tab-header" data-tab="wt-cleanup">3단계: 검증 및 수거</div>
</div>
<div class="tab-content active" id="wt-setup">
<p>메인 프로젝트의 특정 커밋 혹은 브랜치를 기준으로 임시 격리 경로인 <code>../bada-temp/wt-[runId]-[agentId]</code><code>git worktree add</code>를 호출합니다.</p>
<pre><code>git worktree add --checkout -b temp-branch-name wt-path hash</code></pre>
</div>
<div class="tab-content" id="wt-exec">
<p>PTY 세션의 작업 디렉토리(cwd)를 임시 생성된 Worktree 경로로 치환하여 에이전트가 수정 작업을 수행하게 합니다. 사용자의 메인 파일에는 전혀 영향을 주지 않습니다.</p>
</div>
<div class="tab-content" id="wt-cleanup">
<p>작업 완료 성공 시 해당 코드를 커밋한 뒤 메인 브랜치에 병합(merge)을 시도하며, 성공/실패 여부에 무관하게 해당 임시 워크트리 및 임시 브랜치를 물리적으로 제거(Prune)합니다.</p>
<pre><code>git worktree remove --force wt-path
git branch -D temp-branch-name</code></pre>
</div>
</div>
<h2>Squash Merge 및 Discard/Prune 생명주기</h2>
<ul class="doc-list">
<li><strong>성공 ➔ Squash Merge</strong>: 에이전트가 격리된 공간에서 작성한 수십 번의 무수한 빌드 시도 커밋들을 하나의 깔끔한 기능 단위 커밋으로 압축(Squash)하여 메인 브랜치에 이식함으로써 메인 Git History의 안정성과 가시성을 확보합니다.</li>
<li><strong>실패 ➔ Discard/Prune</strong>: 가드레일 예산 차단 등으로 인해 결국 최종 검증에 실패한 경우, 생성되었던 워크트리 디렉토리를 <code>git worktree remove --force</code> 명령어로 디스크에서 제거하고 생성한 브랜치도 흔적 없이 제거하여 원래 개발 상태로 자동 롤백시킵니다.</li>
</ul>
<h2>격리 워크트리 상태 추적 스키마 (SQLite DB)</h2>
<p>BADA가 실시간으로 관리하는 워크트리의 마운트 상태와 디스크 수거 기록은 다음 SQLite 스키마에 완전히 동기화됩니다.</p>
<h3><code>worktree_state</code> 테이블 상세 정의</h3>
<table class="schema-table">
<thead>
<tr>
<th>컬럼명</th>
<th>데이터 타입</th>
<th>제약조건 및 설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>TEXT</td>
<td><code>PRIMARY KEY</code> - 워크트리 상태 ID</td>
</tr>
<tr>
<td><code>run_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 연결된 루프 실행 고유 runId</td>
</tr>
<tr>
<td><code>node_id</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - Cytoscape 워크플로우 내의 노드 식별자</td>
</tr>
<tr>
<td><code>wt_path</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 디스크 상의 임시 워크트리 물리 절대경로</td>
</tr>
<tr>
<td><code>branch_name</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 격리용 임시 Git 브랜치 이름</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td><code>NOT NULL</code> - 상태값 (<code>active | merged | discarded | orphaned</code>)</td>
</tr>
<tr>
<td><code>created_at</code></td>
<td>TEXT</td>
<td>워크트리 마운트 개시 시각</td>
</tr>
<tr>
<td><code>completed_at</code></td>
<td>TEXT</td>
<td>병합 또는 Discard되어 마운트 해제된 수거 완료 시각</td>
</tr>
</tbody>
</table>
</section>
<!-- Section: Loops Feedback -->
<section id="loops-feedback" class="doc-section">
<div class="section-header">
<span class="section-badge">Core Loop Mechanics</span>
<h1>Maker-Checker 피드백 루프</h1>
<p class="section-desc">반복 자가 참조를 통해 에이전트 스스로의 수정율을 극대화합니다.</p>
</div>
<h2>루프백 알고리즘 시각화</h2>
<pre style="background:var(--mantle); color:var(--text);">
[Maker Node] ──(코드작성)──> [Checker Node]
판정 (Approved?)
├──> [Yes] ──> (성공 완료)
└──> [No] ──(Diff + 피드백 주입)──> [Maker Node (재시도)]
</pre>
<h2>점진적 진화(Evolution) 콘텍스트 구조</h2>
<p>반려 피드백이 Maker 노드에 다시 주입될 때, 아래와 같은 JSON 구조로 축적되어 Maker 에이전트의 프롬프트 전면에 강제 바인딩되어 동작합니다.</p>
<pre><code>{
"runId": "wf_run_1781552634074_db9c8",
"retryCount": 2,
"lastFeedback": "index.js 24라인에서 null 예외 처리가 누락되어 빌드가 실패했습니다.",
"gitDiff": "--- index.js\n+++ index.js\n@@ -24,4 +24,2 @@\n- return user.name;\n+ return user ? user.name : 'Unknown';"
}</code></pre>
</section>
<!-- Section: Loops Sandbox -->
<section id="loops-sandbox" class="doc-section">
<div class="section-header">
<span class="section-badge">Batch & Transform Mechanics</span>
<h1>JavaScript VM Sandbox</h1>
<p class="section-desc">비 격리 데이터 변환 스크립트 실행으로 인한 호스트 머신의 위협과 무한 루프를 방지합니다.</p>
</div>
<h2>VM 격리 실행</h2>
<p>배치 스케줄러 워크플로우 진행 도중 JSON 파싱, 키 매핑, 데이터 형변환 등이 수행되는 <strong>JS 변환기 단계(Transform Step)</strong>를 실행할 때, Node.js 내장 <code>vm</code> 모듈을 사용하여 호스트 파일시스템(<code>fs</code>) 모듈 접근 등이 차단된 완전히 격리된 샌드박스 영역 내에서 보안 안전성을 담보하며 실행됩니다.</p>
<h2>세이프티 가드레일</h2>
<ul class="doc-list">
<li><strong>문법 IIFE 자동 포장</strong>: 사용자가 작성한 변환 코드가 비동기(Promise) 및 문법 오류 없이 구동되도록 내부적으로 즉시 실행 함수(IIFE) 블록(<code>(async function() { ... })()</code>)으로 자동 감싸 구동합니다.</li>
<li><strong>강제 실행 시간 타임아웃 (2000ms)</strong>: 스크립트 내에 무한 루프나 블로킹 연산이 포함되었을 경우, 2초가 경과되면 동기식 timeout 가드와 비동기 <code>Promise.race</code> 이중 가드가 개입하여 스레드 락을 해제하고 강제 종료합니다.</li>
</ul>
</section>
<!-- Section: Docker Sandbox v2 -->
<section id="docker-sandbox" class="doc-section">
<div class="section-header">
<span class="section-badge">Isolation & Security</span>
<h1>🐳 Docker 개발 샌드박스 v2</h1>
<p class="section-desc">LLM CLI 에이전트의 AI 추론 제어 비행(Plane)과 실제 파일 수정/코드 빌드를 격리된 도커 내로 3중 분할 격리합니다.</p>
</div>
<h2>격리 아키텍처 개요</h2>
<p>BADA Docker 샌드박스 커넥터 v2는 <strong>제어(Control), 실행(Execution), 자원(Resource)</strong>의 3중 격리 아키텍처를 제공합니다.</p>
<ul class="doc-list">
<li><strong>제어 Plane (BADA Terminal)</strong>: 사용자 인터페이스 표시, 터미널 입출력, 세션 상태 및 Docker API 제어를 담당합니다.</li>
<li><strong>실행 Plane (Host CLI)</strong>: 로컬 또는 원격 SSH Host 상에서 AI 에이전트 CLI(Claude Code, OpenCode 등)가 실행되어 추론 및 도구 사용 결정 수행합니다.</li>
<li><strong>자원 Plane (Docker Container)</strong>: 에이전트가 코드를 빌드하고 실행하며 파일을 수정하는 작업 환경을 컨테이너 내부 <code>/workspace</code>로 완전 격리하여 Host 환경의 훼손을 차단합니다.</li>
</ul>
<h2>사용 및 설정 방법</h2>
<ol class="doc-list" style="margin-left: 20px; margin-top: 10px;">
<li><strong>원격 서버 설정 등록</strong>: BADA Terminal 우측 상단 메뉴의 <code>🖥️ 원격 서버 관리</code>를 클릭하고 서버를 추가/편집합니다.</li>
<li><strong>Docker 옵션 활성화</strong>: <code>🐳 Docker 개발 샌드박스 활성화</code> 체크박스를 켭니다.
<ul style="margin-left: 20px; margin-top: 5px;">
<li><strong>Docker 호스트 주소</strong>: Docker가 실행 중인 서버 IP (생략 시 SSH 접속 호스트 사용).</li>
<li><strong>컨테이너 이미지</strong>: 사용할 개발용 샌드박스 이미지명 (기본: <code>bada-dev-sandbox:latest</code>).</li>
<li><strong>리소스 한도</strong>: 컨테이너의 최대 가용 CPU 코어 수 및 Memory 크기를 제한합니다.</li>
</ul>
</li>
<li><strong>Docker 이미지 빌드 (최초 1회)</strong>: Docker Host 상에서 <code>bada-dev-sandbox:latest</code> 이미지가 없는 경우, CLI 에이전트(예: <code>INSTALL_CLAUDE_CODE=true</code>)를 포함하는 Dockerfile 빌드가 자동으로 수행됩니다.</li>
<li><strong>격리 세션 개시</strong>: 원격 서버 리스트에서 ▶ 버튼을 클릭하여 원격 접속을 개시하면, SSH 터널을 경유해 도커 컨테이너가 가동되고, 터미널 화면에 컨테이너 내부 쉘 또는 내장된 에이전트 CLI가 투명하게 라우팅되어 가동됩니다.</li>
</ol>
<h2>포트 포워딩을 통한 개발 서버 접근</h2>
<p>격리된 샌드박스 컨테이너 안에서 동작하는 웹 서버(예: 3000포트)는 자동으로 Host의 임의 포트와 매핑되며, BADA Terminal이 이를 감지하여 SSH 터널로 Local PC에 동적 매핑해 줍니다. 샌드박스 관리 도구 창에서 매핑된 로컬 포트를 확인하고 웹브라우저로 즉시 접근할 수 있습니다.</p>
</section>
<!-- Section: Triage Guide -->
<section id="triage-guide" class="doc-section">
<div class="section-header">
<span class="section-badge">Resilience & Diagnostics</span>
<h1>AI 자동 장애 트리아지 (Triage Inbox)</h1>
<p class="section-desc">실패한 에이전트 작업의 로그를 해부해 원인과 처방전을 발급해주는 자가 복구 보조 시스템입니다.</p>
</div>
<h2>트리아지 흐름</h2>
<p>워크플로우 노드가 실패 코드를 반환하면, BADA 코어 엔진은 즉시 백그라운드 AI 진단 프로시저(<code>runAutoTriageDiagnostic</code>)를 트리거합니다.</p>
<div class="step-container">
<div class="step-item">
<span class="step-badge">1</span>
<div class="step-title">터미널 버퍼/로그 추출</div>
<div class="step-desc">최종 실패 직전 50라인의 터미널 표준 출력/에러 버퍼 로그를 슬라이스하여 추출합니다.</div>
</div>
<div class="step-item">
<span class="step-badge">2</span>
<div class="step-title">Claude AI 처방 프롬프트</div>
<div class="step-desc">백그라운드 Claude 세션에 실패 콘텍스트와 에러 스트림을 보내 "진단 원인"과 "처방 수동 해결 조치 방안(Markdown)"을 생성하게 합니다.</div>
</div>
<div class="step-item">
<span class="step-badge">3</span>
<div class="step-title">트리아지 인박스 적재</div>
<div class="step-desc">분석 결과를 SQLite <code>triage_items</code> 테이블에 보관하고 모니터 UI의 <code>🚨 트리아지 인박스</code> 탭에 알림 카드로 바인딩합니다.</div>
</div>
</div>
<h2>DB 락 결합 예외 방어</h2>
<p>sqlite3 파일 락 경합(<code>SQLITE_BUSY</code>)이 일어나도 메인 서버 코어가 크래시되지 않도록 트리아지 데이터 트랜잭션 전체에 <code>try-catch</code> 결함 허용(Fault tolerance) 래퍼를 씌웠습니다.</p>
</section>
<!-- Section: CLI Guide -->
<section id="cli-guide" class="doc-section">
<div class="section-header">
<span class="section-badge">CLI Interface</span>
<h1>CLI 트리거 연동 가이드</h1>
<p class="section-desc">외부 크론탭이나 클로드 네이티브 루틴에서 BADA 워크플로우를 가동하고 스트리밍받는 방법을 다룹니다.</p>
</div>
<h2>CLI 스펙 개요</h2>
<p>스크립트 위치: <code>scratch/trigger-bada-workflow.js</code></p>
<p>본 유틸리티는 백엔드 이벤트 버스를 실시간 구독하여 워크플로우의 실행 상세와 비용, 노드 상태 전이를 콘솔 스트림에 렌더링하고 완료 시 성공(0) 또는 실패(1) 코드로 리턴합니다.</p>
<h2>주요 CLI 옵션 및 아웃풋 통제</h2>
<div class="code-header">CLI Options</div>
<pre><code># 기본 실행 구문
NODE_PATH=./node_modules node scratch/trigger-bada-workflow.js [projectId] [workflowId]
# 상세 로그 전체 출력 (버퍼 트렁케이션 비활성화)
NODE_PATH=./node_modules node scratch/trigger-bada-workflow.js [projectId] [workflowId] --verbose</code></pre>
<h2>안전 연동 수거 설계</h2>
<ul class="doc-list">
<li><strong>메모리/이벤트 리스너 누수 방지</strong>: CLI 종료 시 워크플로우 리스너(Named Handler)를 즉각 소멸시켜 다중 기동 시 리스너 누적 현상이 없습니다.</li>
<li><strong>HITL 승인 대기 차단</strong>: 백그라운드 크론 실행 중 인간 검토(HITL) 단계에 돌입하여 행(Hang)이 걸리는 현상을 방지하기 위해, CLI 구동 모드에서는 <code>paused</code> 진입 즉시 정상 종료 코드(exit 0)를 반환하고 물러갑니다.</li>
</ul>
</section>
</main>
</div>
<!-- Javascript -->
<script>
// Tab switching inside sections
document.querySelectorAll('.tab-header').forEach(header => {
header.addEventListener('click', () => {
const tabContainer = header.closest('.tab-container');
// Remove active class from all headers in this container
tabContainer.querySelectorAll('.tab-header').forEach(h => h.classList.remove('active'));
// Add active to clicked header
header.classList.add('active');
// Hide all tab contents in this container
tabContainer.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
// Show the targeted content
const targetId = header.getAttribute('data-tab');
tabContainer.querySelector(`#${targetId}`).classList.add('active');
});
});
// Sidebar navigation active state and switching
const menuItems = document.querySelectorAll('.menu-item');
const docSections = document.querySelectorAll('.doc-section');
const contentContainer = document.getElementById('content-container');
const headerTocSelect = document.getElementById('header-toc-select');
const currentSectionTitle = document.getElementById('current-section-title');
function selectSection(targetId) {
// Find corresponding menu item
const item = Array.from(menuItems).find(i => i.getAttribute('data-target') === targetId);
if (!item) return;
// Remove active class from other items
menuItems.forEach(i => i.classList.remove('active'));
// Add active to current item
item.classList.add('active');
// Hide all sections
docSections.forEach(s => s.classList.remove('active'));
// Show selected section
const targetSection = document.getElementById(targetId);
if (targetSection) {
targetSection.classList.add('active');
contentContainer.scrollTop = 0;
// Update breadcrumbs and select box
const cleanTitle = item.textContent.replace(/[💡🚀💻🌿⏰🛡️📊🧠🔄⚓📦🚨⚙️]/g, '').trim();
currentSectionTitle.textContent = cleanTitle;
headerTocSelect.value = targetId;
}
}
menuItems.forEach(item => {
item.addEventListener('click', () => {
const targetId = item.getAttribute('data-target');
selectSection(targetId);
});
});
headerTocSelect.addEventListener('change', (e) => {
selectSection(e.target.value);
});
// Theme toggler
const themeToggle = document.getElementById('theme-toggle');
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('light-theme');
});
// Real-time search filter inside menu items
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', (e) => {
const query = e.target.value.toLowerCase().trim();
menuItems.forEach(item => {
const text = item.textContent.toLowerCase();
const targetId = item.getAttribute('data-target');
const section = document.getElementById(targetId);
let sectionText = '';
if (section) {
sectionText = section.textContent.toLowerCase();
}
// Match menu text or section text content
if (text.includes(query) || sectionText.includes(query)) {
item.style.display = 'flex';
// Highlight match visually in menu if needed
if (query !== '') {
item.style.borderLeft = '2px solid var(--mauve)';
} else {
item.style.borderLeft = 'none';
}
} else {
item.style.display = 'none';
}
});
// Show/hide menu group titles depending on visible children
document.querySelectorAll('.menu-group').forEach(group => {
const visibleItems = Array.from(group.querySelectorAll('.menu-item')).filter(i => i.style.display !== 'none');
const title = group.querySelector('.menu-group-title');
if (visibleItems.length === 0) {
if (title) title.style.display = 'none';
} else {
if (title) title.style.display = 'block';
}
});
});
</script>
</body>
</html>