GITHUB 레포 딥다이브 · 2026-08-04 · GENSPARK-AI/GENOFFICE · MS 오피스를 흉내 낸 게 아니라, "원본 파일을 한 바이트도 안 건드리고 AI로 고친다"는 발상으로 다시 지은 오피스

genoffice 딥다이브
바꾼 문단만 오려 갈아 끼우는, AI 네이티브 오피스 스위트

genspark-ai/genoffice는 워드·엑셀·파워포인트·PDF를 대체하는 데스크톱 오피스 스위트다(macOS·Windows). 그런데 팔아 먹는 각도가 특이하다 — AI 채팅을 나중에 옆에 붙인 게 아니라, "AI로 문서를 고치는 것"을 1급 기능으로 두고 처음부터 다시 설계했다. 그리고 그 밑을 받치는 엔진에 이 레포의 진짜 자랑이 있다.

핵심은 바이트 보존 왕복(byte-preserving round trip)이다. .docx를 열어 AI가 문단 하나를 고쳐도, 건드리지 않은 나머지는 원본 바이트 그대로 유지하고 바뀐 문단만 다시 만들어 끼워 넣는다. 그래서 워드로 다시 열어도 서식이 깨지지 않는다 — 다른 변환 도구들이 문서를 통째로 다시 그리다 서식을 망가뜨리는 것과 정반대다.

