가장 먼저 튼튼한 기반을 다집니다. 이 프로젝트는 모든 구성 요소(서버, 앱, 플러그인)가 하나의 저장소에 있는 Monorepo 구조를 따릅니다.
은유: 이것은 **"온 가족의 짐을 하나의 거대한 트렁크에 담는 것"**과 같습니다. 각자 작은 가방을 들고 다니면 잃어버리기 쉽지만, 하나로 묶어 관리하면 필요한 물건을 찾기도, 통째로 옮기기도 훨씬 쉬워지죠. (모노레포가 뭔지 까먹으셨다면? 👉 연재 1회의 '용어 미니 사전 2번' 을 다시 보고 오세요!)
지난 연재 2회에서 우리는 Node.js, pnpm, TypeScript 등 OpenClaw라는 건물을 짓기 위한 모든 **'장비와 부품'**들을 내 컴퓨터 주방에 훌륭하게 갖춰보았습니다.
- 기억나시나요? 수족관을 탈출해 기계 슈트를 입은 Node.js, 설계도를 꼼꼼히 검수하는 TypeScript, 그리고 효율적인 장바구니 pnpm까지!
- 아직 도구가 준비되지 않았거나 개념이 가물가물하시다면, 연재 2회: 장기 장만과 주방 공사를 다시 한번 훑어보시는 것을 추천합니다.
인제 준비된 장비들을 가지고, 진짜 OpenClaw의 땅을 다지고 설계도를 펼쳐볼 차례입니다.
이제 연재 2회에서 우리가 정성껏 마련했던 베이스캠프, openclaw-lab 폴더로 들어가 볼까요?
이미 Workspace 폴더 안에 openclaw-lab이라는 작업 공간을 만들어 두셨을 겁니다. 혹시 연재 2회를 건너뛰셨거나 새로 시작하고 싶으신 분들은 연재 2회의 '실습 가이드'를 참고해 기초 폴더 구조를 먼저 갖춰주세요.
터미널에서 우리의 거점 폴더로 이동합니다.
cd ~/Workspace/openclaw-labImportant
앞으로 우리는 Workspace 폴더 안에 두 종류의 폴더를 두고 병행해서 사용할 것입니다.
openclaw-lab(나의 실습장)- 목적: 우리가 강의를 따라가며 기능을 하나하나 직접 구현해 보는 폴더입니다.
- 역할: 텅 빈 바닥부터 시작해서 코드를 직접 타이핑하고 에러를 겪으며 '나만의 OpenClaw'를 조립해 나가는 실제 작업 공간입니다.
openclaw-src(공식 참고서)- 목적: OpenClaw 공식 GitHub에서 가져온 최신 정본 코드가 담긴 폴더입니다.
- 역할: "이 부분은 원래 어떻게 구현되어 있지?" 궁금할 때 열어보고, 필요한 설정이나 복잡한 코드를 카피(Copy)해 오거나 참조하는 **'정답지'**이자 **'기술 백과사전'**입니다.
Tip
'정답지'를 내 컴퓨터에 비치해 볼까요?
터미널에서 Workspace 폴더로 이동한 뒤, 아래 명령어를 입력하여 공식 소스 코드를 내려받으세요. (이 폴더는 실습용이 아니니 눈으로 읽거나 참고 용도로만 사용해 주세요!)
cd ~/Workspace
git clone https://github.com/OpenClaw/OpenClaw openclaw-srcNote
개발을 하다 보면 "어? 제 파일 어디 갔죠?" 하고 길을 잃는 경우가 정말 많습니다. 윈도우(C드라이브) 사용자, 맥(홈) 사용자 모두 Workspace라는 공통된 약속 장소를 정해두면, 나중에 "경로를 못 찾겠어요" 같은 문제를 99% 예방할 수 있습니다. 이것은 전 세계 개발자들의 '국룰(불문율)' 같은 습관이며, 경로 문제로 헷갈릴 일을 원천 봉쇄해 줍니다.
"자, 이제 openclaw-src 폴더에 배달된 부품들을 하나씩 꺼내 봅시다. 이 폴더가 앞으로 우리가 정복할 거대한 성(Castle)입니다."
단순한 폴더 목록이 아닙니다. 이 지도를 머릿속에 넣으면 코드의 흐름이 보입니다.
openclaw-src/ (프로젝트 루트)
├── 📂 apps/ # 실행 가능한 애플리케이션 모음 (Gateway 등)
├── 📂 packages/ # 여러 곳에서 공용으로 쓰는 핵심 라이브러리
└── 📂 src/ # 실제 모든 마법이 일어나는 핵심 소스 (90%의 비중)
├── 📂 gateway/ # 🧠 [중추 신경망]
│ │ # 모든 메시지를 수신하고, 어떤 채널이나 에이전트가 처리할지 결정합니다.
│ ├── server.ts # 게이트웨이 서버의 진입점(시작점)
│ └── router.ts # 메시지 배달 경로를 정의하는 핵심 로직
├── 📂 channels/ # 🔌 [통신 포트]
│ │ # 외부 세상(카톡, 디스코드 등)과 연결되는 입구와 출구입니다.
│ ├── discord/ # 디스코드 전용 연결부
│ ├── slack/ # 슬랙 전용 연결부
│ └── registry.ts # 어떤 통신 채널들이 있는지 관리하는 목록
├── 📂 agents/ # 🤖 [AI 두뇌]
│ │ # 서버에 지능을 부여합니다. 질문에 답하거나 미션을 수행합니다.
│ ├── memory/ # 이전 대화를 기억하는 저장소 관리
│ └── context.ts # 현재 대화의 맥락(Context) 데이터
├── 📂 infra/ # 🧱 [바닥 기초]
│ │ # 데이터베이스(DB), 캐시(Redis), 로그 시스템 등 기초 설비를 담당합니다.
├── 📂 types/ # 📏 [표준 규격]
│ │ # 프로젝트 전체에서 쓰이는 데이터 약속(Interface)들이 모여있습니다.
└── 📂 utils/ # 🛠️ [공구함]
# 날짜 변환, 문자열 가공 등 실무에서 자주 쓰는 유용한 함수들
Tip
우리가 2장에서 가장 먼저 공략할 곳은?
바로 src/gateway/ 입니다. 여기가 OpenClaw의 심장이기 때문이죠!
사용자가 직접 보고 사용하는 프로그램들이 모여 있습니다.
- 데스크톱 앱이나 웹 대시보드처럼 **'눈에 보이는 결과물'**들이 이곳에서 만들어집니다.
서버와 앱이 함께 나눠 쓰는 **'범용 도구'**들이 들어 있습니다.
- 예를 들어, '날짜 계산기'나 '로그 기록기'처럼 양쪽 모두에서 필요한 필수 도구들을 모아둔 곳입니다.
이 거대한 나라의 **'호구조사부'**이자 **'부품 목록'**입니다.
- 어떤 부품이 어디에 있는지, 서로 어떻게 연결되는지(의존성)를 정의합니다.
Tip
설계도를 배우기 전, '실제 건물'을 먼저 투어한 이유:
눈앞에 실물이 있어야 설계도(tsconfig.json)가 왜 필요한지 더 절실히 느껴지기 때문입니다. 이제 이 수많은 폴더와 파일들을 TypeScript가 어떻게 한 줄로 세우고 관리하는지, 다음 챕터에서 확인해 봅시다.
많은 입문자분이 **"이런 설정 파일들 다 건너뛰고, 바로 멋진 AI 봇 코드부터 짜면 안 되나요?"**라고 묻습니다. 마음은 급하시겠지만, OpenClaw 같은 거대한 프로젝트는 아무것도 없는 백지 상태에서 갑자기 태어나지 않습니다. 가장 먼저 **'이 프로젝트는 누구인가?'**를 정의하는 서류들이 필요합니다.
폴더 안에 가장 먼저 만들어져야 할 파일입니다.
- 이름과 나이: 이 프로젝트의 이름은 무엇인지, 버전은 몇인지 적습니다.
- 성격: 이 프로젝트가 무엇을 하는 녀석인지 설명합니다.
- 친구들(의존성): "나는 혼자 다 할 수 없어. A라는 기능은 이 라이브러리의 도움을 받을 거야"라고 외부 도구들과의 관계를 정의합니다.
한 줄 요약: 이 파일이 없으면 컴퓨터는 이 폴더가 그냥 '폴더'인지 '프로그램'인지 알 길이 없습니다.
우리는 TypeScript라는 언어를 씁니다. 인간에게는 친절하지만, 컴퓨터는 바로 이해하지 못하죠. 그래서 누군가 중간에서 번역(컴파일)을 해줘야 합니다.
- 번역 규칙: "너는 너무 엄격하게 번역하지 마", "최신 스타일로 번역해줘" 같은 세세한 규칙을 통역사에게 전달합니다.
- 범위: "이 폴더 안에 있는 파일들만 번역하면 돼"라고 범위를 정해줍니다.
한 줄 요약: TypeScript라는 원석을 브라우저나 컴퓨터가 읽을 수 있는 JavaScript라는 보석으로 깎아내는 '정밀 조각 지침서'입니다.
Tip
실습 준비 완료! 이제 이 서류들이 왜 필요한지 이해하셨나요? 다음 섹션에서 이 서류들을 직접 눈으로 확인하며 실습 환경을 구축해 보겠습니다. 허가증 없이 철근(import)을 하나라도 세우면 공사 중지 명령(Syntax Error)이 떨어집니다.
- 종이에 하는 낙서: 혼자 빈 종이에 그림을 그릴 때는 아무런 규칙이 필요 없습니다. 내가 알아보기만 하면 되고, 틀리면 그냥 지우거나 종이를 버리면 그만이니까요. (이것이 아주 작은 기초 코드를 짤 때의 모습입니다.)
- 100층 건물 짓기 (OpenClaw): 하지만 수만 명의 AI 봇이 거주할 거대한 마천루를 지을 때는 다릅니다. 벽돌 한 장 쌓기 전에 **'건축 안전 지침서'**가 반드시 필요합니다.
- "기둥은 얼마나 튼튼해야 하는가?"
- "어떤 규격의 자재를 사용해야 하는가?"
- 이 지침서가 바로 **
tsconfig.json**입니다. 미리 엄격한 규칙을 정해두지 않으면, 나중에 건물이 통째로 무너지는 대참사(오류)가 날 수 있기 때문입니다.
3. 실제 예시 (Real World Scenario) 만약 설정 없이 바로 코드를 짠다면?
- 개발자: (자신있게)
import { Server } from 'http'; - 컴퓨터(Node.js): "잠깐, import가 뭐죠? 저는 옛날 방식(require)밖에 모르는데요?" -> 에러 발생 (Crash)
- 개발자: (당황하며)
어? 요즘 다 이거 쓰던데? - 컴퓨터: "그건 tsconfig.json 이라는 번역기가 있을 때 얘기입니다. 저한테 미리 언질을 안 주셨잖아요."
결론: tsconfig.json을 먼저 만드는 것은 컴퓨터에게 "지금부터 우리는 최신 유행어(ESM)와 엄격한 문법(TypeScript)으로 대화할 거야. 준비해." 라고 선전포고를 하는 것입니다. 이 합의가 없으면 단 한 줄의 코드도 실행되지 않습니다.
"Moltbot은 대형 프로젝트라서 이미 설정이 다 되어있지만, 맨땅에서 시작하는 나만의 작은 앱은 어떻게 시작하나요?"
1. 은유(Metaphor): 새로운 국가를 세울 때의 "헌법 제정" 백지에 그림을 그리는 것과 같습니다. 나라를 처음 세울 때, 우리 국민은 어떤 언어를 쓰고(Target), 주변 나라와는 어떻게 소통하며(Module), 범죄(Error)에는 얼마나 엄격할 것인지(Strict)를 정하는 **'국가 헌법'**을 만드는 과정이 바로 tsconfig.json 초기화입니다. 헌법이 모호하면 나라가 혼란에 빠지듯, 이 설정이 부실하면 개발 과정 내내 충돌이 일어납니다.
2. 개념(Concept): 초기화의 두 가지 경로 (자동 vs 실전)
TypeScript는 개발자가 처음부터 고생하지 않도록 **'표준 헌법 초안'**을 자동으로 생성해주는 도구(npx tsc --init)를 제공합니다. 초보자는 자동 생성된 초안에서 시작하고, 숙련자는 프로젝트의 목적(고성능 서버, 프론트엔드 등)에 맞춰 그 초안을 수정하여 사용합니다.
3. 코드(Code): 헌법의 탄생과 핵심 3조항
연재 2회에서 사용하던 터미널 창을 그대로 사용하세요. 다음 명령어를 입력하면 수중한 주석과 함께 설정 파일이 생성됩니다.
npx tsc --init자동 생성된 파일에서 아래 **'핵심 3개 조항'**만은 반드시 확인하고 수정해 주세요.
{
"compilerOptions": {
"target": "ES2022", // [제1조] 사용할 언어의 문법 수준 (최신 사투리 인정)
"module": "NodeNext", // [제2조] 소통 규약 (최신 스마트폰 규격 사용)
"strict": true // [제3조] 법 집행의 엄격함 (무관용 원칙)
}
}4. 배경 및 실전 가이드(Context & Guide): 왜 이 3가지인가?
- 왜 target: ES2022인가?: 과거에는 구식 브라우저를 위해 코드를 어렵게 번역해야 했습니다. 하지막 지금 우리가 만드는 서버(Node.js 22)는 똑똑합니다. 최신 문법을 그대로 써야 속도가 빠르고 코드가 깔끔해집니다.
- 왜 module: NodeNext인가?: 자바스크립트 세계는 지금 '구식(CommonJS)'과 '신식(ESM)'이 교체되는 과도기입니다. NodeNext는 "우리는 신식을 쓰되, 구식도 알아듣겠다"는 가장 현명한 중재안입니다.
- 왜 strict: true인가?: "대충 짜고 나중에 고치지 뭐"라는 생각은 개발자의 가장 큰 착각입니다. 처음부터 엄격하게 관리하는 것이, 나중에 버그를 찾느라 밤을 새우는 것보다 100배 경제적입니다.
Tip
요약: 작은 프로젝트라도 npx tsc --init으로 시작하고, Target(최신), Module(NodeNext), Strict(True) 이 세 가지만 기억하세요. 이것만으로도 여러분의 프로젝트는 구글이나 메타(Facebook) 부럽지 않은 튼튼한 기초를 갖추게 됩니다.
앞서 이 파일을 **'건축 안전 지침서'**라고 불렀습니다. 이 지침서 안에는 건물을 지을 때 우리가 지켜야 할 구체적인 약속들이 적혀 있습니다.
rootDir(원본 작업실): 우리가 열심히 코드를 짜는 원본 설계도가 들어있는 **'주 작업실'**입니다. 여기서는src라는 폴더를 쓰기로 약속했습니다.outDir(출고 창고): 작업이 끝난 완제품(컴퓨터가 읽을 수 있는 파일)을 차곡차곡 쌓아두는 **'출고 창고'**입니다.dist라는 이름의 폴더를 창고로 씁니다.
esModuleInterop(만능 어댑터): 세상에는 다양한 규격의 부품들이 있습니다. 이 옵션은 서로 규격이 다른 부품들도 문제없이 대화하게 해주는 **'만능 변환 어댑터'**입니다.skipLibCheck(기성품 검수 생략): 이미 밖에서 검증되어 가져온 전구 나사나 타일 같은 **'기성품 부품'**들까지 우리가 일일이 오타 검사를 하느라 시간을 낭비하지 않겠다는 똑똑한 약속입니다.
{
"compilerOptions": {
"target": "ES2022", /* 건물의 최종 형태(JavaScript)를 최신식으로 맞춥니다. */
"module": "NodeNext", /* 부품들을 조립하는 최신 규격을 따릅니다. */
"moduleResolution": "NodeNext", /* 부품들이 서로를 찾는 방식을 최신식으로 정합니다. */
"outDir": "dist", /* 공사가 끝난 완제품이 쌓이는 '출고 창고' 폴더입니다. */
"rootDir": "src", /* 우리가 작업하는 원본 설계도가 들어있는 '작업실' 폴더입니다. */
"strict": true, /* 설계도에 오타나 실수가 없는지 아주 엄격하게 검증합니다. */
"esModuleInterop": true, /* 규격이 서로 다른 부품들도 문제없이 대화하게 해주는 '만능 어댑터'입니다. */
"forceConsistentCasingInFileNames": true, /* 파일 이름의 대소문자를 헷갈리지 않게 확실히 구분합니다. */
"skipLibCheck": true, /* 이미 검증된 기성품 부품들은 일일이 재검사하지 않고 넘어갑니다. */
"resolveJsonModule": true, /* .json 파일도 부품처럼 바로 가져다 쓸 수 있게 해줍니다. */
"noEmitOnError": true, /* 설계도에 하나라도 실수가 있으면 아예 창고에 물건을 내놓지 않습니다. */
"allowSyntheticDefaultImports": true /* 다양한 부품 조립 방식을 두루 허용해줍니다. */
},
"include": ["src/**/*"], /* 작업실(src) 안에 있는 모든 설계도를 검토 대상에 넣습니다. */
"exclude": [ /* 아래 항목들은 검토 대상에서 제외합니다. */
"node_modules", /* 이미 산더미처럼 쌓인 외부 기성품 부품들 */
"dist", /* 이미 완성되어 나간 출고 창고 */
"src/**/*.test.ts", /* 우리끼리 테스트해본 연습용 도면들 */
"src/**/*.test.tsx",
"src/**/test-helpers.ts"
]
}설계도(tsconfig.json)까지 완료했다면, 이제 지금까지 작업한 내용을 안전하게 기록해둘 차례입니다. 개발자들은 작업의 마디마디마다 **'버전(Version)'**을 남겨둡니다.
- Git Commit (스냅샷): 인공위성에서 지상을 내려다보듯, "현재 공사 진행 상황"을 사진으로 찍어 내 컴퓨터의 **'비밀 앨범(로컬 저장소)'**에 저장하는 것입니다.
- Git Push (앨범 전송): 내 컴퓨터에만 있던 그 앨범을 **'중앙 서버(GitHub 등)'**라는 거대한 금고에 통째로 복사해서 올리는 것입니다.
Note
왜 '버전'이라고 하나요? 만약 내일 공사를 하다가 건물이 무너져도(코드가 꼬여도), 오늘 찍어둔 '사진(버전)'만 있으면 언제든 오늘 상태로 완벽하게 되돌릴 수 있기 때문입니다.
Git Push를 하려면 먼저 결과물을 받아줄 **'온라인 금고(원격 저장소)'**가 필요합니다. 초보자도 1분 만에 따라 할 수 있는 절차입니다.
- **github.com**에 접속합니다.
- 오른쪽 상단 [Sign up] 버튼을 누릅니다.
- 이메일, 비밀번호, 닉네임(username)을 입력하고 간단한 퀴즈(봇 방지)를 풉니다.
- 이메일로 온 인증 코드를 입력하면 가입 완료! (전 세계 개발자들의 공용 여권이 생긴 셈입니다.)
- 로그인 후 왼쪽 위 상단 혹은 오른쪽 위 [+] 아이콘을 눌러 **[New repository]**를 선택합니다.
- Repository name에
openclaw-lab이라고 적습니다. (우리의 실습장 이름과 맞춥니다.) - Public(공개) 또는 Private(비공개) 중 원하는 것을 선택합니다.
- 다른 설정은 건드리지 말고 맨 아래 [Create repository] 버튼을 클릭하세요!
저장소를 만들면 화면에 복사할 수 있는 주소(https://github.com/내아이디/openclaw-lab.git)가 보입니다. 터미널에서 이 주소를 내 프로젝트에 등록해줘야 합니다.
# 내 컴퓨터 프로젝트에 'origin'이라는 이름으로 온라인 주소를 등록합니다.
git remote add origin https://github.com/본인아이디/openclaw-lab.git
# 등록이 잘 되었는지 확인해봅니다.
git remote -v터미널에서 openclaw-lab 폴더로 이동한 상태에서 아래 명령어를 순서대로 입력해보세요.
-
상태 확인: 어떤 파일들이 바뀌었는지 확인합니다.
git status
-
재료 담기: 기록할 파일들을 장바구니(Staging Area)에 담습니다.
git add . -
기록하기 (Commit): 버전 이름과 함께 로컬 기록을 남깁니다. (이것이 하나의 '버전'이 됩니다.)
git commit -m "feat: 기초 공사 및 설계도(tsconfig) 완료" -
전송하기 (Push): 중앙 서버로 내 버전들을 보냅니다.
git push origin main
(※ 이미 깃허브 저장소가 연결된 상태라면 이 명령어로 온라인 금고에 안전하게 복사됩니다.)
축하합니다! 이제 OpenClaw를 짓기 위한 땅도 다졌고, 헌법(tsconfig.json)도 제정했으며, 첫 번째 기록까지 마쳤습니다.
다음 연재에서는 드디어 이 튼튼한 기반 위에 진짜 소문 무성한 'AI 게이트웨이'의 심장을 하나씩 박아보겠습니다. 고생하셨습니다!