| <!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의 메뉴 가이드, 기능 설명 및 사용 설명서"> |
| |
| |
| <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"> |
| |
| |
| <style> |
| :root { |
| --bg: #1e1e2e; |
| --mantle: #181825; |
| --crust: #11111b; |
| --text: #cdd6f4; |
| --subtext: #a6adc8; |
| |
| |
| --mauve: #cba6f7; |
| --blue: #89b4fa; |
| --lavender: #b4befe; |
| --green: #a6e3a1; |
| --yellow: #f9e2af; |
| --red: #f38ba8; |
| --peach: #fab387; |
| --teal: #94e2d5; |
| |
| |
| --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); |
| } |
| |
| |
| 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; |
| } |
| |
| |
| #app-layout { |
| display: flex; |
| width: 100vw; |
| height: 100vh; |
| overflow: hidden; |
| } |
| |
| |
| #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; |
| } |
| |
| |
| #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); |
| } |
| |
| |
| .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-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); } |
| |
| |
| 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; |
| } |
| |
| |
| 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; |
| } |
| |
| |
| .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; |
| } |
| |
| |
| .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; |
| } |
| |
| |
| .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; |
| } |
| |
| |
| 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; |
| } |
| |
| |
| #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); |
| } |
| |
| |
| .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; |
| } |
| |
| |
| .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"> |
| |
| |
| <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 id="content-container"> |
|
|
| |
| <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 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 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 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 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 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);"> |
| |
| <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> |
| |
| <div style="display: flex; gap: 12px; height: 260px; font-family: sans-serif;"> |
| |
| <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> |
| |
| <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> |
| |
| <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 & 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 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 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 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 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 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 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> |
|
|
| |
| <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> |
| |
| |
| <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> |
|
|
| |
| <line x1="200" y1="115" x2="245" y2="115" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow)" class="flow-line" /> |
|
|
| |
| <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> |
|
|
| |
| <line x1="495" y1="115" x2="535" y2="115" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow)" class="flow-line" /> |
|
|
| |
| <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 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 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 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> |
|
|
| |
| <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> |
| |
| |
| <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 & Iteration 한도</text> |
| </g> |
|
|
| |
| <path d="M 240 70 L 350 70" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" /> |
|
|
| |
| <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> |
|
|
| |
| <path d="M 460 115 L 460 185" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" /> |
|
|
| |
| <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> |
|
|
| |
| <path d="M 360 240 L 250 240" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" /> |
|
|
| |
| <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> |
|
|
| |
| <path d="M 140 195 L 140 125" stroke="#a6adc8" stroke-width="2" marker-end="url(#arrow-gray)" class="flow-line" /> |
| |
| |
| <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 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> |
|
|
| |
| <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> |
| |
| |
| <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> |
| |
| |
| <path d="M 80 60 Q 150 160 220 160" stroke="#89b4fa" stroke-width="2" stroke-dasharray="4" fill="none" /> |
| |
| |
| <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">에이전트 단독 파일 수정 & 빌드</text> |
| </g> |
|
|
| |
| <circle cx="220" cy="160" r="5" fill="#89b4fa" /> |
| <circle cx="440" cy="160" r="5" fill="#89b4fa" /> |
| |
| |
| <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> |
|
|
| |
| <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 & 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 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 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 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 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 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> |
|
|
| |
| <script> |
| |
| document.querySelectorAll('.tab-header').forEach(header => { |
| header.addEventListener('click', () => { |
| const tabContainer = header.closest('.tab-container'); |
| |
| |
| tabContainer.querySelectorAll('.tab-header').forEach(h => h.classList.remove('active')); |
| |
| header.classList.add('active'); |
| |
| |
| tabContainer.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); |
| |
| const targetId = header.getAttribute('data-tab'); |
| tabContainer.querySelector(`#${targetId}`).classList.add('active'); |
| }); |
| }); |
| |
| |
| 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) { |
| |
| const item = Array.from(menuItems).find(i => i.getAttribute('data-target') === targetId); |
| if (!item) return; |
| |
| |
| menuItems.forEach(i => i.classList.remove('active')); |
| |
| item.classList.add('active'); |
| |
| |
| docSections.forEach(s => s.classList.remove('active')); |
| |
| |
| const targetSection = document.getElementById(targetId); |
| if (targetSection) { |
| targetSection.classList.add('active'); |
| contentContainer.scrollTop = 0; |
| |
| |
| 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); |
| }); |
| |
| |
| const themeToggle = document.getElementById('theme-toggle'); |
| themeToggle.addEventListener('click', () => { |
| document.body.classList.toggle('light-theme'); |
| }); |
| |
| |
| 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(); |
| } |
| |
| |
| if (text.includes(query) || sectionText.includes(query)) { |
| item.style.display = 'flex'; |
| |
| |
| if (query !== '') { |
| item.style.borderLeft = '2px solid var(--mauve)'; |
| } else { |
| item.style.borderLeft = 'none'; |
| } |
| } else { |
| item.style.display = 'none'; |
| } |
| }); |
| |
| |
| 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> |
|
|