(저장소 genspark-ai/genoffice · 제작 Mainfunc, Inc.(Genspark) · 라이선스 Apache-2.0(단 ee/는 엔터프라이즈) · 언어 TypeScript 770파일 + Rust 7파일 · ~30.8만 줄 · 테스트 303개 · 구조 Electron 앱 5개 + 엔진 패키지 11개 모노레포 · 배포 버전 v0.4.110 · 최신 커밋 2026-08-03(내부 저장소를 주기적으로 미러링하는 "Sync snapshot") · TrendShift Daily #10)
목차
  1. 한 줄 정체
  2. 왜 주목받는가 — "AI + 원본 보존"이라는 두 각도
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 바이트 보존 패치와 공용 AI 엔진
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 기술별 배울 것
  7. 시스템 / 빌드 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 로드맵 (주차별)
  10. 핵심 키워드 사전
  11. 참고 링크

1한 줄 정체

이 프로젝트가 정확히 무엇인지 한 문장으로

genoffice는 "워드·엑셀·PPT·PDF를 편집하는 5개의 Electron 데스크톱 앱을, 하나의 공용 AI 엔진 위에 얹고, 원본 파일을 최대한 안 건드리는 패치 방식으로 저장하도록 만든, 오픈소스 AI 네이티브 오피스 스위트"다. 겉보기엔 무료 MS 오피스 같지만, 속을 보면 "파일 포맷 엔진 + AI 에이전트 루프"를 직접 구현한 대형 모노레포다.

한 장의 비유

"인쇄된 책에서 한 줄만 고칠 때, 그 줄의 활자만 새로 짜 끼우기"

보통의 문서 변환 도구로 .docx를 고치는 건 책 전체를 다시 타이핑하는 것과 같다. 겉보기엔 똑같아도 글꼴·자간·숨은 서식이 조금씩 어긋난다. 워드로 다시 열었을 때 "어, 왜 줄이 밀렸지?" 하는 그 현상이다.

genoffice는 옛날 활판 인쇄공처럼 일한다. 원본 판(원본 파일의 바이트)은 그대로 두고, 당신이 고친 그 한 문단의 활자만 새로 짜서 그 자리에 끼운다. 나머지 줄의 잉크는 한 점도 안 건드린다. 그래서 다시 열면 당신이 고친 부분 말고는 원본과 완전히 동일하다.

용어
오피스 스위트 (office suite)
문서(워드)·표계산(엑셀)·발표자료(PPT)·PDF를 다루는 프로그램 묶음. genoffice는 이 넷을 각각 apps/docs·apps/sheets·apps/slides·apps/pdf 앱으로 만들고, apps/shell이 이들을 탭으로 품는 "런처"가 된다.
용어
Electron (일렉트론)
웹 기술(HTML·CSS·JS)로 데스크톱 앱을 만드는 틀. 안에 크롬(렌더러)과 Node.js(메인 프로세스)를 함께 담는다. VS Code·Slack·Discord가 이걸로 만들어졌다. genoffice의 다섯 앱이 전부 Electron이라, 웹 개발자가 그대로 데스크톱 오피스를 만들 수 있었던 배경이다.
용어
바이트 보존 왕복 (byte-preserving round trip)
파일을 열고(→편집→) 저장했을 때, 손대지 않은 부분이 원본과 바이트 단위로 똑같이 남는 것. genoffice의 핵심 설계 원칙이자 다른 오피스 대비 결정적 차별점이다. "왕복(round trip)"은 열기→저장의 한 바퀴를 뜻한다.

에이전트가 문서 하나를 여는 순간부터 AI가 문단을 고치고 저장할 때까지, genoffice 안에서 벌어지는 일을 압축하면 이렇다:

사용자: "이 계약서 3번 조항을 더 부드럽게 고쳐줘" ← AI 패널에 입력 │ ▼ ① 원본 보관 열린 .docx 를 해시로 원본 그대로 보관 (절대 안 건드림) docx-engine 이 word/document.xml 의 최상위 요소(w:p / w:tbl)를 파싱 ② 블록 트리 문단마다 docxIndex 앵커 + 원본 XML 조각을 붙인 블록 트리 생성 → TipTap 편집기에 스트리밍 (사람 편집·AI 편집 모두 dirty 추적) ③ AI 편집 agent-core 루프가 도는 동안 AI가 replace_blocks 툴 호출 → 3번 조항 블록만 "dirty" 표시, 스냅샷 찍어둠(원클릭 되돌리기용) ④ 조각 생성 저장 시 dirty 블록만 OOXML 조각으로 다시 생성 (이미 있는 스타일만 참조 — 새 서식을 함부로 안 만듦) ⑤ 스플라이스 원본 document.xml 에 그 조각만 갈아 끼움 손 안 댄 블록은 원본 바이트를 그대로 복사 ⑥ 재압축 zip 다시 묶기 — 나머지 모든 엔트리(스타일·이미지·주석)는 바이트 단위로 그대로 복사 → 워드로 열어도 서식 안 깨짐

여기서 결정적인 건 ①과 ⑤·⑥이다. 원본을 통째로 다시 그리는 게 아니라, 고친 문단만 골라 갈아 끼우고 나머지는 원본 바이트를 복사한다. 이 "narrow patch(좁은 패치)" 철학이 docs뿐 아니라 sheets·slides에도 똑같이 흐른다 — 원본 파일이 언제나 진실의 근원이고, 편집은 최소한의 조각 교체로 적용된다.

2왜 주목받는가 — "AI + 원본 보존"이라는 두 각도

무료 오피스는 이미 많은데(LibreOffice·OnlyOffice) 이건 왜 다른가

첫째, AI가 껍데기가 아니라 뼈대다. 대부분의 오피스에 붙은 "AI 도우미"는 옆 창에서 텍스트를 뱉는 챗봇이고, 문서에 반영하려면 사람이 복붙해야 한다. genoffice는 반대다 — AI가 문서 상태를 읽고(read_blocks), 블록을 갈아 끼우고(replace_blocks), 차트를 그리는(insert_chart) 툴을 직접 호출한다. 워크북·슬라이드·PDF 상태 위에서 도는 도구 호출 에이전트(tool-calling agent)가 각 앱에 내장돼 있다.

비유

말로 지시하는 비서 vs 손이 달린 비서. 보통의 오피스 AI는 "이렇게 고치면 어때요?" 하고 말만 하는 비서다 — 실제 수정은 당신 몫이다. genoffice의 AI는 손이 달려서 직접 문서의 그 문단을 지우고 새로 쓰고, 표에 수식을 넣고, 슬라이드에 차트를 꽂는다. 대신 무슨 짓을 했는지 스냅샷으로 남겨 한 번에 되돌릴 수 있게 해둔다.

둘째, 원본 보존이 곧 호환성이다. 실무에서 오픈소스 오피스가 외면받는 가장 큰 이유는 "워드로 만든 파일을 열었다 저장하면 서식이 틀어진다"는 것이다. genoffice의 바이트 보존 왕복은 이 지점을 정면으로 노린다. 손 안 댄 문단은 원본 XML 조각 그대로, 스타일·이미지·주석·수식은 zip 엔트리 그대로 복사하니, 회사에서 돌려보는 워드 파일을 깨뜨리지 않고 AI로만 고칠 수 있다. 테스트가 이걸 못 박는다 — "no edits → byte-identical output including comments.xml"(편집이 없으면 주석까지 포함해 바이트 동일).

이 레포의 강점
"직접 만든 포맷 엔진"이 주는 것들

남의 변환 라이브러리에 기대지 않고 docx·pptx 엔진을 직접 짰기에 얻는 것들 — 정밀 제어(문단 단위 패치, 추적 변경·잉크·수식 보존), 고충실도 렌더링(원본 레이아웃의 줄 metrics 재현), AI와의 결합(블록 트리가 곧 AI가 다루는 단위). 포맷을 손수 파싱했기에 "AI가 문서의 구조를 이해하고 좁게 편집"하는 게 가능해진다.

셋째, 다섯 앱이 한 엔진을 공유한다는 공학적 절제다. AI 에이전트 루프(agent-core), 모델 추상화(ai-provider), 검색(ai-search)을 패키지로 빼서 docs·sheets·slides·pdf가 똑같이 끼워 쓴다. 앱마다 AI를 새로 만들지 않고, 스킬(skill)이라는 플러그인으로 "이 앱에서 AI가 쓸 수 있는 툴 묶음"만 갈아 끼운다. 오피스 4종을 한 팀이 유지보수할 수 있는 구조적 비결이다.

주의
모델 호출은 Genspark 계정을 거친다

기본 설정에서 AI는 Genspark 계정으로 로그인해 모델 호출을 Genspark 서버로 라우팅한다(로컬에 API 키를 저장하지 않음). 오픈소스이고 Anthropic·Gemini·OpenAI 키를 직접 넣는 길도 열려 있지만, 편하게 쓰려면 회사 서비스에 묶인다는 뜻이다. 또 이 저장소는 내부 개발 저장소를 주기적으로 미러링한 "Sync snapshot"이라, 이슈·커밋 히스토리가 일반 OSS처럼 촘촘하지 않다.

3기술 스택 전체 지도

데스크톱 셸 · 편집기 · 포맷 엔진 · AI 계층을 각각

genoffice는 레이어가 뚜렷한 스택이다. 위에서부터 ① Electron 앱(셸+4 편집기), ② 각 편집기의 렌더러 UI(React), ③ 순수 TypeScript 포맷 엔진, ④ 공용 AI 계층, 그리고 sheets만 가진 ⑤ Rust 사이드카다.

레이어무엇쓰인 기술
데스크톱 셸앱 컨테이너·자동 업데이트·창 관리Electron, electron-utils(메인 프로세스 헬퍼)
Docs 편집기.docx 워드프로세서 UIReact, TipTap(스트리밍 편집기), 페이지네이션 뷰
Sheets 편집기.xlsx 표계산 UIReact, Univer 코어(Apache-2.0) + 자체 확장, Konva(차트)
Slides 편집기.pptx 프레젠테이션 UIReact, 자체 pptx 렌더러, HarfBuzz(harfbuzzjs) 텍스트 셰이핑
PDF 편집기PDF 뷰어·주석·서명pdf.js(렌더) + pdf-lib(편집)
포맷 엔진파일 파싱·생성·패치docx-engine·pptx-engine·pptx-render (fast-xml-parser, jszip)
xlsx 사이드카엑셀 import/export·재계산Rust: calamine(읽기) + IronCalc(수식) + quick-xml
AI 계층에이전트 루프·모델·검색agent-core, ai-provider(스트리밍), ai-search
공용 인프라다국어·UI 킷·최근파일i18n, ui(React 킷), project-store
용어
TipTap (팁탭)
ProseMirror 기반의 리치 텍스트 편집기 프레임워크. genoffice의 docs 앱이 이걸로 문서를 편집하고, 특히 스트리밍 — AI가 글자를 흘려보내면 실시간으로 화면에 반영 — 을 구현했다. 사람 편집과 AI 편집을 같은 편집기에서 dirty 추적으로 관리한다.
용어
Univer (유니버)
오픈소스 표계산 코어(Apache-2.0, dream-num/univer). genoffice sheets는 이 코어 위에 대규모 자체 확장(피벗·슬라이서·조건부 서식·수식 추적)을 얹었다. "표 UI는 검증된 오픈소스를 쓰되, 파일 왕복은 자체 엔진으로"라는 실용적 선택.
용어
OOXML (Office Open XML)
.docx·.xlsx·.pptx의 실제 정체. 사실 이 파일들은 zip으로 묶인 XML 뭉치다. .docx의 알맹이는 word/document.xml. genoffice의 포맷 엔진은 이 XML을 직접 파싱·생성·패치한다. fast-xml-parser로 읽고 jszip으로 zip을 풀고 다시 묶는다.
용어
HarfBuzz / 텍스트 셰이핑
글자를 실제 픽셀 위치로 배치하는 계산을 "셰이핑"이라 한다(합자·커닝·복잡한 문자체계). harfbuzzjs는 그 표준 엔진의 JS 포팅. slides가 이걸로 PPT의 글자 위치를 원본과 똑같이 재현한다 — 폰트 metrics는 opentype.js, 양방향 텍스트는 bidi-js.
용어
calamine · IronCalc (Rust)
calamine=Rust로 엑셀을 빠르게 읽는 라이브러리. IronCalc=Rust로 만든 스프레드시트 수식 계산 엔진. sheets는 이 둘을 묶은 Rust 사이드카(별도 프로세스)로 무거운 xlsx 파싱·재계산을 처리한다 — JS로 하면 느릴 일을 네이티브로 내린 것.

4아키텍처 심화 — 바이트 보존 패치와 공용 AI 엔진

전체 그림 → 핵심 패턴 3개(패치·에이전트·사이드카)

전체 구조 한눈에

다섯 앱은 각자 메인 프로세스(Node)렌더러(React UI)로 나뉜 Electron 앱이고, 셸이 이들을 탭으로 품는다. 앱마다 AI 패널이 있지만, 그 밑의 에이전트 루프·모델 호출은 공용 패키지를 공유한다.

┌──────────────────────── apps/shell (GenOffice 런처) ─────────────────────────┐ │ 홈 화면 · 탭 호스팅 · 자동 업데이트 │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ apps/docs │ │ apps/sheets│ │ apps/slides│ │ apps/pdf │ ← 각각 독립 앱 │ │ │ (.docx) │ │ (.xlsx) │ │ (.pptx) │ │ (PDF) │ │ │ │ │ │ │ │ │ │ │ │ │ │ [AI 패널] │ │ [AI 패널] │ │ [AI 패널] │ │ [AI 패널] │ ← 같은 UI │ │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │ │ │ │ │ │ │ docx-engine Univer+Rust pptx-engine pdf.js+ │ │ (블록패치) 사이드카 pptx-render pdf-lib ← 앱별 포맷 엔진 │ │ │ │ │ │ │ │ └──────────────┴──────┬───────┴──────────────┘ │ │ ▼ │ │ ┌───────── 공용 AI 계층 (packages) ──────────┐ │ │ │ agent-core (에이전트 루프 + 스킬 합성) │ │ │ │ ai-provider (모델 추상화 + 스트리밍) │ │ │ │ ai-search (Genspark 인증 + 웹/이미지) │ │ │ └───────────────────┬────────────────────────┘ │ └────────────────────────────┼─────────────────────────────────────────────────┘ ▼ Genspark 서버 프록시 → Claude / GPT / Gemini (로컬에 API 키 저장 안 함; 직접 키 입력도 선택 가능)

핵심 패턴 ① — 바이트 보존 패치 (docx-engine)

이 레포의 심장이다. 발상은 "원본은 진실, 편집은 좁은 조각 교체". 파싱 단계에서 문단마다 docxIndex(원본에서 몇 번째 요소인가)와 원본 XML 조각을 앵커로 달아둔다. 저장할 때 이 앵커를 기준으로, dirty가 아닌 블록은 원본 조각을 그대로 쓰고 dirty 블록만 새 OOXML로 만든다.

# SaveBlock — 저장할 때 각 블록이 취하는 4가지 형태 (patch.ts)
{ kind: 'original', docxIndex }        # 원본 조각 그대로 복사 (안 건드림)
{ kind: 'generated', block }            # 편집기가 고친 블록 → 새 OOXML 생성
{ kind: 'xml', xml, docxIndex }        # 편집기가 만든 자립 조각(새 표 등)
{ kind: 'image' | 'chart', ... }       # 새 이미지·차트 → media/relationship 추가

generated 블록은 "이미 있는 스타일만 참조"한다는 규칙을 지킨다 — AI가 멋대로 새 서식 정의를 만들어 원본 스타일 표를 오염시키지 않도록. 그리고 saveDocx는 바뀐 조각을 원본 document.xml에 스플라이스한 뒤, zip의 다른 모든 엔트리(스타일·이미지·주석·테마·잉크·수식)를 바이트 단위로 복사해 재압축한다. 테스트가 이 불변식을 촘촘히 지킨다 — "편집 없으면 comments.xml까지 바이트 동일", "손 안 댄 bidi 문단 바이트 동일", "cross-paragraph 범위의 마커 보존" 등.

비유

포토샵 레이어 vs 사진 재촬영. 사진을 고칠 때 원본 위에 레이어 하나만 얹어 그 부분만 바꾸면 원본 픽셀은 그대로다. 반대로 사진을 다시 찍으면(재렌더링) 미세하게 다 달라진다. genoffice는 레이어 방식이라, "고친 곳"과 "원본 그대로"가 명확히 분리된다.

핵심 패턴 ② — 공용 에이전트 루프 (agent-core)

모든 앱이 공유하는 AI의 두뇌. 순수 TypeScript(Electron 의존 없음)이고, "스킬"이라는 플러그인으로 앱별 능력을 끼운다. 눈여겨볼 설계가 세 가지다.

용어
에이전트 스킬 (AgentSkill)
AI에게 "이 앱에서 뭘 할 수 있는지"를 한 묶음으로 준 것. 시스템 프롬프트·툴 정의·매 턴 붙일 컨텍스트(문서 뼈대+선택 영역)·툴 실행 함수로 구성된다. docs는 get_document_context·read_blocks·replace_blocks·insert_chart 등 10개 툴을 스킬로 노출한다.

핵심 패턴 ③ — Rust xlsx 사이드카 (apps/sheets/native)

엑셀은 수만 행·복잡한 수식이 흔해 JS만으로는 버겁다. sheets는 무거운 일을 별도 Rust 프로세스(사이드카)로 내린다. JS와는 stdin/stdout에 한 줄씩 JSON을 주고받는 라인 프로토콜로 통신하고, 세션(sessionId)으로 열린 워크북 상태를 유지한다.

# xlsx 사이드카가 받는 명령들 (main.rs, JSON 라인 프로토콜)
Open          # 워크북 열기 → sessionId 발급
ReadRange     # 특정 시트의 셀 범위 읽기
RecalcCells   # 편집한 셀 기준 수식 재계산 (IronCalc)
ConvertWorkbook / SaveArchive   # 포맷 변환 · 저장
ScanEntries / ReadMedia / ArchiveManifest   # zip 내부 탐색·미디어

여기서도 "원본 보존" 철학이 반복된다 — 테스트 이름이 그대로 증거다: "preserves unrelated workbook parts and updates Sheet1 in place"(관련 없는 워크북 부분은 보존하고 Sheet1만 제자리 갱신). 문서든 표든, 건드린 곳만 바꾸고 나머지는 원본 그대로가 이 레포 전체를 관통하는 하나의 원칙이다.

5디렉토리 구조 해부

모노레포 어디에 무엇이 있나 (줄 수 = 규모 감각)
genoffice/ ├─ apps/ ← 5개 Electron 앱 (각 main + renderer) │ ├─ sheets/ ~99,600줄 가장 큼. native/ 에 Rust xlsx 사이드카 포함 │ │ ├─ native/xlsx-engine/ Rust: calamine + IronCalc (7개 .rs) │ │ └─ src/renderer/ai/prompts/guides/ 차트·피벗·서식 등 11개 AI 가이드(.md) │ ├─ slides/ ~69,000줄 자체 pptx 렌더/편집 엔진 │ ├─ docs/ ~63,800줄 TipTap 편집기 + docs AI 스킬 │ │ └─ src/renderer/ai/ docs-skill · tools · AiPanel │ ├─ pdf/ ~10,100줄 pdf.js + pdf-lib │ └─ shell/ ~9,000줄 런처 · 탭 · 자동 업데이트 │ ├─ packages/ ← 11개 공용 엔진 (순수 TS, Electron 무의존) │ ├─ pptx-engine/ ~22,800줄 pptx 모델 (fast-xml-parser, jszip) │ ├─ docx-engine/ ~19,000줄 ★ 바이트 보존 패치의 본체 │ │ ├─ parse.ts generate.ts patch.ts 파싱 → 생성 → 패치 │ │ ├─ chart.ts math.ts ink.ts notes.ts 차트·수식·잉크·주석 │ │ └─ theme.ts section.ts watermark.ts 테마·구역·워터마크 │ ├─ pptx-render/ ~6,900줄 EMU→px 좌표계, RenderTree (opentype.js) │ ├─ project-store/ ~1,800줄 최근 파일 저장소 │ ├─ agent-core/ ~1,640줄 ★ 에이전트 루프 + 스킬 (loop·skill·types) │ ├─ ai-provider/ ~1,400줄 모델 추상화 (chat·stream·providers) │ ├─ ai-search/ ~1,000줄 Genspark 인증 + 웹/이미지 검색 │ ├─ file-parse/ ~700줄 AI 첨부용 텍스트 추출 (pdfjs-dist) │ ├─ electron-utils · i18n · ui 메인 프로세스 헬퍼 · 다국어 · React 킷 │ ├─ ee/ 엔터프라이즈 예약 디렉토리 (현재 비어 있음, 별도 라이선스) ├─ e2e/ Playwright + Electron 통합 테스트 ├─ fixtures/ 테스트용 .docx 등 픽스처 ├─ tools/ 서드파티 고지 생성 · 라이선스 검사 · 포맷 └─ scripts/ 로컬 UI/e2e 드라이버 (Playwright)

읽는 순서를 추천하면 이렇다: README → package.json(스크립트·워크스페이스) → packages/docx-engine/src/patch.ts(바이트 보존의 핵심) → packages/agent-core/src/loop.ts·skill.ts(AI 루프) → apps/docs/src/renderer/ai/(엔진이 앱에서 어떻게 쓰이는지). 엔진 패키지는 UI가 없어 단위 테스트만으로 동작을 이해할 수 있으니, 각 *.test.ts가 훌륭한 명세서가 된다.

6학습 포인트 — 기술별 배울 것

이 레포에서 실제로 뽑아 갈 수 있는 지식

1) OOXML 파일 포맷의 실체

