10만 스타의 미니멀 Agent harness 'Pi' 분석
AI 프로그래밍 Agent 분야가 Claude Code, Cursor, OpenCode, Codex CLI 등으로 기능 경쟁을 벌이는 가운데 10만 스타를 받은 미니멀 Agent harness 'Pi'를 정리한 글…
중국어 원문을 AI로 번역했습니다. 고유명사와 수치는 원문 표기를 우선하며, 중요한 판단에는 아래 출처 원문을 함께 확인하세요.
안녕하세요, 저는 松柏입니다.
올해 AI 프로그래밍 Agent 분야는 경쟁이 정말 치열했습니다. Claude Code, Cursor, OpenCode, Codex CLI 모두 기능을 미친 듯이 쌓아 올리고 있습니다. 펫, sub-agents, plan mode, MCP, 확장 마켓까지, 생각할 수 있는 것은 전부 집어넣으려고 합니다.
그런데 한 프로젝트는 오히려 반대로 갑니다. 바로 Pi, 극미니멀을 표방하는 Agent Harness입니다:
기본적으로 모델에 4개의 도구만 제공합니다: read, write, edit, bash. 시스템 프롬프트에 도구 정의를 더해도 총 1000 tokens가 채 안 됩니다.
이렇게까지 미니멀한 물건인데도 GitHub 10만+ stars, npm 주간 다운로드 120만+, 3개월 만에 54k에서 98k로 늘었습니다. 이미 많은 사람이 일상 주력으로 쓰고 있습니다:
이 글에서는 먼저 Pi를 빠르게 시작하는 방법을 안내하고, 그다음 핵심 설계 철학과 계층형 아키텍처를 깊이 파헤쳐 보겠습니다. 다 읽고 나면 Agent 프레임워크 설계 사고방식에 대해 새로운 인식을 갖게 될 것입니다.
서론은 이쯤 하고, 좋아요와 구독 부탁드리며 바로 시작하겠습니다!
빠른 시작
설치
한 줄 명령으로 끝납니다:
추천 방식 curl -fsSL https://pi.dev/install.sh | sh # 또는 npm npm install -g --ignore-scripts @earendil-works/pi-coding-agent
설치가 끝나면 터미널에서 바로 pi를 입력해 대화형 인터페이스에 들어갈 수 있습니다.
모델 설정
Pi는 15개 이상의 모델 제공자를 지원합니다. Anthropic, OpenAI, Google, DeepSeek, xAI, Groq, Ollama 등이 기본적으로 다 있습니다. 설정 방식도 간단합니다:
- 구독이 있다면(Claude Pro/Max, ChatGPT Plus 등), 바로 /login으로 OAuth 진행
- API Key를 쓴다면 환경 변수만 설정하면 됩니다. 예를 들어 ANTHROPIC_API_KEY
들어간 뒤 /model로 모델을 전환하고, Ctrl+P로 자주 쓰는 모델 목록을 빠르게 순환할 수 있습니다. 게다가 세션 도중에도 모델을 바꿀 수 있으며, 컨텍스트는 자동으로 제공자 간 변환이 이루어집니다. 이 부분은 뒤의 아키텍처 부분에서 자세히 다루겠습니다.
기본 사용
다른 제품과 비슷합니다. 터미널을 열고 요구사항을 입력하면 Pi가 처리해 줍니다:
대화형 모드 pi # 한 줄 호출, 스크립트나 CI에 적합 pi -p "이 함수에 단위 테스트 추가해줘"
Pi는 기본적으로 모델에 4개의 도구만 줍니다:
- read: 파일 읽기(이미지 지원)
- write: 파일 쓰기, 디렉터리 자동 생성
- edit: 정확한 텍스트 치환
- bash: 임의 명령 실행
4개는 너무 적다고 느낄 수도 있습니다. 하지만 잘 생각해 보면, bash만 있으면 파일을 검색해야 할 때 rg를 돌리고, git 로그를 봐야 할 때 git log를 돌리고, 의존성을 설치해야 할 때 npm install을 하면 됩니다. 그래서 대부분의 요구사항은 사실 전용 tool을 만들 필요 없이 bash 하나로 구현할 수 있습니다. 이것도 Pi의 핵심 설계 사고방식 중 하나입니다.
세션 관리
Pi의 세션은 일반적인 선형 기록이 아니라 하나의 트리입니다. 매 대화가 트리 구조로 저장되며, 임의의 노드에서 분기해 나갈 수 있습니다:
pi -c # 지난 세션 이어가기 pi -r # 과거 세션 목록 탐색 pi --fork < id > # 특정 과거 노드에서 새 브랜치 갈라내기
세션 안에서 /tree로 전체 대화 트리를 볼 수 있고, 어떤 노드로든 되돌아갈 수 있습니다.
네 가지 실행 모드
터미널에서 직접 상호작용하는 것 외에도, Pi에는 세 가지 헤드리스 모드가 있어 다른 곳에 통합하기 편합니다:
모드 명령 적합한 상황 Interactive pi 일상 개발, 완전한 터미널 경험 Print/JSON pi -p "query" 스크립트 호출, CI 파이프라인 RPC --mode rpc stdin/stdout JSON 프로토콜, 비 Node 프로젝트용 SDK TypeScript API 자체 애플리케이션에 임베드
이 네 가지 모드는 동일한 session 형식과 이벤트 스트림을 공유합니다. 그래서 터미널이든, Web이든, CI든 호출하면 모두 같은 Agent를 보게 됩니다. 예를 들어 OpenClaw는 Pi의 SDK 모드로 만든 완전한 제품입니다.
OK, 여기까지 기본적인 시작 흐름은 다 짚었습니다.
이제 더 흥미로운 부분, Pi는 왜 이렇게 설계했는지에 대해 얘기해 보겠습니다.
극미니멀 설계 철학
Pi의 저자 Mario Zechner는 이런 말을 했습니다: "if I don't need it, it won't be built", 쉬운 말로 하면 필요 없는 건 만들지 않는다는 것입니다. Pi의 설계 전체가 이 원칙을 중심으로 전개됩니다.
극미니멀 시스템 Prompt
먼저 Pi의 전체 시스템 프롬프트를 보겠습니다:
You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files. Available tools: - read: Read file contents - bash: Execute bash commands - edit: Make surgical edits to files - write: Create or overwrite files Guidelines: - Use bash for file operations like ls, grep, find - Use read to examine files before editing - Use edit for precise changes (old text must match exactly) - Use write only for new files or complete rewrites - Be concise in your responses - Show file paths clearly when working with files
이게 전부? 이게 전부입니다! 도구 정의를 더해도 총 1000 tokens가 채 안 됩니다.
왜 시스템 프롬프트가 이렇게 짧아야 할까요? 요즘 프런티어 모델은 대량의 RL 훈련을 거쳐 사실 이미 coding agent가 되는 법을 타고나서 알고 있기 때문입니다. 우리가 system prompt에서 일일이 어떻게 하라고 가르칠 필요가 없습니다. 모델은 스스로 도구를 고르고, 파일을 읽고, 명령을 실행합니다. Pi가 Terminal-Bench 2.0에서 받은 점수도 이를 검증합니다. 극미니멀 prompt의 효과는 만 token이 넘는 prompt에 못지않습니다:
게다가 prompt가 짧을수록 더 안정적이고, 제공자 쪽 cache가 더 쉽게 적중되어 매 요청의 비용도 더 낮아집니다.
4개의 도구
앞서 Pi에는 read, write, edit, bash 네 개의 도구밖에 없다고 언급했는데, 이는 다른 Agent들이 너댓 개씩 tool을 두는 방식과 확실히 매우 다릅니다.
Pi의 사고방식은 각 기능마다 전용 tool(검색 tool, git tool, 테스트 tool……)을 만드는 대신, bash 하나만 남기고 모델이 스스로 명령을 작성하게 하는 것입니다.
또한 도구가 적으면 좋은 점이 하나 더 있습니다. 바로 모델의 의사결정이 빨라진다는 것입니다. 도구가 많을수록 모델은 어느 것을 쓸지 더 고민하고, 심지어 잘못 고르기도 합니다. 4개의 도구는 경우의 수가 몇 가지 안 되니 선택 비용이 거의 0입니다.
전체 권한 실행
Pi는 기본적으로 어떤 권한 확인도 띄우지 않습니다. "파일 쓰기를 허용할까요"도 없고, "명령 실행을 허용할까요"도 없습니다. 모델은 도구를 받으면 바로 씁니다.
꽤 급진적으로 들리지만, 근거가 없는 것도 아닙니다. Agent가 코드를 쓰고, 코드를 실행하고, 네트워크에 연결할 수 있는 한, 소위 권한 팝업은 본질적으로 안전감을 주는 것일 뿐 실제로 막아내는 것은 없다는 것입니다. 결국 우리 자신이 승인한다 해도 계속 허용을 눌러대지 않습니까.
물론, 격리가 정말로 필요한 상황이라면 Pi도 세 가지 컨테이너화 방식을 제공합니다. Gondolin(로컬 마이크로 가상 머신), Docker, OpenShell(정책 샌드박스)을 필요에 따라 선택하면 됩니다.
일부러 만들지 않은 기능들
이 부분이 제 생각에 Pi에서 가장 흥미로운 곳입니다. 많은 Agent 제품이 판매 포인트로 내세우는 기능을 Pi는 하나도 하지 않는데, 각각에 대해 더 간단한 대안 아이디어를 제시합니다:
1) Plan Mode → 파일 작성
내장 계획 모드는 필요 없고, 그냥 PLAN.md를 작성하면 됩니다:
Goal 인증 시스템을 리팩터링해 OAuth 지원 ## Approach 1. OAuth 2.0 흐름 조사 2. token 저장 schema 설계 3. 인증 엔드포인트 구현 4. 프런트엔드 로그인 흐름 업데이트 ## Current Step 3단계 진행 중
Agent가 읽고 고칠 수 있고, 당신도 수동으로 편집할 수 있으며, git으로 버전 관리도 할 수 있습니다. Agent 내부에 숨겨진 Plan Mode보다 훨씬 투명합니다.
2) Sub-agents → bash 자기 호출
Pi는 bash를 통해 또 다른 자기 자신을 띄울 수 있습니다:
pi -p "review this PR" --provider anthropic --model claude-sonnet-4-5
tmux에 넣어 돌릴 수도 있고, 전 과정에서 하위 Agent가 무엇을 하는지 볼 수 있습니다. 이에 비해 Claude Code의 sub-agent는 블랙박스라서, 최종 결과만 볼 수 있고 중간 과정은 완전히 불투명합니다.
3) MCP → CLI 도구 + README
MCP의 문제는 컨텍스트 오버헤드입니다. 예를 들어 Playwright MCP는 등록만 해도 21개의 tool, 13.7k tokens를 차지합니다. 이번에 쓰든 안 쓰든 창을 차지합니다. Pi의 방식은 평범한 CLI 도구로 만들고 README 하나를 붙여서, Agent가 필요할 때 bash로 호출하고 겸사겸사 README를 읽어 사용법을 보게 하는 것입니다. 실제로 쓸 때만 token 비용을 치릅니다.
4) 백그라운드 프로세스 → tmux
백그라운드에서 dev server를 돌려야 하나요? tmux로 하나 띄우면 됩니다:
tmux new-session -d -s dev "npm run dev"
Agent는 언제든 tmux capture-pane으로 로그 출력을 볼 수 있어, 내장 백그라운드 bash 기능보다 더 유연하고 관측성도 더 좋습니다.
계층형 아키텍처 해부
설계 이념을 다뤘으니, 이제 Pi의 코드가 어떻게 구성되어 있는지 보겠습니다.
Pi는 TypeScript 모노레포로, 핵심은 네 계층으로 나뉘며 아래에서 위로 순서대로 다음과 같습니다:
pi-ai: 통합 다중 모델 API
가장 아래 계층의 패키지로, 각 LLM 제공자의 API를 하나의 통합 인터페이스로 추상화합니다. 밑에서는 사실 네 가지 프로토콜만 연결하면 됩니다. OpenAI Completions, OpenAI Responses, Anthropic Messages, Google Generative AI. 각 제공자는 기본적으로 이 네 가지 API의 어떤 변형입니다.
이 계층에는 배울 만한 설계 포인트가 몇 가지 있습니다:
먼저 제공자 간 컨텍스트 릴레이입니다. 세션 도중 Claude에서 GPT로 전환할 수 있으며, pi-ai는 Claude의 사고 사슬(chain of thought)을 <thinking> 태그로 바꿔 메시지에 넣어, 새 모델이 이전 컨텍스트를 최대한 이해할 수 있게 합니다. 코드로는 대략 이렇습니다:
// Claude로 대화 시작 const claude = getModel('anthropic', 'claude-sonnet-4-5'); context.messages.push({ role: 'user', content: '25 * 18 = ?' }); const claudeResponse = await complete(claude, context); // 중간에 GPT로 전환, 컨텍스트 자동 변환 const gpt = getModel('openai', 'gpt-5.1-codex'); context.messages.push({ role: 'user', content: '맞아?' }); const gptResponse = await complete(gpt, context);
다음은 전 구간 Abort 지원입니다. 많은 LLM 래핑 라이브러리는 요청 중단 상황을 아예 처리하지 않습니다. pi-ai는 처음부터 AbortController를 지원하며, 중단된 뒤에도 이미 생성된 부분 결과를 얻을 수 있어 중단됐다고 전부 잃어버리지 않습니다.
또한 도구 결과 분리도 있습니다. 도구 하나가 실행을 마치면 "LLM에게 보여줄 텍스트"와 "UI에 표시할 구조화 데이터"를 각각 반환할 수 있어, 이제 잔뜩 쌓인 텍스트 출력에서 힘들게 파싱할 필요가 없습니다.
pi-agent-core: Agent 루프
중간 계층으로, Agent의 핵심 실행 루프를 구현한다: 사용자 메시지 수신 → LLM 호출 → LLM이 도구를 사용하려 함 → 실행 → 결과를 다시 먹임 → 다시 LLM 호출 → 더 이상 도구가 필요 없을 때까지 반복.
이 계층의 핵심 클래스는 Agent이며, 상태(메시지 히스토리, 도구 목록, 현재 모델)를 관리하는 것 외에도 두 가지 메시지 큐를 제공한다:
- Steering: Agent가 작업하는 동안 한마디를 끼워 넣으면, 현재 도구가 실행을 마치면 처리된다
- Follow-up: 큐에 대기하다가, Agent가 이번 라운드를 다 마친 뒤에 처리된다
전체 루프는 이벤트 기반이며, 모든 생명주기 노드는 AgentEvent를 통해 노출되므로, 상위 계층은 이벤트를 받아 각종 UI를 구성할 수 있다.
pi-coding-agent: 코딩 Agent CLI
애플리케이션 계층, 즉 실제로 여러분이 입력하는 pi 명령이며, 핵심은 AgentSession으로, Agent 루프 위에 다음을 더했다:
- 세션 지속성: JSONL 형식의 트리형 저장으로, 각 메시지에 id와 parentId가 있어 분기 작업에 새 파일을 만들 필요가 없다
- 자동 압축: 컨텍스트가 거의 찰 때 오래된 메시지를 자동 compaction하며, 압축 전략은 확장을 통해 사용자 정의할 수 있다
- 도구 등록: read/write/edit/bash를 내장하고, 그 외에 grep/find/ls 세 가지 읽기 전용 도구를 선택적으로 제공
- 확장 로딩: jiti로 TypeScript를 동적으로 로드하여, 작성 후 컴파일 없이 바로 실행
앞서 언급한 네 가지 실행 모드가 바로 이 계층에서 구현되며, 이들은 동일한 session과 이벤트 스트림을 공유한다.
pi-tui: 차분 렌더링 터미널 UI
Pi의 터미널 UI는 Amp, OpenCode처럼 터미널 화면 전체를 점유하지 않고, 일반 CLI처럼 아래로 내용을 써 내려가며 터미널 자체의 스크롤과 검색을 보존한다.
렌더링 방식은 유지 모드(Retained Mode)다: 각 컴포넌트에는 render(width) 메서드가 있어 ANSI 스타일이 포함된 텍스트 줄을 반환한다. 이미 스트리밍 출력이 끝난 메시지는 렌더링 결과를 캐시해 두고 다음에 그대로 재사용한다.
업데이트할 때는 차분 렌더링을 사용해, 새 프레임과 옛 프레임을 줄 단위로 비교하여 변경된 부분만 다시 그린다. 여기에 터미널의 동기 출력 이스케이프 시퀀스(CSI ?2026h / CSI ?2026l)를 함께 사용해, 한 프레임의 모든 출력을 모아 원자적으로 화면에 밀어 넣어 Ghostty와 iTerm2에서 기본적으로 깜빡임 없는(zero flicker) 수준을 구현했다.
확장 시스템
Pi의 확장 메커니즘은 세 계층으로 나뉜다:
Extensions(코드 레벨)
TypeScript 모듈로, 도구를 등록하고, 명령을 추가하고, 단축키를 바인딩하고, 도구 호출을 가로채고, UI 컴포넌트를 사용자 정의할 수 있다. 예시 코드:
// ~/.pi/agent/extensions/my-tool.ts import type { ExtensionAPI } from '@earendil-works/pi-coding-agent' ; import { Type } from 'typebox' ; export default function ( pi: ExtensionAPI ) { pi. registerTool ({ name : 'search_docs' , description : '搜索项目文档' , parameters : Type . Object ({ query : Type . String () }), async execute ( id, params, ctx ) { const result = await searchIndex (params. query ); return { content : [{ type : 'text' , text : result }] }; } }); }
저장 후 /reload로 핫 리로드하며, 재시작이 필요 없다. 공식 저장소에는 50+ 예시가 있으며, 권한 확인, Git 체크포인트부터 Snake 미니게임까지 있다.
Skills(프롬프트 레벨)
Skills는 Markdown 파일로, 특정 작업의 지시와 워크플로를 정의한다. Extensions와의 핵심 차이는 필요할 때 로드한다는 점으로, 평소에는 컨텍스트에 한 줄 설명(수십 개 token)만 남겨 두고, 실제로 트리거될 때 전체 내용을 로드한다.
이렇게 하면 수십 개의 Skill을 설치해도 컨텍스트 윈도우를 터뜨리지 않는데, 이른바 "점진적 컨텍스트 공개"다.
Packages(생태계 패키징)
Extensions, Skills, Prompt Templates, Themes를 모두 하나의 Package로 패키징해 npm 또는 git으로 설치할 수 있다:
pi install npm:pi-autoresearch pi install git:github.com/badlogic/pi-doom
Shopify의 pi-autoresearch
Package라 하면, 현재 가장 화제가 된 하나를 빼놓을 수 없는데, Shopify 엔지니어 David Cortés가 만든 pi-autoresearch다.
이것은 자동화 성능 최적화 루프다: 최적화할 지표(예를 들어 빌드 시간)를 설정하면, Agent가 자동으로 코드 수정을 시도하고, benchmark를 돌리고, 베이스라인보다 빠르면 유지하고 느리면 롤백한 다음, 다음 라운드를 계속하며, 여러분이 중단할 때까지 반복한다.
가장 흥미로운 점은, 이 확장 자체가 Pi에게 작성하게 한 것이다.
나중에 Shopify CEO Tobi Lütke가 이것을 보고 직접 나서서 32개의 commit을 기여했다. 현재 pi-autoresearch는 GitHub에서 7900+ star를 기록했고, Shopify 내부에서는 이것으로 단위 테스트 속도를 300배 높였으며, React 컴포넌트 마운트가 20% 빨라졌다.
맺음말
저는 Pi라는 프레임워크에서 가장 배울 만한 점이 기능이 많을수록 좋은 게 아니라, 핵심적인 것을 제대로 해내면 된다는 것이라고 생각합니다. 여러분은 어떻게 생각하시나요?
이 글은 여기까지입니다. 도움이 되셨다면 팔로우 부탁드립니다~
다음 회에 봐요, 안녕👋🏻
co松柏
Java 백엔드 개발자 @위챗 공식계정 | co松柏
25
글
46k
읽음
73
팔로워