GITHUB 레포 딥다이브 · 2026-08-04 · CLOUDFLARE/COMPUTER · AI 에이전트에게 "진짜 컴퓨터"를 쥐여 주는데, 그 컴퓨터의 정체가 Durable Object 안의 SQLite다

computer 딥다이브
에이전트의 파일시스템을 SQLite 한 덩어리로 만들고, 실행 환경은 갈아 끼운다

cloudflare/computer는 AI 에이전트에게 파일시스템 + 셸 + 코드 실행을 통째로 내주는 Cloudflare의 신작이다. 핵심 발상이 독특하다 — 파일시스템을 컨테이너 디스크가 아니라 Durable Object 안의 SQLite에 담고, 그 위에 실행 환경(컨테이너/격리 워커)을 갈아 끼울 수 있는 플러그인으로 얹는다.

그래서 파일의 "진짜 원본"은 언제나 Durable Object의 SQLite에 있고(영구·버전 관리됨), 실행이 필요할 때만 그 상태를 컨테이너로 투영하거나 격리 워커로 되돌려 쓴다. 컨테이너 백엔드는 이 SQLite 상태를 진짜 리눅스 FUSE 파일시스템으로 마운트하고, 변경분은 computerd라는 데몬이 capnweb RPC로 동기화한다. 같은 워크스페이스를 무거운 컨테이너로도, 가벼운 격리 워커로도 돌릴 수 있다는 뜻이다.