docx·xlsx·pptx가 "zip 안의 XML"이라는 사실과, 그걸 다루는 실전 코드를 볼 수 있다. jszip으로 풀고 fast-xml-parser로 파싱해 word/document.xmlw:p(문단)·w:tbl(표)를 다루는 흐름은, 오피스 자동화·문서 생성 도구를 만들 때 그대로 쓰인다. 배울 것: 왜 문서 편집이 "XML 조각 스플라이스"가 되는가, relationship·media·styles가 어떻게 얽히는가.

2) 원본 보존 패치라는 설계 사상

"전체 재생성" 대신 "dirty만 재생성 + 나머지 원본 복사"라는 불변식 중심 설계. 이건 문서 편집에만 국한되지 않는다 — 코드 포매터, 마이그레이션 도구, 설정 파일 편집기 등 "사람이 만든 원본을 최소한만 건드려야 하는" 모든 곳에 적용되는 사고법이다. 배울 것: 앵커(docxIndex) 기반 재조립, "손 안 댄 건 바이트 동일"을 테스트로 못 박는 방법.

3) 도구 호출 에이전트 루프를 직접 구현하기

agent-core는 LangChain 같은 프레임워크 없이 에이전트 루프를 밑바닥부터 짠 좋은 교보재다. 턴 제한(기본 8), 이력 제한(40), 바이트 예산 압축, 툴 입력 파싱 실패 재시도(최대 3), 스냅샷/롤백, 스트리밍 이벤트까지 — 실전 에이전트에 필요한 안전장치와 자원 관리가 응축돼 있다. 배울 것: 왜 메시지 개수가 아니라 바이트로 컨텍스트를 재는가, 스킬 합성으로 앱별 능력을 어떻게 조립하는가.

