내부 동작 원리와 아키텍처 깊이 보기 (Under the Hood)
holaOS의 내부 구조는 단순한 UI 래퍼가 아니에요. Electron 기반의 데스크톱 셸 아래에 강력한 Node.js/TypeScript 런타임 하네스, TanStack Start 앱 모듈, SQLite 기반의 지속성 작업 큐(Job Queue), 그리고 표준화된 MCP 클라이언트 호스트가 톱니바퀴처럼 연동되어 구동돼요.
시스템 전체 구조 및 아키텍처 레이어
holaOS의 중심에는 메인 워크스페이스 엔진이 위치하며, 하부의 에이전트 하네스, 공유 메모리, MCP 게이트웨이를 종합적으로 제어해요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
flowchart LR
U["사용자 UI 레이어"] --> W["워크스페이스 메인 엔진"]
W --> H["에이전트 하네스 레이어"]
H --> A1["Claude Code 에이전트"]
H --> A2["Codex 에이전트"]
H --> A3["holaOS 내장 에이전트"]
A1 --> M["공유 메모리 저장소"]
A2 --> M
A3 --> M
H --> P["MCP 통합 게이트웨이"]
P --> T["외부 도구 및 API"]
에이전트 간 요청 처리 및 메모리 동기화 흐름
사용자가 작업을 요청했을 때 공유 메모리와 MCP 도구가 어떻게 상호작용하며 에이전트 간 맥락을 유지하는지 살펴보죠.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
sequenceDiagram
participant User as 사용자
participant Workspace as 워크스페이스 조율기
participant Memory as 공유 메모리 DB
participant Agent as Claude Code 에이전트
participant MCP as MCP 프로토콜 서버
User->>Workspace: 작업 요청 제출
Workspace->>Memory: 관련 컨텍스트 및 과거 메모리 조회
Memory-->>Workspace: 공유 컨텍스트 반환
Workspace->>Agent: 프롬프트 및 공유 컨텍스트 전달
Agent->>MCP: MCP 도구 실행 요청
MCP-->>Agent: 결과 데이터 반환
Agent->>Memory: 업데이트된 작업 결과 저장
Agent-->>User: 최종 결과 답변 출력
공유 메모리 및 워크스페이스 데이터 스키마
로컬 SQLite에 저장되는 데이터 스키마 관계를 나타낸 다이어그램이에요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
erDiagram
SHARED_MEMORY {
string memory_id
string content_text
string tag_name
string created_at
}
WORK_TASK {
string task_id
string task_status
string goal_description
}
AGENT_HARNESS {
string harness_id
string agent_type
string model_provider
}
MCP_TOOL {
string tool_id
string server_name
string tool_schema
}
WORK_TASK ||--o{ SHARED_MEMORY : writes
AGENT_HARNESS ||--o{ WORK_TASK : executes
AGENT_HARNESS ||--o{ MCP_TOOL : invokes
에이전트 태스크 생명주기
에이전트가 생성되어 컨텍스트를 로드하고 MCP 도구를 실행한 뒤 저장하는 상태 전이 구조예요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
stateDiagram-v2
[*] --> STATE_IDLE
STATE_IDLE --> STATE_CONTEXT_LOAD : 작업 요청 수신
STATE_CONTEXT_LOAD --> STATE_PROMPT_DISPATCH : 공유 메모리 로드 완료
STATE_PROMPT_DISPATCH --> STATE_TOOL_EXECUTION : 에이전트 할당 및 실행
STATE_TOOL_EXECUTION --> STATE_MEMORY_SYNC : MCP 도구 호출 완료
STATE_MEMORY_SYNC --> STATE_FINISHED : 공유 메모리 업데이트 완료
STATE_FINISHED --> [*]
메인 코어 모듈 클래스 구조
오케스트레이션 엔진의 주요 모듈 클래스 구조예요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
classDiagram
class ENGINE_CORE {
+string workspaceId
+initSession()
+dispatchTask()
}
class HARNESS_RUNNER {
+string agentName
+runClaudeCode()
+runCodex()
}
class MEMORY_MANAGER {
+storeMemory()
+queryContext()
}
class MCP_CLIENT {
+registerServer()
+executeTool()
}
ENGINE_CORE --> HARNESS_RUNNER
ENGINE_CORE --> MEMORY_MANAGER
HARNESS_RUNNER --> MCP_CLIENT
작업 유형별 에이전트 활용 비중
holaOS 워크스페이스 내부에서 각 에이전트가 주로 담당하는 전형적인 역할 비중이에요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
pie title holaOS 작업 수행 시 에이전트별 활용 비중
"Claude Code 에이전트" : 40
"Codex 에이전트" : 35
"holaOS 내장 에이전트" : 25
작업 파이프라인 흐름
단일 작업이 들어왔을 때 로컬 SQLite 큐를 거쳐 적절한 에이전트로 분배되는 파이프라인을 시각화했어요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
flowchart TD
A["신규 작업 입력"] --> B["SQLite 작업 큐 등록"]
B --> C{"에이전트 선택"}
C -->|"코드 구조 분석"| D["Claude Code 하네스"]
C -->|"구현 및 리팩토링"| E["Codex 하네스"]
D --> F["공유 메모리 기록"]
E --> F
F --> G["결과 시각화 및 완료"]
MCP 연결 및 도구 전송 아키텍처
stdio 및 HTTP SSE를 포함한 MCP 커넥터 통합 레이어 구조예요.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
flowchart LR
A["holaOS 코어 런타임"] --> B["MCP Client 호스트"]
B --> C["Stdio 전송 레이어"]
B --> D["HTTP SSE 전송 레이어"]
C --> E["로컬 파일 및 SQLite MCP"]
D --> F["원격 서비스 API MCP"]
코드로 보는 런타임 오케스트레이션 예시
실제 TypeScript 런타임 내부에서 공유 메모리를 로드하고 도구를 실행하는 핵심 의사코드 패턴은 다음과 같아요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| import { WorkspaceRuntime, SharedMemoryStore, AgentHarness } from "@holaboss/runtime";
import { MCPClientManager } from "@holaboss/mcp";
export class AgentWorkspaceOrchestrator {
private memoryStore: SharedMemoryStore;
private mcpClient: MCPClientManager;
constructor() {
this.memoryStore = new SharedMemoryStore({ dbPath: "./data/shared_memory.sqlite" });
this.mcpClient = new MCPClientManager();
}
public async initializeWorkspace(): Promise<void> {
await this.memoryStore.initSchema();
await this.mcpClient.connectRegisteredServers();
}
public async runMultiAgentTask(taskGoal: string): Promise<void> {
const context = await this.memoryStore.fetchContextByQuery(taskGoal);
const claudeHarness = new AgentHarness({ agentType: "claude-code" });
const analysisResult = await claudeHarness.execute({ prompt: taskGoal, initialContext: context });
await this.memoryStore.saveRecord({
sourceAgent: "claude-code",
content: analysisResult.output,
tags: ["analysis", "architecture"]
});
const codexHarness = new AgentHarness({ agentType: "codex" });
const updatedContext = await this.memoryStore.fetchLatestContext();
const refactorResult = await codexHarness.execute({
prompt: "위 분석 결과를 바탕으로 구현 코드를 작성하세요.",
initialContext: updatedContext
});
await this.memoryStore.saveRecord({
sourceAgent: "codex",
content: refactorResult.output,
tags: ["refactored-code"]
});
}
}
|