이 저장소가 대체 무엇인가.
OfficeCLI는 "AI 에이전트를 위해 처음부터 설계된 오피스 문서 자동화 도구"를 표방하는 커맨드라인 프로그램이다. officecli add deck.pptx / --type slide --prop title="Q4 Report" 한 줄로 슬라이드를 추가하고, officecli view report.docx html로 문서를 브라우저에 그려 보여준다. 지금까지 파이썬 python-pptx로 50줄 짜야 했던 일을 명령 한 줄로 대체하는 것이 목표다.
보통 AI가 문서를 만들 때는 눈을 감고 타자를 치는 것과 같다 — XML 태그를 조립할 뿐, 실제로 슬라이드가 어떻게 보이는지는 알 수 없다. 제목이 화면 밖으로 넘쳐도, 두 도형이 겹쳐도 모른다.
OfficeCLI는 조수에게 "손"(경로 기반 편집 명령)과 "눈"(내장 HTML/PNG 렌더러)을 함께 쥐여준다. 만든 뒤 view screenshot으로 완성본을 그려 AI에게 보여주고, AI는 "아, 제목이 잘렸네" 하고 스스로 고친다. 오피스가 없는 리눅스 서버·도커 안에서도 이 보고-고치기 루프가 그대로 돈다.
구현은 C#/.NET 10 단일 프로젝트다. OOXML(오피스 파일의 내부 XML 포맷)을 다루는 마이크로소프트 공식 라이브러리 DocumentFormat.OpenXml과 명령줄 파서 System.CommandLine — 딱 두 개의 외부 의존성만으로, 350개 이상의 엑셀 함수 계산기·피벗 엔진·차트/수식/다이어그램 렌더러까지 전부 바이너리 안에 넣었다. 라이선스는 관대한 Apache 2.0이며, 제작사는 자연어로 오피스를 다루는 데스크톱 앱 AionUi도 함께 운영한다.
OfficeCLI가 흥미로운 건 기능 개수가 아니라 설계 철학이다. 경로 기반 주소(/slide[1]/shape[2]) · 3단계 계층 API(읽기→DOM→raw XML) · 결정적 JSON 출력 · 자기교정(self-healing) 에러 · 상주 프로세스(named pipe)로 지연 감추기 · 렌더링을 통한 시각 피드백 루프 — 이 모든 것이 "사람이 아니라 LLM이 쓴다"는 전제 하나에서 도출된다. AI 에이전트용 도구를 만들려는 개발자에게 이보다 밀도 높은 참고서는 드물다.
README의 "world's first and the best"는 검증된 사실이 아니라 자기 주장이다(유사 도구로 python-docx/openpyxl, 그리고 마이크로소프트 자체 Office Scripts·Graph API가 있다). 또한 officecli install은 감지된 모든 AI 도구(Claude Code·Cursor·Copilot…)에 스킬 파일을 자동 주입하고, 업데이트를 백그라운드에서 확인한다 — 편리하지만 무엇을 어디에 쓰는지 알고 켜야 한다(OFFICECLI_SKIP_UPDATE=1로 끌 수 있음). 별점·다운로드 수는 신뢰 불가로 인용하지 않았다.
트렌딩 이유와, 기존 오피스 자동화 도구(python-pptx·openpyxl) 대비 결정적 차이.
기존 문서 라이브러리의 치명적 약점은 피드백 부재였다. python-pptx로 슬라이드를 만들면 AI는 XML을 쓸 뿐, 결과가 어떻게 보이는지 알 방법이 없다. OfficeCLI는 from-scratch로 만든 HTML 렌더링 엔진을 바이너리에 내장해, view screenshot 한 번으로 문서를 PNG로 그려낸다. 멀티모달 AI는 그 이미지를 읽고 "제목이 넘쳤다"를 스스로 판단해 고친다. 도형·차트(추세선·오차막대·워터폴·캔들스틱)·수식(KaTeX)·3D 모델(Three.js)·모프 전환까지 렌더한다.
python-pptx = 안대를 쓴 채 그림 그리기. 붓질(코드)은 하지만 캔버스는 못 본다.
OfficeCLI = 거울을 보며 화장하기. 한 번 바르고 거울(렌더러)로 확인하고 다시 고친다. 이 "확인" 단계가 완성도를 결정적으로 끌어올린다.
파이썬 기반 자동화는 늘 pip install·가상환경·버전 충돌에 시달린다. OfficeCLI는 .NET 런타임까지 통째로 박은 self-contained single-file 바이너리다. 다운로드해서 바로 실행하면 된다. 오피스도, 파이썬도, 어떤 런타임도 설치할 필요가 없어 도커·CI·헤드리스 서버에 그대로 얹힌다. AI 에이전트 입장에서는 "환경 구축"이라는 가장 큰 마찰이 사라진다.
OfficeCLI의 명령은 전부 경로 + 속성 꼴이다. /slide[1]/shape[2]처럼 1-based 인덱스에 요소 이름을 쓰는 직관적 경로(XML 네임스페이스를 몰라도 됨), 모든 명령에 --json 일관 출력, not_found·invalid_value 같은 구조화된 에러 코드 + 수정 제안. AI가 "추측 → 실패 → 재시도"를 반복하지 않고, 에러 메시지만 보고 스스로 교정한다. 이 "self-healing" 설계가 토큰 낭비를 크게 줄인다.
merge 명령은 {{key}} 자리표시자가 든 템플릿에 JSON 데이터를 부어 문서를 양산한다. dump는 기존 문서(사람이 만든 예쁜 샘플)를 재생 가능한 batch JSON으로 역직렬화한다. AI가 레이아웃을 비싸게 한 번 설계하면, 이후 생산 코드가 싸고·결정적으로·토큰 0원에 N개를 찍어낸다. "매번 처음부터 다시 생성해 제각각인 N개"라는 실패 모드를 피한다.
무엇으로 만들었는가 — 런타임·의존성·내장 엔진.
| 항목 | 내용 · 왜 이 선택인가 |
|---|---|
| 언어 | C# / .NET 10 (net10.0). ImplicitUsings + Nullable 활성. 소스는 C# 단일 프로젝트 하나에 약 340개 이상의 .cs 파일 |
| 배포 형태 | PublishSingleFile=true + SelfContained=true + PublishTrimmed=true → 런타임 포함 단일 실행 파일. 사용자는 .NET을 설치할 필요 없음 |
| 타깃 플랫폼 | Win x64/ARM64 · macOS x64(Intel)/ARM64(Apple Silicon) · Linux x64/ARM64 — 6종 바이너리 |
| 배포 채널 | GitHub Releases 직접 다운로드 · Homebrew · Scoop · npm(@officecli/officecli, 네이티브 바이너리 페치) |
거대한 기능량에 비해 NuGet 외부 패키지가 단 2개다. 나머지는 전부 자체 구현했다는 뜻 — 이것이 "단일 바이너리·무의존"을 가능케 한 설계의 근간이다.
| 패키지 | 역할 |
|---|---|
| DocumentFormat.OpenXml 3.4.1 | 마이크로소프트 공식 OOXML SDK. .docx/.xlsx/.pptx의 내부 XML을 안전하게 읽고 쓰는 저수준 토대 |
| System.CommandLine 3.0 (preview) | 명령·옵션·인자 파싱. officecli <verb> <file> <path> --prop ... 구문 처리 |
.csproj의 <EmbeddedResource>를 보면 이 도구가 무엇을 스스로 짊어졌는지 드러난다 — 렌더링용 CSS/JS, KaTeX 자산, 차트 스타일 XML, PPT 애니메이션 효과 템플릿, 도움말 스키마(JSON), 그리고 11종의 스킬 파일까지 전부 어셈블리 안에 포함된다. 디스크에 풀지 않고 Assembly.GetManifestResourceStream으로 직접 읽어 "설치 파일은 .exe 하나뿐"을 지킨다.
| 내장 엔진 | 하는 일 |
|---|---|
| HTML 렌더링 엔진 | OOXML → 고정밀 HTML. 도형·차트·수식·3D·전환·효과까지. 이 엔진이 프로젝트의 keystone |
| PNG 스크린샷 | 렌더된 HTML을 헤드리스 브라우저로 파이프해 페이지별 PNG 생성(멀티모달 AI용) |
| 수식 엔진 | OMML(오피스 수식 XML) ↔ LaTeX 변환, KaTeX로 렌더. Word/PPT 모두 LaTeX 입력 지원 |
| 공식(Formula) 엔진 | 350개 이상 엑셀 함수를 쓰는 즉시 자동 계산. 스필 동적 배열·재무/채권·통계·회귀 함수 포함 |
| 피벗 엔진 | 소스 범위 → 네이티브 OOXML 피벗테이블(다중 필드·날짜 그룹·계산 필드·top-N). 캐시까지 써서 엑셀이 열면 집계가 이미 채워져 있음 |
| 다이어그램 | Mermaid → PPT/Word 네이티브 편집 가능 도형, 또는 임의 Mermaid를 고정밀 PNG로 |
| 차트 렌더 | 파레토(자동정렬+누적%)·박스휘스커·워터폴·캔들스틱·스파크라인·로그축 등 |
핵심 설계 패턴 5가지 — 왜 이렇게 만들었는가.
OfficeCLI 명령은 추상화 높이가 다른 3층으로 나뉜다. AI는 위층(싸고 안전)부터 쓰고, 필요할 때만 아래층(강력하지만 위험)으로 내려간다 — 토큰과 실수를 동시에 줄이는 구조다.
| 계층 | 목적 | 명령 |
|---|---|---|
| L1 읽기 | 내용의 의미적 뷰 | view (text·annotated·outline·stats·issues·html·svg·screenshot) |
| L2 DOM | 요소 단위 구조 편집 | get·query·set·add·remove·move·swap |
| L3 raw XML | XPath 직접 접근(만능 폴백) | raw·raw-set·add-part·validate |
병원과 같다. L1=문진("어디가 아파요?" — 요약을 본다). L2=처방·시술(장기 단위로 고친다). L3=수술(XML을 직접 연다 — 강력하지만 위험). 환자를 바로 수술대에 눕히지 않듯, AI도 웬만하면 L1/L2에서 끝내게 유도한다.
모든 요소에 /slide[1]/shape[2] 같은 안정적 경로가 있다. 진짜 XPath가 아니라 1-based 인덱스 + 요소의 로컬 이름을 쓰는 단순화된 문법이다. AI가 w:·a: 같은 XML 네임스페이스를 이해하지 않아도 문서를 항해할 수 있다. 엑셀은 /Sheet1/A1이나 $Sheet:A1, row[Salary>5000 and Region=EMEA] 같은 불리언 선택자까지 지원한다.
문서를 열 때마다 디스크에서 파싱하면 다단계 편집이 느리다. OfficeCLI는 첫 접근 시 자동으로 상주 프로세스를 띄워 문서를 메모리에 붙잡아 둔다. 이후 명령들은 named pipe(이름 있는 파이프)로 그 상주에게 요청을 보내 파일 I/O 없이 처리한다. ResidentServer.cs의 설계가 특히 정교하다:
_handler.Dispose() 이후에 취소한다. 덕분에 "ping이 응답한다 = 파일이 잠겨 있다"는 불변식이 성립 → 클라이언트가 상주와 직접 접근 사이에서 race에 걸려도 항상 재시도 가능한 "busy" 에러로 안전하게 귀결된다. create는 60초, open은 12분 idle 타임아웃(핑 명령으로 승격).상주는 편집을 메모리에 두고 디스크 쓰기를 미룬다. OfficeCLI 자신의 get/query/view는 항상 최신을 보지만, python-docx·Word·업로드 같은 외부 프로그램이 읽기 전에는 save(상주 유지) 또는 close(flush+해제)로 디스크에 내려야 한다. idle 몇 초 뒤 자동 flush되고, OFFICECLI_RESIDENT_FLUSH=each로 매 변경마다 즉시 flush하게 할 수도 있다.
보통 엑셀 파일에 수식만 써 넣으면 값은 비어 있다 — 오피스가 열어서 재계산해야 채워진다. OfficeCLI는 =SUM(A1:A2)를 쓰는 순간 자체 공식 엔진이 즉시 계산해 값까지 기록한다. FILTER/SORT/UNIQUE/LET/LAMBDA 같은 스필 동적 배열은 _xlfn. 접두사를 자동으로 붙이고, 행/열 삽입 시 수식 참조를 자동으로 재작성한다. 피벗도 캐시+정의를 OOXML에 함께 써서 "엑셀이 열자마자 집계 완료" 상태를 만든다.
4번까지가 "손"이라면 이건 "눈"이다. view html(자산 인라인된 독립 HTML)·view screenshot(페이지별 PNG)·watch(자동 새로고침 로컬 HTTP 서버)의 세 모드로 AI가 결과를 확인한다. 특히 watch는 add/set/remove가 실행될 때마다 브라우저를 즉시 갱신하고(엑셀은 셀 인라인 편집·차트 드래그 이동까지), Core/Watch/의 SSE(Server-Sent Events) 기반으로 구현됐다. 디스플레이 없는 서버·도커에서도 이 루프가 돌아가는 게 결정적이다.
폴더만 봐도 설계 의도가 읽힌다.
ExcelHandler 하나가 .Add.Cells·.Set.Charts·.Query.Cf·.Pivot처럼 40개 이상의 파일로 분할돼 있다. 이는 기능이 방대할 때 한 클래스를 기능축으로 나눠 관리하는 C# 특유의 partial class 패턴이다. 새 기능을 추가할 때 기존 파일을 건드리지 않고 새 부분 파일만 더하면 되므로, 방대한 오피스 기능을 점진적으로 쌓아 올리기에 적합하다. Core/와 Handlers/의 분리(공용 엔진 vs 포맷별 실행기)도 교과서적이다.
이 레포에서 실제로 배울 수 있는 것들.
OfficeCLI는 "사람이 아니라 LLM이 쓰는 CLI"의 모범 사례다. 결정적 JSON 출력(--json 일관 스키마), 경로 기반 주소, 3단계 점진적 복잡도, 구조화 에러 코드+수정 제안(self-healing), 내장 도움말(officecli help docx paragraph로 속성명을 추측 대신 조회) — 이 다섯이 "에이전트 친화적 도구"의 핵심 축이다. 자신의 도구를 AI가 쓰게 만들려는 개발자라면 이 패턴을 그대로 훔쳐 쓸 수 있다.
.docx/.xlsx/.pptx는 사실 ZIP으로 압축된 XML 묶음(OOXML)이다. OfficeCLI는 마이크로소프트 공식 SDK 위에서 이걸 다룬다. 파일 하나를 dump로 떠서 batch JSON을 들여다보면 오피스 파일의 내부 구조가 한눈에 보인다 — 워드의 w:p(문단)/w:r(런), 엑셀의 워크시트/셀/공유문자열, PPT의 슬라이드/셰이프 트리.
PublishSingleFile+SelfContained+PublishTrimmed로 런타임까지 박은 단일 실행 파일을 만드는 실전 예다. 임베디드 리소스(Assembly.GetManifestResourceStream)로 CSS·스킬·스키마를 바이너리에 넣어 "설치 파일은 exe 하나"를 지키는 기법도 배울 수 있다.
ResidentServer.cs는 프로세스 간 통신(IPC)·idle 타임아웃·우아한 종료·race-safe 폴백을 실전 수준으로 보여준다. 특히 "두 개의 CancellationTokenSource로 ping 생존성과 파일 잠금을 연동"하는 부분은 동시성 설계의 좋은 사례다.
OOXML → HTML → (헤드리스 브라우저) → PNG로 이어지는 파이프라인, 그리고 그 이미지를 다시 AI에게 먹여 결과를 검증하는 에이전트 자기교정 루프는 요즘 AI 에이전트 설계의 최전선 주제다.
1. officecli create deck.pptx → watch로 브라우저를 띄워 두고 다른 터미널에서 add를 날려 실시간 갱신을 눈으로 확인한다.
2. 아무 .docx나 dump로 떠서 batch JSON을 열어 본다 — OOXML 구조가 사람이 읽을 수 있는 형태로 보인다.
3. officecli help xlsx chart --json으로 도구가 AI에게 스키마를 어떻게 노출하는지 관찰한다.
무엇이 필요하고, 어떻게 까는가.
| 항목 | 내용 |
|---|---|
| OS | Windows(x64/ARM64) · macOS(Intel/Apple Silicon) · Linux(x64/ARM64) |
| 런타임 | 불필요 — .NET이 바이너리에 임베드됨. 오피스도, 파이썬도 필요 없음 |
| 디스플레이 | 불필요 — 렌더링이 헤드리스로 동작(서버·도커·CI OK) |
| 스크린샷 기능 | view screenshot은 헤드리스 브라우저 파이프를 사용(환경에 따라 브라우저 자산 필요할 수 있음) |
| 설정 위치 | ~/.officecli/config.json · 업데이트 자동 확인(끄기: config autoUpdate false) |
# macOS / Linux — 원라인
curl -fsSL https://raw.githubusercontent.com/iOfficeAI/OfficeCLI/main/install.sh | bash
# Windows (PowerShell)
irm https://raw.githubusercontent.com/iOfficeAI/OfficeCLI/main/install.ps1 | iex
# 패키지 매니저
brew install officecli # Homebrew
scoop install officecli # Scoop (Windows)
npm install -g @officecli/officecli # npm (플랫폼 바이너리 페치)
officecli --version # 설치 확인
officecli install(또는 바로 officecli 실행)은 감지된 모든 AI 도구에 스킬 파일을 자동 주입한다. 또 curl … | bash로 원격 스크립트를 바로 실행하는 설치 방식은 편하지만, 신뢰하는 소스인지 확인하고 쓰는 습관이 필요하다. 업데이트는 백그라운드에서 확인되며 OFFICECLI_SKIP_UPDATE=1·config autoUpdate false로 끌 수 있다. 기업/보안 환경이라면 SECURITY.md와 네트워크 정책을 먼저 검토하자.
난이도별로 손을 움직여 보자.
과제 1. 빈 PPT를 만들고 슬라이드/도형을 몇 개 추가한 뒤 view outline과 view screenshot을 비교한다.
officecli create deck.pptx
officecli add deck.pptx / --type slide --prop title="Q4 Report" --prop background=1A1A2E
officecli add deck.pptx '/slide[1]' --type shape \
--prop text="Revenue grew 25%" --prop x=2cm --prop y=5cm --prop size=24 --prop color=FFFFFF
officecli view deck.pptx outline
officecli view deck.pptx screenshot -o /tmp/deck.png
과제 2. 엑셀에 표를 만들고 =SUM/=XLOOKUP을 써 넣은 뒤 get으로 값이 이미 계산돼 있는지 확인한다. 그다음 소스 범위로 피벗테이블을 한 줄에 생성한다.
officecli add sales.xlsx '/Sheet1' --type pivottable \
--prop source='Data!A1:E10000' --prop rows='Region,Category' \
--prop cols=Quarter --prop values='Revenue:sum,Units:avg' \
--prop showDataAs=percentOfTotal
과제 3. {{client}}·{{total}} 자리표시자가 든 인보이스 템플릿을 만들고, JSON을 바꿔가며 merge로 여러 문서를 찍어낸다. "설계 1번, 생산 N번" 파이프라인을 체감한다.
officecli merge invoice-template.docx out-001.docx '{"client":"Acme","total":"$5,200"}'
과제 4. officecli mcp claude로 MCP 서버를 등록하고, Claude Code/Cursor에서 자연어로 "3장짜리 회사 소개 슬라이드 만들어 줘"를 시켜 render→look→fix 루프가 실제로 도는지 관찰한다.
과제 5. dump로 사람이 만든 예쁜 문서를 batch JSON으로 떠서, 구조를 수정한 뒤 batch로 재생해 "샘플 학습 → 변형 생성"을 실습한다.
과제 6. ResidentServer.cs의 "두 CTS" 종료 시퀀스를 읽고, 왜 ping-CTS를 Dispose() 뒤에 취소하는지 설명해 본다. ExcelHandler의 partial class 분할이 유지보수에 어떤 이점을 주는지도 정리한다.
이 레포를 발판으로 4주간 뻗어나갈 길.
| 주차 | 주제 | 할 것 |
|---|---|---|
| 1주차 | OOXML 기초 | .docx/.xlsx/.pptx의 압축을 풀어 내부 XML을 직접 열어 본다. dump 결과와 대조하며 w:p/워크시트/슬라이드 트리의 구조를 익힌다 |
| 2주차 | 에이전트용 도구 설계 | MCP 프로토콜(JSON-RPC), 결정적 출력·구조화 에러·점진적 복잡도 패턴을 학습하고, 나만의 작은 CLI를 "AI가 쓰기 좋게" 설계해 본다 |
| 3주차 | .NET 배포 & 동시성 | self-contained single-file 발행, 임베디드 리소스, named pipe IPC, CancellationToken 패턴을 직접 구현 |
| 4주차 | 렌더링 & 멀티모달 루프 | 헤드리스 브라우저(Playwright/Puppeteer)로 HTML→PNG 파이프라인을 만들고, 그 이미지를 멀티모달 LLM에 먹여 자기교정 루프를 실험 |
OfficeCLI의 진짜 교훈은 오피스가 아니라 인터페이스 철학이다. 경로 주소·계층 API·결정적 JSON·self-healing 에러·시각 피드백 — 이 다섯 원칙은 오피스든 CAD든 데이터베이스든, "AI가 다룰 도구"를 설계할 때 그대로 적용된다. 이 레포를 읽는 목적을 "officecli 사용법"이 아니라 "에이전트 친화적 도구의 해부"로 두면 얻는 게 훨씬 크다.
이 문서에 나온 용어를 한자리에.
DocumentFormat.OpenXml SDK가 이걸 읽고 쓴다./slide[1]/shape[2], /Sheet1/A1처럼 1-based 인덱스 + 요소 이름으로 문서 안 요소를 가리키는 단순화 문법. XPath와 달리 네임스페이스를 몰라도 된다.view(읽기·의미적 뷰) → L2 get/set/add/remove(DOM 편집) → L3 raw(XML 직접). 위층부터 쓰고 필요할 때만 내려가 토큰·실수를 줄인다.save=flush+상주 유지, close=flush+해제. 외부 프로그램이 파일을 읽기 전 필수.{{key}} 템플릿에 JSON 부어 양산. dump=기존 문서를 재생 가능 batch JSON으로 역직렬화. batch=그 JSON을 재생해 문서 생성.officecli mcp claude).더 깊이 파고들 곳.