4) 성능이 필요한 곳에 네이티브(사이드카) 붙이기

JS 앱이 무거운 연산(엑셀 파싱·수식)을 Rust 사이드카로 내리고 JSON 라인 프로토콜로 통신하는 패턴. Electron/Node 앱에서 성능 병목을 우회하는 실전 아키텍처다. 배울 것: 프로세스 간 라인 프로토콜 설계, 세션 기반 상태 관리, JS↔Rust 경계 나누기.

5) 고충실도 렌더링과 텍스트 셰이핑

slides가 opentype.js(폰트 metrics)·harfbuzzjs(셰이핑)·bidi-js(양방향)로 PPT 글자를 원본과 똑같이 배치하고, pptx-renderEMU→px 좌표계와 데이터 기반 RenderTree로 도형·채우기·선을 그린다. 배울 것: 문서 좌표계 변환, 폰트 metrics로 줄바꿈 계산하기, Konva 같은 캔버스 라이브러리를 얇게 감싸기.

실습 아이디어(가벼운 것)
엔진만 떼서 Node 스크립트로 돌려보기

packages의 엔진은 Electron 무의존 순수 TS다. docx-engine을 import해 샘플 .docx를 파싱→블록 트리 출력→한 문단만 바꿔 저장한 뒤, 원본과 diff로 비교해 "정말 그 문단만 바뀌었는지" 눈으로 확인해 보라. npm run fixtures로 테스트 .docx를 생성할 수 있고, 각 *.test.ts가 사용 예시다.