(저장소 cloudflare/computer · npm @cloudflare/computer · 라이선스 MIT · 언어 TypeScript 376파일 ~13.2만 줄 · 테스트 144개(.test.ts, 소스당 1개 관례) · 모노레포 5패키지 + 예제 7개 · 핵심 의존 capnweb·just-bash·fuse-native·@platformatic/vfs · 상태 PREVIEW(프로덕션 부적합·API 불안정) · 최신 커밋 2026-08-03 · 버전 0.1.0-alpha.1(tag v0.1.1) · TrendShift Daily #8)
목차
  1. 한 줄 정체
  2. 왜 주목받는가 — "파일시스템이 곧 원본"이라는 각도
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — DO·capnweb·FUSE의 삼각형
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 기술별 배울 것
  7. 시스템 / 배포 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 로드맵 (주차별)
  10. 핵심 키워드 사전
  11. 참고 링크

1한 줄 정체

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

cloudflare/computer는 "AI 에이전트가 쓸 파일시스템을 Durable Object 안의 SQLite에 저장하고, 그 파일시스템 위에서 셸 명령과 코드를 실행하는 실행 환경을 컨테이너·격리 워커 중에 골라 끼울 수 있게 만든, Cloudflare 엣지 위의 에이전트용 컴퓨터"다. 한마디로 에이전트에게 내주는 "상태가 영구히 남는 작업용 컴퓨터"인데, 그 컴퓨터의 심장이 디스크가 아니라 데이터베이스라는 점이 남다르다.

한 장의 비유

"클라우드에 저장되는 게임 세이브 파일 — 어느 기계에서 이어 해도 똑같다"

콘솔 게임의 세이브 데이터가 본체가 아니라 클라우드에 있으면, 집 PS5에서 하던 걸 친구 집 기계에서 이어서 할 수 있다. 진짜 상태(세이브)는 클라우드에 있고, 기계는 그때그때 빌려 쓰는 "실행기"일 뿐이다.

computer가 딱 그 구조다. 에이전트의 파일들(세이브)은 항상 Durable Object의 SQLite(클라우드)에 있다. 실행이 필요하면 그 상태를 컨테이너에 FUSE로 마운트해 진짜 리눅스에서 git·pandoc을 돌리거나, 더 가벼우면 격리 워커에서 셸만 잠깐 켠다. 어느 실행기를 쓰든 파일의 원본은 한 곳(DO)이라, 컨테이너가 꺼져도 상태는 그대로 남는다.

용어
Durable Object (DO, 지속 객체)
Cloudflare Workers의 "상태를 가진 작은 서버" 단위. 하나의 DO는 전 세계에 딱 한 인스턴스만 존재하고, 자기만의 SQLite 저장소를 끼고 산다. 요청이 없어도 데이터는 영구히 남는다. computer는 이 DO 하나를 "한 에이전트의 컴퓨터 한 대"로 삼고, 그 안의 SQLite를 파일시스템의 원본으로 쓴다.
용어
computerd (컴퓨터 데몬)
컨테이너 안에서 도는 작은 리눅스 데몬. 두 가지 일을 한다 — ① DO의 SQLite 상태를 FUSE로 마운트해 실제 파일시스템처럼 보이게 하고, ② capnweb RPC 서버를 열어 변경분을 DO와 양방향 동기화한다. npm에 코드로 올리면 120MB라 무거워서, 미리 빌드한 단일 실행 바이너리를 컨테이너 이미지로 따로 배포한다.

사용자(에이전트 코드)가 파일을 쓰고 명령 하나를 돌릴 때 computer 안에서 벌어지는 일을 압축하면 이렇다:

에이전트 코드: ws.fs.writeFile("/card.md", ...) + ws.runtime.exec("pandoc ...", {backend:"container"}) │ ▼ ① 파일 쓰기 DO 안의 SQLite에 바로 기록 (vfs_nodes / vfs_chunks 테이블) → 이 순간 "원본"이 갱신됨. 컨테이너는 아직 몰라도 됨. ② 백엔드 연결 exec 첫 호출 때 컨테이너 백엔드를 lazy 연결 컨테이너가 뜨고 computerd가 부팅 → capnweb 세션 수립 ③ 상태 동기화 DO → 컨테이너로 변경분 push (바뀐 청크의 해시만 전송) computerd가 FUSE 마운트에 반영 → /workspace/card.md 가 진짜로 보임 ④ 명령 실행 컨테이너에서 pandoc 실제 실행 (진짜 바이너리·진짜 네트워크) stdout/stderr 를 capnweb 스트림으로 실시간 전달 ⑤ 결과 되쓰기 pandoc 이 만든 card.pdf 를 FUSE 가 가로채 청크로 쪼갬 → 변경분을 다시 DO 로 fetch → SQLite 원본 갱신 ⑥ 반환 exec 결과 {exitCode, stdout, pushed, pulled, sync} 반환 컨테이너는 꺼져도 됨 — card.pdf 는 이미 DO(원본)에 있다

여기서 결정적인 건 ①과 ⑤가 모두 SQLite를 갱신한다는 점이다. 호스트(DO)에서 쓴 card.md와 컨테이너의 pandoc이 만든 card.pdf같은 하나의 파일시스템으로 보인다 — 한쪽은 데이터베이스에 직접 쓰고, 다른 쪽은 FUSE를 통해 쓰지만, 둘 다 결국 같은 SQLite에 수렴한다. 이 "하나의 파일시스템" 착시를 만드는 게 이 레포의 전부라고 해도 된다.

2왜 주목받는가 — "파일시스템이 곧 원본"이라는 각도

에이전트 샌드박스가 넘쳐나는데 이건 왜 다른가

첫째, 발상의 순서가 거꾸로다. E2B·Daytona·Modal 같은 기존 "에이전트 샌드박스"는 컴퓨터(컨테이너/VM)를 먼저 주고, 파일시스템은 그 안의 디스크다 — 컨테이너가 죽으면 상태도 날아간다. computer는 반대로 파일시스템(DO 안 SQLite)을 원본이자 진실로 두고, 실행 환경을 일회용 부속으로 갈아 끼운다. 그래서 컨테이너가 꺼져도, 심지어 실행 환경 없이도 파일은 그대로 남고 버전이 관리된다. 에이전트의 "기억"을 디스크가 아니라 데이터베이스에 두는 셈이다.

비유

구글 독스 vs 워드 파일. 워드는 문서가 특정 노트북 안 파일이라, 그 노트북이 고장 나면 문서도 위태롭다(=컨테이너 디스크). 구글 독스는 문서가 클라우드에 살고, 브라우저는 그저 그때그때 보는 창이다. computer의 파일시스템은 구글 독스 쪽이다 — 실행기(컨테이너)는 문서를 잠깐 여는 창일 뿐, 원본은 항상 클라우드(DO)에 있다.

둘째, 하나의 워크스페이스, 여러 실행 표면(execution surface)이라는 유연함이다. 같은 파일시스템 위에서 상황에 맞게 실행기를 고를 수 있다 — 진짜 리눅스 바이너리(git, pandoc, npm)가 필요하면 컨테이너 백엔드, 셸 몇 줄이면 되는 가벼운 작업엔 격리 워커(just-bash), 구조화된 코드 실행엔 격리 자바스크립트 백엔드. 무거운 컨테이너를 항상 띄울 필요가 없어 비용·지연이 준다.

셋째, Cloudflare 엣지 원시요소(primitive)를 정직하게 조립했다는 공학적 매력이다. Durable Object(상태+SQLite), Containers(진짜 리눅스), Worker Loaders(동적 격리 실행), R2(오브젝트 스토리지) — 남의 인프라를 흉내 내지 않고 자사 블록을 레고처럼 끼워 "에이전트용 컴퓨터"를 만들었다. capnweb(용량 기반 RPC)로 DO와 컨테이너를 잇고, git 내부구현처럼 내용 주소 지정(content-addressed) 청크 저장소로 바뀐 조각만 골라 동기화한다.

이 레포의 강점
"파일시스템 = 데이터베이스"가 공짜로 주는 것들

파일시스템을 SQLite에 담자, 평범한 디스크에선 어려운 것들이 저절로 따라온다 — 영속성(컨테이너와 무관하게 상태 유지), 버전/개정(rev) 추적, 내용 기반 중복제거(같은 청크는 한 번만 저장), 델타 동기화(바뀐 청크 해시만 전송). "저장을 DB로 바꿨을 뿐인데 부수 효과로 얻는 능력"이 이 설계의 진짜 배당금이다.

주의
아직 PREVIEW — 프로덕션 금지

README가 대문짝만하게 경고한다: "PREVIEW ONLY … NOT suitable for production use. APIs are unstable." 워크스페이스당 용량은 DO 저장소를 공유해 ~10GB가 상한이고, 컨테이너 쪽 파일시스템은 메모리에 얹혀 "에이전트 규모"(모노레포 통째 X)를 가정한다. 큰 순차 I/O는 FUSE 특성상 진짜 디스크보다 느리다. "배워두면 좋은 최신 설계"로 보되, 지금 프로덕션에 넣을 물건은 아니다.

3기술 스택 전체 지도

모노레포 5패키지 + 어떤 Cloudflare 블록으로 지었나

몸통: TypeScript 모노레포 (npm workspaces)

전체가 TypeScript다(376파일, ~13.2만 줄). 프레임워크 런타임 의존은 놀랄 만큼 적다 — 공개 패키지 @cloudflare/computer의 런타임 의존은 acorn(JS 파싱), capnweb(RPC), just-bash(격리 셸) 단 셋이고, AI SDK 도구·Node VFS 제공자·zod는 전부 optional peerDependency라 쓸 때만 딸려온다. 무겁게 만들지 않으려는 절제가 보인다.

용어
capnweb
Cloudflare가 만든 용량 기반(capability-based) RPC 라이브러리. 원격 객체를 "스텁(stub)"으로 잡아 메서드를 호출하고, ReadableStream을 그대로 실어 보내 엔드투엔드 백프레셔(backpressure)가 커널 파이프까지 이어진다. computer에선 DO ↔ computerd 사이의 파일 동기화와 명령 실행 스트림을 나르는 배관이다.
용어
FUSE (Filesystem in Userspace) · just-bash
FUSE는 커널 드라이버 없이 사용자 공간 프로그램이 "가짜 파일시스템"을 마운트하게 해주는 리눅스 기능. computerd가 이걸로 SQLite 상태를 /workspace에 진짜 폴더처럼 띄운다. just-bash는 순수 JS로 구현한 bash 호환 셸 — 진짜 리눅스 없이 격리 워커 안에서 셸 명령을 해석·실행한다.

5개 패키지 — 무엇이 무엇을 하나

패키지npm 이름역할
computer@cloudflare/computer유일한 공개 패키지. DO 쪽 얼굴 — Workspace, runtime 라우터, 백엔드들, git·assets·artifacts·tools 서브경로
dofs@cloudflare/dofsSQLite 기반 VFS. fs/* 원시연산(read·write·mkdir·chunk), 스키마·마이그레이션, 동기화 빌딩블록
rpc@cloudflare/computer-rpccapnweb 배선. 와이어 타입(SyncRPC·ShellRPC), server/client/driver/debug 헬퍼
computerd@cloudflare/computerd컨테이너 안 데몬. FUSE 마운트(fuse-native) + HTTP/WS capnweb 서버 + exec Runner. 소스 전용
computerd-linux-x64(동명 npm)미리 빌드한 SEA 바이너리. 단일 레이어 컨테이너 이미지로 배포 — Dockerfile이 COPY --from
용어
Durable Object / Container / Worker Loader / R2 (엣지 원시요소 4종)
DO=상태+SQLite를 가진 단일 서버 단위(파일 원본). Container=진짜 리눅스가 도는 무거운 실행기(컨테이너 백엔드). Worker Loader=코드를 즉석에서 격리 워커로 띄우는 바인딩(worker-shell·worker-javascript 백엔드의 실행터). R2=S3 호환 오브젝트 스토리지(/workspace/r2 마운트·아티팩트 공유 링크). computer는 이 넷을 조립한다.

빌드 · 배포 도구

4아키텍처 심화 — DO·capnweb·FUSE의 삼각형

이 레포의 진짜 알맹이. "하나의 파일시스템 착시"를 어떻게 만드나

전체 그림은 세 꼭짓점의 삼각형이다. ① DO(Workspace) 안 SQLite가 파일의 원본, ② capnweb이 그 사이의 배관, ③ computerd(FUSE)가 컨테이너에서 진짜 파일시스템으로 투영. 컨테이너 백엔드일 때의 실제 배선은 이렇다:

에이전트 코드 (DO 내부: Workspace + SQLite VFS = 권위 있는 원본 상태) │ ws.runtime.exec(cmd, {backend:"container"}) ▼ ┌──────────────────────── Durable Object ────────────────────────┐ │ Workspace ── runtime(라우터) ── 백엔드 레지스트리 │ │ SQLite: vfs_nodes · vfs_dirents · vfs_chunks · vfs_blobs │ └───────────────▲───────────────────────────────┬────────────────┘ │ capnweb (WebSocket /ws) │ 컨테이너 부팅 SyncRPC ▷ push / fetchChanges / hasObjects │ (바뀐 청크의 해시만 오감 · 내용주소 · 스트림) ▼ ┌──────────────────────── Container ─────────────────────────────┐ │ computerd 데몬 │ │ ├─ FUSE 마운트 → /workspace (SQLite 상태를 진짜 폴더로 투영) │ │ ├─ HTTP/WS capnweb 서버 (:8080) │ │ └─ exec Runner (ShellRPC) → 진짜 bash·git·pandoc 실행 │ └─────────────────────────────────────────────────────────────────┘ ※ 역방향 다이얼: computerd 가 ws://computer.internal/ws 로 DO 에 "되전화"해 세션 수립

재미있는 디테일 하나 — 세션을 컨테이너가 DO에게 되건다(reverse-dial). 보통은 바깥(DO)이 안(컨테이너)으로 연결하지만, 여기선 computerd가 부팅 후 ws://computer.internal/ws로 DO에 전화를 걸어 capnweb 세션을 연다. 컨테이너를 외부에서 직접 주소 지정하기 어려운 환경을 우아하게 피하는 방식이다.

백엔드 계약 — 실행기를 갈아 끼우는 인터페이스

모든 실행기는 WorkspaceBackend 한 인터페이스를 구현한다. 핵심은 connect(host)가 돌려주는 BackendHandlesync 필드다:

// 백엔드가 연결되면 돌려주는 핸들 (개념 요약)
interface BackendHandle {
  rpc: WorkspaceRPC;            // 이 백엔드의 computerd 를 가리키는 스텁
  sync?: "remote" | "none";    // ★ 이 백엔드가 자기 저장소를 갖는가?
  closed?: Promise<void>;       // 전송 끊기면 resolve → 핸들 버리고 재연결
  close(): Promise<void>;
}

sync:"remote""이 백엔드는 자기만의 SQLite VFS가 따로 있다"는 뜻(컨테이너) — 그래서 DO와 push/pull로 상태를 오간다. sync:"none""저장소를 새로 두지 않고 호스트 DO를 그대로 재사용한다"는 뜻(격리 워커 셸) — 되돌려 부를 두 번째 저장소가 없으니 동기화가 no-op이라 왕복이 사라진다. 같은 파일시스템 위에 "동기화가 필요한 실행기"와 "필요 없는 실행기"를 한 인터페이스로 나란히 꽂는 게 이 설계의 묘수다.

세 가지 백엔드 비교

백엔드소스 언어동기화필요 조건
container-shell셸 명령remote(자체 SQLite VFS, capnweb 동기화)Cloudflare Container + computerd, nodejs_compat
worker-shelljust-bash 명령none(같은 DO로 되부름)Worker Loader 바인딩, experimental 플래그
worker-javascriptECMAScript 모듈noneWorker Loader, experimental, waitUntil
용어
SyncRPC / ShellRPC (capnweb 와이어 계약)
둘이 합쳐 WorkspaceRPC를 이룬다. SyncRPC=파일 동기화: push(DO→컨테이너), fetchChanges(컨테이너←DO), hasObjects/fetchObjects(해시로 없는 청크만 골라 가져오기), watermarks(싼 진단·하트비트). ShellRPC=명령 실행: exec(→ {id, events: 스트림}), getExec·killExec·disposeExec.

파일시스템의 정체 — content-addressed 청크 저장소

SQLite 스키마(SCHEMA_VERSION 5)를 보면 이 파일시스템이 사실 git과 닮은 내용 주소 저장소임이 드러난다. 파일 바이트는 512 KiB 청크로 쪼개 해시를 키로 저장한다:

vfs_nodes(inode, type, mode, mtime, rev, manifest_hash, size ...)  // 파일/폴더/심링크
vfs_dirents(parent_inode, name, child_inode)                       // 이름→inode (디렉터리)
vfs_chunks(inode, idx, hash, size)                                 // 파일 = 청크들의 순서
vfs_blobs(hash, size)  +  vfs_blob_bytes(hash, bytes)              // 해시→실제 바이트 (중복제거)

이 구조라서 동기화가 똑똑해진다 — DO가 "이 파일이 바뀌었고, 청크 해시는 A·B·C다"라고 보내면, 받는 쪽은 hasObjects로 "A·B는 이미 있음, C만 없음"을 답하고 C의 바이트만 전송한다. 같은 청크는 온 시스템에서 한 번만 저장되고(중복제거), 큰 파일을 조금 고쳐도 바뀐 청크만 오간다(델타 동기화). 대신 큰 파일을 쓸 때마다 청크를 해싱하는 비용이 붙어, 순차 대용량 I/O는 느려진다(§7 벤치 참고).

비유

레고로 지은 집을 이사하기. 집을 통째로 트럭에 싣는 대신(=파일 전체 전송), 레고 블록으로 지었다면 "새로 바뀐 블록 몇 개"만 택배로 보내면 상대가 자기 집에 끼운다. 같은 모양 블록은 이미 갖고 있으니 안 보낸다. computer의 청크 동기화가 이 레고 이사다 — 그래서 빠르고 알뜰하지만, 블록을 매번 쪼개고 번호(해시) 매기는 수고가 든다.

5디렉토리 구조 해부

13.2만 줄이 5패키지 + 7예제로 어떻게 나뉘어 있나
computer/ ├─ package.json 루트 (npm workspaces: packages/* + examples/*) ├─ biome.jsonc 린트·포맷 설정 ├─ AGENTS.md AI 에이전트용 개발 관문(레포 규약) ├─ .agents/skills/ capnweb · cloudflare · TDD · debugging-computerd-fuse … ├─ docs/ 01~19 번호 스펙 .md (10=구조, 16=코드실행, 19=성능) │ ├─ packages/ │ ├─ computer/ ★ 공개 패키지 @cloudflare/computer │ │ └─ src/ │ │ ├─ workspace.ts runtime · backend · shell · client · proxy │ │ ├─ runtime/ bridge · capability · runtime · wire (exec 라우터) │ │ ├─ backends/ │ │ │ ├─ container/ cloudflare-container · container-host · lifecycle │ │ │ ├─ worker-shell/ just-bash 를 동적 워커에서 · git/assets/artifacts-command │ │ │ └─ worker-javascript/ ESM 평가 · module-graph · frames │ │ ├─ git/ clone · commit · diff · staging (isomorphic-git 지연로드) │ │ ├─ assets/ R2 업로드 · sigv4 · 공유 링크 │ │ ├─ artifacts/ 빌드 산출물 리포지토리 │ │ └─ tools/ ai.ts (AI SDK 도구) · fs/{read,write,edit,list} │ │ │ ├─ dofs/ @cloudflare/dofs — SQLite VFS │ │ └─ src/ provider.ts · storage.ts · schema/{core,sync,migrations} │ │ fs/{mkdir,writeFile,readFile,rm,readdir,stat,grep,gc,watch} │ │ sync/{apply,blobs,changes,coalesce,fetch,manifests,watermarks} │ │ │ ├─ rpc/ @cloudflare/computer-rpc — capnweb 와이어 │ │ └─ src/ interface.ts · server.ts · client.ts · sync-driver.ts │ │ │ ├─ computerd/ @cloudflare/computerd — 컨테이너 데몬(소스 전용) │ │ └─ src/ cli/computerd.ts · fuse/{driver,backend,vfs} · exec/{runner,log} │ │ │ └─ computer-computerd-linux-x64/ 미리 빌드한 SEA 바이너리 (이미지로 배포) │ └─ examples/ (7종) ├─ container / worker-shell / worker-javascript 세 백엔드 각각의 워커 ├─ think / think-compare-runtimes @cloudflare/think 에이전트 ├─ tutorial host 쓰기+컨테이너 pandoc → R2 공유 └─ artifacts / assets 빌드 게시 · 이미지 생성 링크

구조에서 읽히는 힌트 셋. 첫째, 공개는 packages/computer 하나뿐이고 나머지 넷은 그 밑을 받치는 내부 부품이다 — 사용자는 @cloudflare/computer만 알면 되고, dofs·rpc·computerd는 몰라도 된다. 둘째, packages/computer/src/backends/ 아래 세 폴더가 §4의 세 백엔드와 정확히 대응한다. 셋째, git·assets·artifacts·tools 서브경로가 별도로 있는 건, 이 파일시스템 위에 git 저장소, R2 자산, AI SDK 도구까지 "에이전트가 실제로 쓸 살림살이"를 얹어 팔기 때문이다.

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

이 레포를 뜯어보며 실제로 익힐 수 있는 것들

① Durable Object = 상태를 가진 컴퓨트 (가장 값진 배움)

대부분의 서버리스는 "무상태(stateless)"라 상태를 매번 외부 DB에서 불러온다. Durable Object는 코드와 상태(SQLite)가 한 몸인 드문 모델이다. 이 레포는 DO를 "한 에이전트의 컴퓨터 한 대"로 쓰는 실전 예를 통째로 보여준다 — 서버리스에서 "영구히 켜져 있는 것처럼 보이는 상태"를 어떻게 얻는가를 코드로 배우는 최고의 교재다.

② 내용 주소 저장 + 델타 동기화 (git 내부구현의 축소판)

파일을 청크로 쪼개 해시를 키로 저장하고, 바뀐 청크만 골라 보내는 hasObjects/fetchObjects 흐름은 사실상 git의 object store와 packfile 협상을 파일시스템에 적용한 것이다. 중복제거·델타 전송·rev 추적이 왜 "저장을 내용 주소로 바꾸면 공짜로 따라오는가"를 실물로 이해하게 된다.

③ FUSE와 VFS — 파일시스템은 만들 수 있는 것

packages/computerd/src/fuse/는 "파일시스템도 그냥 프로그램"임을 가르친다. create/open/write/release 콜백을 구현하면 ls·cat·git이 그대로 동작한다. st_blocks·st_blksize를 손수 채워 du가 올바로 나오게 하는 디테일까지, POSIX 파일시스템 시맨틱을 바닥부터 만난다.

④ capnweb — 용량 기반 RPC와 스트리밍

메서드 호출뿐 아니라 ReadableStream을 그대로 실어 보내 백프레셔가 양끝을 잇는 RPC. 명령의 stdout이 커널 파이프에서 클라이언트까지 밀림 없이 흐르는 구조, 원격 스텁을 using으로 수명 관리하는 패턴(아래 함정) 등, "네트워크 너머 객체를 로컬처럼 다루는" 최신 RPC 감각을 얻는다.

⑤ 모노레포 엔지니어링 위생

Biome(린트+포맷), sherif(의존성 일관성), 소스당 .test.ts 1개 관례(144개), SEA 단일 바이너리 빌드(esbuild+postject), OIDC 트러스티드 퍼블리싱, 그리고 .agents/skills/AI 에이전트가 이 레포를 개발하도록 규약을 문서화한 점까지 — 2026년식 프로덕션 TS 모노레포의 표준 장비를 한 번에 훑는다.

함정
원격 스텁은 GC되지 않는다 — using을 잊지 말 것

README가 못 박는다: capnweb의 원격 스텁은 자동 회수되지 않는다. getWorkspace(...)ws.runtime.exec(...)가 돌려주는 값은 using으로 받아 스코프를 벗어날 때 정리해야 한다. 반대로 순수 값 반환(readFile의 문자열, stat, readdir)은 스텁이 아니라 그냥 써도 된다. 이걸 놓치면 스텁이 새어 컨테이너 메모리가 부푼다.

7시스템 / 배포 요구사항

돌려 보려면 무엇이 필요한가 · 성능은 어떤가
쓰는 방식필요한 것
컨테이너 백엔드Cloudflare Container(예: standard-2 = 1 vCPU·6 GiB·12 GB 디스크) + computerd 이미지, wrangler, compatibility_flags:["nodejs_compat"]
격리 워커 셸/JSWorker Loader 바인딩(LOADER), compatibility_flags:["nodejs_compat","experimental"]. 컨테이너 불필요
로컬 개발wrangler dev. 컨테이너에 /dev/fuse가 없으면 computerd가 유저스페이스 shim으로 자동 폴백(FUSE_MOUNT=auto)
저장 한도워크스페이스당 ~10 GB(DO 저장소 공유). 컨테이너 쪽 FS는 메모리 상주 — "에이전트 규모"용

성능 — FUSE는 언제 이기고 언제 지나 (docs/19, standard-2 기준)

computerd FUSE를 tmpfs·실제 디스크(ext4)와 비교한 수치. 비율은 computerd/기준값이라 1.0 미만이면 computer가 더 빠름:

작업vs 실제 디스크해석
파일 1000개 stat0.91x메타데이터 위주는 디스크보다 빠름 — SQLite 인덱스가 파일 나열·삭제에 유리
rm / mkdir 트리0.66x / 0.74x
git init+commit / clone0.72x / 0.84x
64 MiB 쓰기 / 복사 / 읽기16.9x / 40x / 30x큰 순차 I/O는 크게 느림 — 청크마다 해싱·내용주소 저장 비용
sandbox-sdk npm install
(854패키지·36,675파일)
124.7초
(디스크 63.9초·tmpfs 34.3초)
디스크의 약 2배 — 파일 많은 설치는 손해

요약하면 "작은 파일 많이 만지는 일(git·빌드 메타·탐색)엔 강하고, 큰 파일 통째로 읽고 쓰는 일엔 약하다". 에이전트가 코드·문서를 조물조물 다루는 전형적 작업엔 잘 맞고, 대용량 미디어 처리엔 안 맞는다는 뜻이다.

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

난이도별로. 위에서 아래로 갈수록 어렵다
과제 1 난이도 ●○○○○

worker-shell 예제로 "파일 쓰고 명령 돌리기"

examples/worker-shellwrangler dev로 띄우고, ws.fs.writeFile("/hello.txt", ...)로 파일을 쓴 뒤 ws.runtime.exec("cat /hello.txt")를 돌려 보자. 컨테이너 없이 격리 워커만으로 파일시스템+셸이 도는 걸 확인하는 게 첫걸음. exec 결과의 stdout·exitCode를 찍어 보고, 되었으면 ws.fs.readdir("/")로 방금 만든 파일이 보이는지 본다.

과제 2 난이도 ●●○○○

같은 워크스페이스를 두 백엔드로 돌려 비교

examples/think처럼 한 Workspace에 "shell"(worker-shell)과 "container" 백엔드를 둘 다 등록하고, 같은 파일을 만든 뒤 exec(cmd, {backend:"shell"}){backend:"container"}로 각각 실행해 보자. 컨테이너에서만 git --version·pandoc이 되는 이유(진짜 리눅스 vs just-bash)를 몸으로 이해하고, 첫 컨테이너 exec의 지연(lazy 부팅+동기화)을 측정한다.

과제 3 난이도 ●●●○○

SQLite 스키마를 열어 "파일이 청크로 쪼개지는" 걸 관찰

packages/dofs의 스키마(vfs_nodes·vfs_chunks·vfs_blobs)를 읽고, 큰 파일 하나를 쓴 뒤 같은 내용을 복사해 보자. 청크 해시가 재사용(중복제거)되는지, 파일을 조금만 고치면 바뀐 청크만 새로 생기는지를 확인하면 §4의 델타 동기화가 왜 성립하는지 확실히 잡힌다. docs/19의 벤치 하네스도 함께 읽어 "왜 큰 쓰기가 느린가"를 수치로 대조.

과제 4 난이도 ●●●●○

capnweb 동기화(push/fetchChanges) 흐름 추적하기

packages/rpc/src/interface.tspackages/dofs/src/sync/를 따라가며, DO가 컨테이너로 push할 때와 컨테이너 변경을 fetchChanges로 되가져올 때 어떤 청크 해시가 오가는지 로그를 심어 관찰한다. watermarks가 하트비트로 쓰이는 지점, hasObjects로 "없는 것만" 고르는 협상을 눈으로 확인하면 분산 동기화 설계가 손에 잡힌다.

과제 5 난이도 ●●●●●

@cloudflare/think로 "파일 쓰고 코드 돌리는" 미니 에이전트

examples/tutorial을 본떠, LLM에게 createAITools({workspace})를 쥐여 주고 "/report.md를 쓰고 컨테이너에서 pandoc으로 PDF 변환해 R2 공유 링크를 반환"하는 에이전트를 만들어 보자. host에서 쓴 파일과 컨테이너 pandoc이 만든 PDF가 같은 파일시스템으로 보이는 순간을 직접 구현하는, 이 레포의 정수를 통째로 체험하는 과제다.

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

이 레포를 계기로 공부 계획을 짠다면
주차주제구체적으로
1주Durable Objects + WorkersDO의 단일 인스턴스·SQLite 저장소·alarm, Workers 요청 수명주기, wrangler 바인딩. packages/computer/src/workspace.ts를 표본으로
2주내용 주소 저장 & 델타 동기화청킹·해싱·중복제거·rev, git object store/packfile 협상과의 평행. packages/dofs/src/{schema,sync}
3주FUSE & VFS사용자공간 파일시스템, POSIX 시맨틱(inode·dirent·stat), 쓰기 버퍼·release 커밋. packages/computerd/src/fuse/
4주capnweb & 용량 기반 RPC스텁·프로미스 파이프라이닝·스트리밍 백프레셔·수명관리(using). packages/rpc/와 capnweb 문서
5주(선택)에이전트 샌드박스 설계E2B·Daytona·Modal·cloudflare/sandbox-sdk 비교, MCP로 도구 노출, 안전한 코드 실행(격리·타임아웃·네트워크 정책)

10핵심 키워드 사전

이 문서에 나온 개념 압축 정리
용어
Workspace / runtime.exec
에이전트의 컴퓨터 한 대(=DO)를 감싼 최상위 객체. ws.fs.*로 파일을, ws.runtime.exec(source,{backend})로 명령/코드를 실행한다. exec가 유일한 실행 진입점이고, 백엔드에 따라 source가 셸 명령이거나 ESM 모듈이 된다.
용어
Durable Object (DO)
상태(SQLite)를 끼고 사는 단일 인스턴스 서버 단위. computer는 DO 하나를 한 에이전트의 파일 원본 저장소로 삼는다. 컨테이너와 무관하게 상태가 영구히 남는 근원.
용어
computerd
컨테이너 안 데몬. DO의 SQLite 상태를 FUSE로 /workspace에 마운트하고, capnweb 서버로 변경분을 DO와 동기화하며, 셸 명령을 실제 실행한다. SEA 바이너리로 컨테이너 이미지에 담겨 배포.
용어
백엔드 / sync: remote·none
실행기(컨테이너·격리 워커)를 한 인터페이스로 추상화한 것. remote=자체 SQLite VFS를 갖고 DO와 push/pull(컨테이너). none=호스트 DO를 재사용해 동기화가 no-op(격리 워커 셸).
용어
capnweb
Cloudflare의 용량 기반 RPC. 원격 객체를 스텁으로 다루고 스트림을 실어 백프레셔가 양끝을 잇는다. DO↔computerd의 SyncRPC(동기화)·ShellRPC(실행)를 나른다. 스텁은 GC 안 되니 using 필수.
용어
content-addressed 청크 저장소
파일을 512 KiB 청크로 쪼개 해시를 키로 저장하는 방식. 같은 청크는 한 번만 저장(중복제거)하고, hasObjects 협상으로 없는 청크만 전송(델타 동기화)한다. git object store의 파일시스템판.
용어
FUSE (Filesystem in Userspace)
커널 드라이버 없이 사용자공간 프로그램이 파일시스템을 마운트하는 리눅스 기능. computerd가 이걸로 SQLite 상태를 진짜 폴더처럼 보이게 해, 컨테이너의 git·pandoc이 그대로 동작한다.
용어
just-bash / Worker Loader
just-bash=순수 JS로 구현한 bash 호환 셸(진짜 리눅스 없이 격리 워커에서 셸 명령 실행). Worker Loader=코드를 즉석에서 격리 워커로 띄우는 바인딩(worker-shell·worker-javascript 백엔드의 실행터, experimental).
용어
역방향 다이얼(reverse-dial)
보통과 반대로 컨테이너(computerd)가 DO에게 ws://computer.internal/ws로 "되전화"해 capnweb 세션을 여는 방식. 컨테이너를 외부에서 직접 주소 지정하기 어려운 환경을 우회한다.
용어
SEA (Single Executable Application)
Node 앱을 한 개의 실행 바이너리로 묶는 기법. esbuild로 번들 → node --experimental-sea-config + postject로 주입. computerd를 npm(120MB) 대신 가벼운 컨테이너 이미지로 배포하려는 선택.

11참고 링크

더 파고들 때