이 인덱스에는 이름이 같은 goose가 둘 있습니다. 이 문서는 45.2k★ AI 에이전트 goose(aaif-goose/goose)를 다룹니다. WHOOP 5.0 밴드용 건강 앱인 b-nnett/goose는 별도 문서(goose-deep-dive.html)에서 다뤘습니다. 깃허브에서 레포 이름은 얼마든지 겹칠 수 있으니, 항상 owner/repo 풀네임으로 확인하는 습관이 좋습니다.
"클라우드가 아니라 내 컴퓨터에서 직접 돌면서, 코드 작성부터 자료 조사·문서 작업·자동화까지 시켜먹을 수 있는 오픈소스 AI 에이전트"입니다. AI 에이전트란 단순히 질문에 답하는 챗봇이 아니라, 파일을 읽고·명령을 실행하고·도구를 골라 쓰면서 여러 단계의 작업을 스스로 진행하는 프로그램을 말합니다. goose는 그 에이전트를 macOS·Linux·Windows용 데스크탑 앱, 터미널 CLI, 그리고 어디에든 심을 수 있는 API 서버, 세 형태로 제공합니다.
가장 큰 특징은 "특정 회사에 묶이지 않는다"는 점입니다. Anthropic·OpenAI·Google·Ollama 등 15개 이상의 프로바이더를 API 키로 붙일 수 있고, 심지어 이미 결제 중인 Claude·ChatGPT·Gemini 구독을 ACP라는 프로토콜로 끌어와 쓸 수도 있습니다. 2026년 Block에서 Linux Foundation 산하 AAIF로 이관되면서 "한 회사의 제품"이 아니라 공공 인프라 성격의 에이전트 플랫폼으로 자리를 굳히는 중입니다.
통신사 약정폰은 그 통신사에서만 쓸 수 있지만, 자급제 폰은 아무 유심이나 꽂으면 됩니다. goose가 바로 자급제 폰입니다 — 본체(에이전트 루프·도구·UI)는 goose가 제공하고, 두뇌(LLM)는 Anthropic이든 OpenAI든 내 PC의 Ollama든 마음대로 꽂아 씁니다.
여기에 더해 "이미 쓰는 요금제(Claude·ChatGPT 구독)를 그대로 연결"하는 ACP까지 지원하니, 두뇌 선택의 자유가 이 프로젝트의 정체성입니다.
rmcp로 구현했다.goose가 다시 트렌딩에 오른 직접적 계기는 Linux Foundation 산하 AAIF(Agentic AI Foundation)로의 이관입니다. README 첫 줄에 "block/goose에서 이사했다"는 공지가 붙어 있을 만큼 최근 일입니다. 한 기업(Block)의 사이드 프로젝트에서 쿠버네티스처럼 재단이 관리하는 중립 오픈소스로 격이 바뀐 것인데, 기업 입장에선 "벤더 종속 없이 도입할 수 있는 에이전트"라는 신뢰 신호가 됩니다.
두 번째 이유는 구독 재사용(ACP)입니다. 에이전트를 쓰려면 보통 API 키를 새로 발급받아 토큰당 비용을 내야 하는데, goose는 이미 결제 중인 Claude·ChatGPT·Gemini 구독을 ACP로 연결해 쓰는 길을 열었습니다. 개인 개발자에게는 추가 비용 0원으로 데스크탑 에이전트를 들이는 매력적인 선택지입니다.
| 도구 | 성격 | goose와의 차이 |
|---|---|---|
| Claude Code | Anthropic의 코딩 CLI 에이전트 | Claude 전용·터미널 중심. goose는 멀티 프로바이더 + 데스크탑 앱이 기본 |
| OpenHands | 오픈소스 코딩 에이전트(웹 UI) | 코딩 작업 특화. goose는 코딩 외 리서치·문서·자동화까지 범용 지향 |
| goose | 로컬 우선 범용 에이전트 | 데스크탑+CLI+API 서버 3면 제공, Rust 코어, 재단(AAIF) 거버넌스 |
코딩 에이전트 경쟁이 워낙 뜨겁다 보니 goose도 "또 하나의 코딩 CLI"로 오해받기 쉽다. 하지만 goose의 공식 소개 첫 문장은 "Not just for code"다. 스케줄러(예약 실행), recipe(작업 패키지), 메모리·튜토리얼 같은 내장 확장 구성을 보면 일상 업무 자동화 플랫폼을 목표로 설계됐음이 드러난다.
이 관점으로 보면 왜 데스크탑 앱(Electron)에 공을 들이는지, 왜 프로바이더가 60개를 넘는지, 왜 recipe로 "에이전트 구성 공유"를 만들었는지가 한 줄로 꿰어진다. 비개발자 동료에게 "이 recipe 딥링크 눌러" 하고 건네는 시나리오까지 포함한 설계다.
goose는 "성능이 필요한 코어는 Rust, 화면은 웹 기술"이라는 요즘 데스크탑 앱의 정석 분업을 따릅니다. 다만 Tauri가 아니라 Electron을 쓰고, Rust 코어를 라이브러리로 링크하는 대신 goosed라는 별도 서버 프로세스로 띄워 HTTP로 통신한다는 점이 독특합니다(4장에서 자세히).
| crate | 역할 |
|---|---|
| goose | 코어. 에이전트 루프·세션·프로바이더·recipe·ACP·스케줄러 (.rs 295개로 전체의 67%) |
| goose-cli | 터미널 명령 goose — session/run/recipe/schedule/acp/mcp/tui 등 서브커맨드 |
| goose-server | HTTP API 서버 goosed — axum 기반, 데스크탑 앱의 백엔드 |
| goose-mcp | 내장 MCP 서버 모음 (memory·tutorial·computercontroller 등) |
| goose-providers | 프로바이더 공통 타입(대화 포맷·에러) |
| goose-sdk(+types) | Rust SDK — uniffi로 Python/Kotlin 바인딩 생성 가능 |
| vendor/v8 | V8 자바스크립트 엔진 래퍼 — LLM이 만든 코드를 샌드박스에서 실행하는 용도 |
| 크레이트 | 버전 | 쓰임 |
|---|---|---|
| tokio | 1.48 | 비동기 런타임 — 에이전트 루프·스트리밍의 토대 |
| axum | 0.8 | goosed HTTP 서버 프레임워크 |
| rmcp | 1.4 | MCP 공식 Rust SDK — 확장 연결 |
| agent-client-protocol | 0.11 | ACP — 외부 에이전트/에디터와의 표준 대화 |
| sqlx (sqlite) | 0.8.5 | 세션 영속화 — SQLite WAL 모드 |
| utoipa | 4.2 | OpenAPI 스펙 자동 생성 → UI 클라이언트 코드젠의 출발점 |
| candle-core/nn | 0.10 | 로컬 ML 추론 (HuggingFace의 Rust ML 프레임워크) |
| tree-sitter 계열 | — | 코드 구조 분석 확장(analyze) — 언어별 파서 |
| keyring | 3.6.3 | API 키를 OS 키체인에 안전 보관 |
| reqwest / rustls | 0.13 / 0.23 | HTTP 클라이언트 · TLS |
| 기술 | 버전 | 역할 |
|---|---|---|
| Electron | 41 | 데스크탑 셸 (Tauri 아님 — Chromium 내장) |
| React | 19.2 | UI 컴포넌트 |
| Vite + TypeScript | 7.3 / 5.9 | 빌드·타입 체크 |
| Tailwind CSS + Radix UI | 4.2 | 스타일·접근성 컴포넌트 |
| @hey-api/openapi-ts | — | goosed의 OpenAPI 스펙에서 API 클라이언트 자동 생성 |
| vitest + Playwright | 4 / 1.58 | 단위·E2E 테스트 |
| 도구 | 내용 |
|---|---|
| Justfile | 태스크 러너 — just run-ui(데스크탑 개발), just run-server(goosed), just release-binary |
| Nix flake | flake.nix + rust-overlay — 재현 가능한 개발 환경 |
| Dockerfile | 멀티스테이지: rust 빌더 → debian-slim 런타임(digest 고정) |
| pnpm workspace | ui/ 아래 sdk·desktop 등 4패키지 모노레포 |
goosed는 utoipa로 자기 API의 OpenAPI 명세를 자동 생성하고, 데스크탑 앱은 @hey-api/openapi-ts로 그 명세에서 TypeScript 클라이언트를 생성한다(generate-api 스크립트). Rust와 TypeScript라는 다른 언어 사이에서 API 타입이 어긋날 수 없는 구조를 만든 것 — 프론트·백엔드 분리 프로젝트라면 어디든 훔쳐올 만한 패턴이다.
먼저 독수리 시점입니다. goose의 큰 그림은 "하나의 Rust 코어(goose crate)를 세 가지 껍데기가 둘러싼 구조"입니다. CLI는 코어를 직접 부르고, 데스크탑 앱은 goosed 서버를 자식 프로세스로 띄워 HTTP로 이야기합니다.
부품 이름만 외우면 금방 길을 잃으니, 대표 흐름 하나를 입구부터 출구까지 따라가 봅니다. 해피패스(정상 경로)만 봅니다 — 에러 처리·재시도는 생략.
# 메시지 한 통의 여행 (해피패스) 1. 입력 → Electron UI에서 메시지 전송 2. HTTP → goosed의 routes/reply.rs 가 받음 3. 루프 시작 → 코어 Agent::reply() 호출 → AgentEvent 스트림 반환 4. 두뇌 → Provider.stream() 으로 LLM에 메시지+도구 목록 전달 5. 도구? → LLM이 "도구 쓰겠다" 하면 ExtensionManager가 MCP로 해당 확장 실행 (진행 알림도 스트림에 합류) 6. 반복 → 도구 결과를 다시 4번으로 (max_turns 한도까지) 7. 출력 → 이벤트가 SSE(text/event-stream)로 UI에 실시간 전달 8. 저장 → 대화는 sqlx로 SQLite에 기록 (다음 세션에 복원)
레스토랑으로 치면 Electron 앱은 홀, goosed는 주문 창구, 코어의 Agent는 주방장입니다. 주방장은 레시피(프롬프트)를 보고 → 필요한 재료를 창고(MCP 도구)에서 가져오고 → 맛을 보고 부족하면 다시 가져오기를 반복한 뒤 → 접시가 완성되는 과정을 실시간 중계(SSE)로 홀에 흘려보냅니다. 손님은 요리가 끝날 때까지 깜깜이로 기다리지 않아도 됩니다.
프로바이더 추상화(providers/base.rs)의 trait를 보면 필수 메서드는 stream() 하나뿐이고, 한 번에 다 받는 complete()는 스트림을 끝까지 모아서 만드는 디폴트 구현입니다. "스트리밍을 나중에 덧붙이는" 흔한 설계를 뒤집은 것으로, LLM 시대 API 설계의 모범 답안입니다.
// crates/goose/src/providers/base.rs (개념 발췌) trait Provider { async fn stream(&self, ...) -> Result<MessageStream, ProviderError>; // 필수 async fn complete(&self, ...) -> ... { collect_stream(self.stream(...)).await // 디폴트: 스트림을 모아서 반환 } }
프로바이더는 두 방식으로 등록됩니다. Anthropic·OpenAI처럼 로직이 필요한 34종은 providers/init.rs에서 registry.register::<T>()로 타입 등록하고, groq·deepseek·mistral처럼 OpenAI 호환 API면 providers/declarative/에 JSON 파일 하나만 두면 끝(29종)입니다. 코드를 안 짜고도 프로바이더를 추가하는 길을 따로 닦아둔 것 — 플러그인 시스템 설계에서 배울 만한 "쉬운 길/어려운 길" 이원화입니다.
데스크탑 앱이 Rust 코어를 쓰는 방법으로 goose는 FFI(언어 간 직접 호출)가 아니라 사이드카(sidecar)를 골랐습니다. ui/desktop/src/goosed.ts가 goosed 실행 파일을 자식 프로세스로 띄우고 HTTP로 대화합니다. 결합도가 낮아져 같은 goosed에 CLI·웹·외부 도구도 붙을 수 있고, 원격 goosed에 접속하는 옵션까지 자연스럽게 열립니다.
에이전트가 생성한 코드를 그냥 셸에서 돌리면 위험합니다. goose는 vendor/v8로 V8 엔진을 직접 묶고(deno_core 경유), platform_extensions/code_execution.rs의 "코드 모드"에서 격리된 자바스크립트 샌드박스 안에 LLM 생성 코드를 가둬 실행합니다. 보안과 기능을 맞바꾸지 않으려는 의지가 빌드 비용(V8 vendoring)을 감수하게 한 사례입니다.
| 파일 | 왜 여기부터 |
|---|---|
| Justfile | 빌드·실행 명령이 다 모여 있어 프로젝트의 "조작 패널"을 한눈에 파악 |
| crates/goose/src/agents/agent.rs | 에이전트 루프의 심장. reply()부터 읽으면 전체 흐름이 보임 |
| crates/goose/src/providers/base.rs | Provider trait — "두뇌 교체 자유"가 코드로 어떻게 구현되는지 |
goose 코어는 도메인별 폴더 + mod.rs 컨벤션을 따른다. 폴더 이름이 곧 기능(agents·providers·session·recipe)이고, 큰 파일이 꽤 있다(agent.rs 3,400줄·extension_manager.rs 2,900줄). Rust 프로젝트에서 "파일이 크다 = 나쁘다"가 아니라 관련 로직을 한 모듈에 모으는 스타일도 흔하다는 걸 보여주는 사례다.
crate 10개가 "코어 라이브러리 / CLI / 서버 / SDK"로 책임을 나눠 갖고, 의존성 버전은 루트의 [workspace.dependencies] 한 곳에서 관리됩니다. 실습: 작은 Rust 프로젝트를 lib + cli + server 3-crate 워크스페이스로 쪼개고, 공통 의존성을 workspace로 끌어올려 보기.
Provider trait 하나로 60개 넘는 LLM 서비스를 갈아끼우는 구조는 전략 패턴(Strategy Pattern)의 대규모 실전 사례입니다. 실습: "텍스트 요약기" trait를 정의하고 OpenAI 호환 API용 구현과 로컬 더미 구현 두 개를 만들어, 런타임에 골라 쓰는 미니 레지스트리 작성하기.
goose는 MCP(도구 연결)와 ACP(에이전트 간 대화)를 모두 1급으로 구현한 드문 레포입니다. 특히 ExtensionConfig enum이 stdio·HTTP 스트리밍·내장·인라인 파이썬 등 7가지 연결 방식을 하나의 타입으로 다루는 부분이 교재감입니다. 실습: rmcp(Rust)나 공식 Python SDK로 "오늘 날씨를 알려주는" MCP 서버를 만들어 goose에 stdio 확장으로 연결해 보기.
FFI 대신 자식 프로세스 + HTTP를 택한 trade-off(결합도↓ vs 프로세스 관리 비용↑)를 ui/desktop/src/goosed.ts에서 직접 확인할 수 있습니다. 실습: 아무 언어로 짠 로컬 HTTP 서버를 Electron(또는 Tauri)에서 spawn하고, 종료 시 자식 프로세스를 깨끗이 정리하는 수명주기 코드 작성하기.
Rust(utoipa) → OpenAPI → TypeScript(@hey-api/openapi-ts)로 이어지는 단일 진실원 파이프라인은 어떤 풀스택 프로젝트에도 이식 가능한 패턴입니다. 실습: FastAPI나 axum+utoipa로 작은 API를 만들고, 그 OpenAPI 스펙에서 프론트엔드 클라이언트를 자동 생성해 수동 fetch 코드와 비교하기.
| 항목 | 요구사항 |
|---|---|
| 그냥 쓰기 | macOS · Linux · Windows용 데스크탑 앱 설치(권장), 또는 CLI 설치 스크립트 |
| LLM 연결 | 프로바이더 API 키 1개 이상, 로컬이면 Ollama, 또는 Claude/ChatGPT/Gemini 구독(ACP) |
| 소스 빌드 — Rust | rust-toolchain.toml 기준 Rust 1.92 (workspace 최소 1.91.1) |
| 소스 빌드 — UI | Node 24.10+ · pnpm 10.30+ (ui/desktop engines 기준) |
| 빌드 체감 | V8 vendoring 때문에 첫 빌드가 무겁다 — 시간·디스크 여유 필요. Nix flake로 환경 재현 가능 |
| 데이터 저장 | 세션은 로컬 SQLite(WAL), API 키는 OS 키체인(keyring) |
goose의 developer 확장은 파일 편집·셸 실행 도구를 제공한다. 즉 LLM의 판단으로 내 컴퓨터에서 명령이 실행될 수 있다. 권한 설정(permission 모듈)과 도구 확인(confirmation) 기능을 끄지 말고, 중요한 작업 폴더는 git으로 보호한 상태에서 쓰는 습관이 안전하다.
# 가장 빠른 시작 — CLI 설치 (macOS/Linux) curl -fsSL https://github.com/aaif-goose/goose/releases/download/stable/download_cli.sh | bash # 소스로 개발해 보고 싶다면 git clone --depth 1 https://github.com/aaif-goose/goose cd goose just run-server # goosed 서버 띄우기 just run-ui # Electron 데스크탑 개발 모드 (pnpm 필요)
데스크탑 앱을 설치하고 프로바이더 하나를 연결한 뒤, "이 폴더의 파일들을 정리해 README 초안을 써줘" 같은 멀티스텝 작업을 시켜 본다. 에이전트가 도구를 고르고 반복하는 과정을 화면에서 관찰하며 4장의 흐름도와 대조하기.
workflow_recipes/의 YAML 레시피 하나를 열어 instructions·extensions·파라미터가 어떻게 선언되는지 분석하고, 내 업무 하나(예: 주간 보고 초안)를 recipe로 작성해 goose recipe validate로 검증해 본다.
Python 공식 MCP SDK로 도구 1개짜리 MCP 서버(예: 사내 위키 검색 흉내)를 만들고, goose에 stdio 확장으로 등록해 에이전트가 실제로 호출하게 만든다. 어떤 스키마를 줘야 LLM이 도구를 "잘 고르는지" 설명문을 다듬어 보기.
crates/goose/src/providers/declarative/의 JSON 하나를 본떠, OpenAI 호환 API를 제공하는 다른 서비스(또는 로컬 vLLM)를 코드 수정 없이 JSON만으로 등록해 본다. "쉬운 확장 경로"가 어떻게 설계됐는지 체감하는 과제.
agents/agent.rs의 reply() → reply_internal()을 읽고, max_turns·컨텍스트 압축·도구 호출 분기를 포함한 상태 다이어그램을 직접 그린다. tokio::select!로 알림과 결과를 한 스트림에 합치는 tool_stream()까지 따라가면 비동기 Rust 실전 독해 완성.
아무 언어로 "LLM 호출 → 도구 호출 파싱 → 실행 → 결과 재투입"을 도는 100줄짜리 에이전트 루프를 짜 본다. goose가 왜 스트리밍 우선 trait·이벤트 enum·세션 영속화를 뒀는지, 직접 만들며 결핍으로 배우는 과제.
| 주차 | 학습 주제 | 실천 목표 |
|---|---|---|
| 1주차 | 에이전트 개념·goose 사용 | 데스크탑+CLI 설치, 프로바이더 연결, 멀티스텝 작업 5개 실행 |
| 2주차 | MCP 표준 | MCP 스펙 읽기, 도구 1개짜리 서버 제작·연결 |
| 3주차 | 비동기 Rust 기초 | tokio·async-stream 튜토리얼, 작은 스트리밍 CLI 작성 |
| 4주차 | goose 코어 정독 | agent.rs·providers/base.rs·extension_manager.rs 독해·도식화 |
| 5주차 | axum 서버 패턴 | SSE 스트리밍 엔드포인트 + utoipa OpenAPI 생성 실습 |
| 6주차 | Electron 사이드카 | 웹 UI + 네이티브 백엔드 프로세스 관리 미니앱 |
| 7주차 | ACP·에이전트 상호운용 | goose acp 모드 실험, 에디터(Zed 등)와 연결 구조 이해 |
| 8주차 | 나만의 에이전트 | recipe+MCP 확장 조합으로 실제 업무 자동화 1건 완성 |
| 링크 | 설명 |
|---|---|
| GitHub 저장소 | 소스 전체. Justfile·crates/goose/가 출발점 |
| 공식 Quickstart | 설치·첫 실행 가이드 |
| ACP 프로바이더 가이드 | Claude/ChatGPT/Gemini 구독 연결 방법 |
| AAIF (Agentic AI Foundation) | goose가 속한 Linux Foundation 산하 재단 |
| MCP 공식 사이트 | 도구 연결 표준 스펙·SDK |
| GOVERNANCE.md | 재단 이관 후의 프로젝트 운영 구조 |
| CUSTOM_DISTROS.md | 나만의 goose 배포판 만들기(프로바이더·브랜딩 프리셋) |