7시스템 / 빌드 요구사항

써보려면 · 소스에서 빌드하려면
구분요구
실행(사용자)macOS(Apple Silicon) 서명된 .dmg 또는 Windows(x64) .exe 설치. 릴리스 페이지에서 내려받아 설치.
AI 사용Genspark 계정 로그인(기본) 또는 Anthropic/Gemini/OpenAI API 키 직접 입력.
개발 — 공통Node.js ≥20, npm ≥10. npm installnpm run dev(4 편집기 + 셸 동시 실행, Vite 개발 서버).
개발 — sheets추가로 Rust 툴체인(cargo on PATH). npm run build -w @genoffice/sheets가 xlsx 사이드카를 자동 컴파일.
테스트npm test(엔진+앱 단위 테스트; docs/sheets/slides는 디스플레이 불필요), npm run typecheck, npm run test:e2e(Playwright).
패키징npm run dist:mac(dmg) / npm run dist:win(nsis). 빌드 시 서드파티 라이선스 고지 자동 재생성.

번들 폰트(Liberation·Carlito·Caladea·Noto CJK 서브셋)는 OFL/Apache, 런타임 의존성은 전부 MIT/Apache-2.0/OFL로 정리돼 있다 — 상업적 재배포까지 염두에 둔 라이선스 위생이다. 다만 ee/ 디렉토리만은 별도의 GenOffice Enterprise License이고 외부 기여를 받지 않는다(CODEOWNERS로 강제).

주의
"Sync snapshot" 저장소의 성격

이 저장소는 내부 개발 저장소를 주기적으로 통째 미러링한 것이라(최신 커밋도 "Sync snapshot (2026-08-03)"), 일반 OSS처럼 세밀한 커밋 단위 히스토리나 활발한 이슈 트래킹을 기대하긴 어렵다. 코드를 읽고 배우는 데는 최상급이지만, "기여해서 머지받기"의 협업 흐름은 제한적일 수 있다.

8직접 해볼 수 있는 실습 과제

난이도별 — 손으로 만지며 이해하기
과제 1 · 입문난이도 ★☆☆☆☆

.docx가 zip이라는 걸 손으로 확인

아무 워드 파일의 확장자를 .zip으로 바꿔 압축을 풀어 보라. word/document.xml을 열어 <w:p>(문단)·<w:r>(런)·<w:t>(텍스트)를 눈으로 찾아본다. 그런 뒤 genoffice의 docx-engine/src/parse.ts가 바로 이 요소들을 어떻게 블록으로 바꾸는지 대조한다. 목표: "문서 편집 = XML 편집"을 체감.

과제 2 · 기초난이도 ★★☆☆☆

엔진 단독 실행 + 바이트 diff

레포를 클론해 npm installnpm run fixtures로 테스트 .docx 생성. 작은 Node 스크립트에서 docx-engine으로 파일을 파싱하고, 문단 하나의 텍스트만 바꿔 저장한 뒤, 원본과 저장본을 unzipdiff -r로 비교하라. 목표: "정말 바뀐 파트만 달라지고 나머지는 동일"함을 직접 확인.

과제 3 · 중급난이도 ★★★☆☆

agent-core 루프에 나만의 스킬 끼우기

agent-coreAgentSkill 인터페이스를 구현해 아주 단순한 스킬(예: "문서의 단어 수를 세는 count_words 툴")을 만든다. composeSkills로 기존 스킬과 합쳐 루프에 넣고, 툴 호출→실행→응답이 도는 걸 로그로 관찰하라. 목표: 도구 호출 에이전트의 최소 골격을 손에 익히기.

과제 4 · 심화난이도 ★★★★☆

Rust 사이드카 프로토콜 흉내 내기

apps/sheets/native/xlsx-engine/src/main.rs의 JSON 라인 프로토콜(Open/ReadRange/RecalcCells)을 읽고, 작은 Rust(또는 Node) 프로그램으로 stdin에서 JSON 한 줄을 읽어 처리하고 stdout으로 응답하는 사이드카를 직접 만들어 본다. 세션 상태를 HashMap<sessionId, ...>로 유지하라. 목표: 프로세스 간 라인 프로토콜과 세션 설계 이해.

과제 5 · 도전난이도 ★★★★★

"바이트 보존"을 깨는 최소 반례 찾기

docx-engine의 테스트를 읽고, 어떤 편집이 "손 안 댄 부분까지 바뀌게" 만드는지 가설을 세워 실험하라(예: 특정 필드·잉크·수식이 섞인 문단). 실패 케이스를 *.test.ts 형식의 테스트로 재현해 본다. 목표: 불변식이 어디서 깨지는지 파고들며 포맷의 엣지 케이스를 학습.

9관련 기술 심화 로드맵 (주차별)

이 레포를 온전히 소화하려면 무엇을 순서대로 볼까
주차주제구체적으로
1주차OOXML 포맷 기초docx/xlsx/pptx의 zip+XML 구조, ECMA-376 개요, jszip·fast-xml-parser로 파싱 실습. genoffice parse.ts 읽기.
2주차원본 보존 패치patch.ts·generate.ts 정독. 앵커 기반 재조립, SaveBlock 4형태, "스타일은 참조만" 규칙. 관련 *.test.ts로 불변식 확인.
3주차Electron 앱 구조메인/렌더러/프리로드 분리, IPC, 자동 업데이트. shell이 4앱을 탭으로 호스팅하는 방식. 렌더러 보안(sandbox)·SECURITY.md.
4주차리치 텍스트 편집기ProseMirror/TipTap 모델, 문서 스키마, 스트리밍 편집·dirty 추적. docs 앱의 편집기 연동 코드.
5주차도구 호출 에이전트agent-core loop·skill·types 정독. 턴/이력/바이트 예산, 스냅샷 롤백, 스트리밍. ai-provider의 모델 추상화·스트리밍.
6주차네이티브 사이드카Rust calamine·IronCalc, JSON 라인 프로토콜, 세션 상태. JS↔Rust 경계 설계와 빌드 연동(cargo).
7주차렌더링·텍스트 셰이핑pptx-render의 EMU→px, RenderTree, opentype.js metrics·harfbuzzjs 셰이핑·bidi-js. Konva 캔버스.
8주차통합·패키징·라이선스Playwright e2e, dist:mac/win, 서드파티 고지 자동화, OFL/Apache 폰트, ee/ 라이선스 경계.

10핵심 키워드 사전

이 문서에 나온 용어 빠른 복습
용어
바이트 보존 왕복
열기→편집→저장에서 손 안 댄 부분이 원본과 바이트 단위로 동일하게 남는 것. genoffice의 핵심 원칙이자 최대 차별점. 테스트로 못 박혀 있다.
용어
OOXML / document.xml
.docx·.xlsx·.pptx의 실체 = zip+XML. .docx 본문은 word/document.xml. 포맷 엔진이 이 XML의 w:p·w:tbl을 직접 다룬다.
용어
docxIndex 앵커
각 블록이 원본에서 몇 번째 요소인지 가리키는 표식. 저장 시 이 앵커로 "원본 조각 복사 vs 새로 생성"을 구분해 좁은 패치를 완성한다.
용어
SaveBlock
저장할 블록의 4가지 형태: original(원본 복사)·generated(새 OOXML)·xml(자립 조각)·image/chart(새 미디어). 대부분은 original로 남아 원본이 보존된다.
용어
AgentSkill / composeSkills
AI의 앱별 능력 묶음(프롬프트+툴+컨텍스트+실행기). composeSkills가 여러 스킬을 합치되 툴 이름 충돌은 에러로 막는다. 다섯 앱이 같은 루프에 다른 스킬을 끼운다.
용어
컨텍스트 압축(compaction)
대화 이력을 UTF-8 바이트 예산(기본 256KB)으로 관리하고, 넘치면 LLM 요약+기계 다이제스트로 줄이는 것. 최근 96KB는 사용자 경계에서 보존.
용어
스냅샷 롤백
AI 툴이 문서를 바꾸기 직전 상태를 찍어, 수정을 한 번에 되돌릴 수 있게 하는 안전장치(snapshotBefore). "손 달린 AI"의 필수 장치.
용어
Rust 사이드카
무거운 xlsx 파싱·수식 재계산을 맡는 별도 Rust 프로세스. JS와 stdin/stdout JSON 라인 프로토콜로 통신, 세션으로 워크북 상태 유지. calamine+IronCalc.
용어
텍스트 셰이핑 / HarfBuzz
글자를 실제 픽셀 위치로 배치하는 계산(합자·커닝·복잡 문자). slides가 harfbuzzjs+opentype.js+bidi-js로 PPT 글자 배치를 원본과 똑같이 재현.
용어
Univer
오픈소스 표계산 코어(Apache-2.0). sheets가 이 UI 코어 위에 피벗·슬라이서·조건부 서식 등 자체 확장을 얹었다. 파일 왕복은 자체 엔진+Rust 사이드카가 담당.

11참고 링크

더 파고들 때