dao. (저장소: tigicion/dao-code · TypeScript · ★732 · TrendShift Daily 2위 · MIT)이 레포가 무엇을 하는 물건인가.
Claude Code 같은 도구가 '똑똑하지만 비싼 모델'을 사서 좋은 경험을 낸다면, dao-code는 '값싼 모델(DeepSeek V4) + 캐시 규율'로 같은 경험을 훨씬 싸게 낸다. 핵심 무기는 성능이 아니라 돈을 아끼는 엔지니어링이다.
dao-code(명령어 dao)는 터미널 안에서 사는 AI 코딩 비서다. 코드를 읽고, 코드를 쓰고, 셸 명령을 실행하고, 버그를 고친다 — 그 과정에서 자기 추론(reasoning)과 도구 호출을 실시간으로 흘려보여 주되, 쓰기·실행처럼 위험한 동작은 승인 게이트(approval gate) 뒤에서만 한다. 대상 모델은 DeepSeek V4이고, 1M(백만) 토큰 컨텍스트를 쓴다. 중국어 우선(Chinese-first)으로 설계됐고, 영감의 원천은 Claude Code다.
여기서 계속 나올 핵심 단어부터 이름표를 붙여 두자. 프롬프트 캐시는 "모델이 방금 읽은 앞부분을 기억해 두었다가 다음에 싸게 재활용하는 장치"이고, dao-code의 모든 비용 마법이 여기서 나온다.
트렌딩 이유 · 경쟁(특히 Claude Code) 대비 장점.
dao-code는 자신을 세 축 — 가용성(Availability) · 비용(Cost) · 경험(Experience) — 으로 설명한다. 이 셋이 곧 주목 이유다.
① 가용성 — 에이전트는 "실제로 돌릴 수 있어야" 쓸모가 있다. Claude Code는 Anthropic 계정과 해외 네트워크가 필요해 중국 본토에선 문턱이 높고, 일부 국산 코딩 플랜은 쿼터(사용량 할당)가 부족하다. dao-code는 완전 오픈소스(MIT)이고, 기반 모델 DeepSeek가 가입 즉시·쓴 만큼 결제·본토에서 바로 접속이라 그 문턱이 없다.
② 비용 — DeepSeek는 주요 모델 중 최저가 축이고, 여기에 캐시가 얹힌다. 적중 가격이 실패의 약 1/120(두 자릿수 배 차이)이라, 시스템 프리픽스·도구 목록·기억을 바이트 단위로 고정해 적중률을 끌어올린다. 실제 오픈소스 버그 수정 7건(valibot·date-fns·es-toolkit·sqlglot·hono)을 돌린 측정치가 README에 통째로 공개돼 있다.
| 측정 항목 | 값 | 의미 |
|---|---|---|
| 총 입력 토큰 | 3,886,037 | 7개 실제 버그수정 작업 합계 |
| 캐시 적중률 | 95.8% | 과제별 85.4%~97.7% |
| 총 비용 | ¥1.07 | 기능 1개당 평균 ¥0.15 (읽기+수정+테스트+자가검토) |
| vs Claude Opus 4.8 | 약 30배 저렴 | 같은 토큰 트레이스를 각 공식 요금으로 환산 |
| vs Claude Sonnet 4.6 | 약 18배 저렴 | 동일 비교(캐시 이점은 상대에게도 유리하게 적용) |
③ 경험 — 단순히 싼 게 아니라, 비싼 모델이 주던 '똑똑한 경험'을 캐시로 흉내 낸다. 세션을 넘나드는 기억, 막혔을 때 스스로 의심하는 반성 레이어, 긴 작업이 삼천포로 빠지지 않게 하는 재초점(refocus) — 이 셋을 모두 '메인 캐시를 재활용하는 분신(fork)'에서 돌려 추가 비용을 거의 안 들인다. 그리고 이 모든 수치를 /cost 명령으로 언제든 재생·검증할 수 있게 열어 둔 '검증 가능성'이 신뢰를 준다.
세션 간 기억·자가 교정 같은 고급 경험을 얻으려면 보통 매 요청에 많은 문맥을 다시 넣어야 하고, 비싼 모델일수록 그 비용이 눈덩이처럼 커진다. 장시간 자율 작업은 특히 토큰을 태운다.
앞부분(프리픽스)을 절대 흔들지 않고 고정해 캐시 적중률을 극대화하고, 반성·기억은 그 캐시를 그대로 물려받은 분신에서 돌린다. 그래서 '고급 경험'의 추가 요금이 거의 0에 수렴한다. 같은 결과를 30배 싸게.
터미널 UI부터 모델·빌드까지 한눈에.
놀라운 점부터: 런타임 의존성이 딱 6개다. HTTP 라이브러리(axios)도, 인자 파서(commander)도, 벤더 SDK(openai)도 없다 — 대부분 직접 구현했다. 그만큼 "군더더기 없이 캐시·프리픽스를 손수 통제"하겠다는 설계 의지가 읽힌다.
| 레이어 | 기술 / 버전 | 역할 |
|---|---|---|
| 언어 | TypeScript 5.6 (ESM, 85.4%) | 전체 코드베이스. 타입 안전. |
| 터미널 UI | Ink 7 + React 19 | React 문법으로 터미널 화면을 그림(TUI). |
| 코드 색칠 | cli-highlight | diff·코드 블록 구문 강조. |
| 모델 | DeepSeek V4 (pro / flash) | 추론 엔진. 자체 streamChat로 스트리밍 호출. |
| 스키마/검증 | Zod + zod-to-json-schema | 도구 입력 검증 + 도구 정의를 모델용 JSON Schema로 변환. |
| 확장 프로토콜 | @modelcontextprotocol/sdk 1.29 | MCP 서버 연결(외부 도구 붙이기). |
| 런타임 | Node.js ≥20 | 실행 환경. |
| 빌드 | tsc → dist · bun build --compile | 라이브러리 빌드 + 의존성 없는 단일 실행 바이너리 생성. |
| 테스트 | Vitest 2 + ink-testing-library | 단위 테스트 + TUI 컴포넌트 테스트. |
<div>를 쓰듯, Ink에선 <Box>·<Text>로 터미널 화면을 컴포넌트로 조립한다. 그래서 dao-code의 화려한 화면(태극 스플래시, 실시간 스트리밍, 할 일 체크리스트)이 React 코드로 만들어진다. TUI는 그렇게 만든 '글자로 된 UI'를 부르는 말.zod-to-json-schema로 모델이 이해하는 JSON Schema 형식으로 바꿔 "너는 이런 도구들을 이런 인자로 부를 수 있어"라고 알려 준다. 규격 한 곳(Zod)만 고치면 검증과 모델 노출이 동시에 맞춰진다.먼저 전체 그림, 그다음 요청 한 줄기를 끝까지 따라가기.
dao-code의 심장은 에이전트 루프(agent loop) 하나다. "모델에게 물어본다 → 모델이 도구를 쓰겠다고 하면 승인 받고 실행한다 → 결과를 다시 모델에게 준다 → 모델이 더 이상 도구를 안 쓸 때까지 반복"이 전부다. 먼저 숲을 보자.
이제 대표 흐름 딱 한 줄기를 손으로 따라가 보자. 사용자가 이렇게 쳤다고 하자: dao "src/utils.ts의 formatDate를 타임존 인식하게 고쳐줘". 핵심 5% 경로(해피 패스)만 본다.
여기서 이 프로젝트 특유의 '정상 모양새'를 하나 짚자. 위 루프가 도는 내내 모델에게 보내는 맨 앞부분(시스템 지시 + 도구 목록 + 기억)은 한 글자도 바뀌지 않게 고정돼 있다. 이게 byte-stable prefix(바이트 고정 프리픽스)이고, 캐시 적중률의 근원이다. 반성·기억 같은 곁가지 작업은 이 고정 프리픽스를 그대로 물려받은 분신(fork)에서 돌려, 캐시를 깨지 않으면서 별도 일을 처리한다.
어떤 폴더가 무슨 일을 하나.
먼저 저장소 전체 레이아웃. 핵심은 src/ 한 채이고, 그 안이 '기능별로 방을 나눈' 구조다.
실행하면 작업 폴더에 .dao/가 생겨 '이번 작업의 모든 상태'가 여기 쌓인다. 이 폴더 구조를 알면 crash 복구·되돌리기가 어떻게 가능한지 감이 온다.
| 경로 | 역할 |
|---|---|
.dao/settings.json | 권한 규칙(allow/ask/deny). 프로젝트용은 커밋, .local.json은 커밋 제외. |
.dao/sessions/<id>/ | events.jsonl(매 턴 이벤트) + state.json(스냅샷). dao -c가 여기서 재개. |
.dao/shadow.git | 내 진짜 .git과 완전히 분리된 작업트리 스냅샷. /restore·/rewind의 근거. |
.dao/spill/ | 도구 출력이 너무 크면 여기로 '흘려' 저장하고, 문맥엔 포인터만 남김. |
.dao/agents/ · commands/ · skills/ | 사용자 정의 서브에이전트·슬래시 명령·스킬(각각 .md 파일). |
.dao/hooks.json · mcp.json | 수명주기 훅 · MCP 서버 연결 설정. |
src/agent/loop.ts | 에이전트 루프의 본체. 여길 읽으면 전체 동작이 보인다. |
이 레포에서 훔쳐 배울 만한 것 + 어느 파일을 보면 되는지.
화려한 CLI를 만들고 싶다면 이만한 교보재가 없다. 태극 스플래시, 실시간 스트리밍, diff 하이라이트, 할 일 체크리스트가 전부 React 컴포넌트다. src/의 렌더링 코드를 읽으면 "상태(state)가 바뀌면 화면이 다시 그려진다"는 React 모델이 터미널에서 어떻게 도는지 보인다.
LLM에게 "너는 이런 도구를 쓸 수 있어"를 알려 주는 표준 방법을 실전 코드로 볼 수 있다. 규격을 Zod로 한 번 적고 zod-to-json-schema로 변환하는 이 패턴은 어떤 에이전트를 만들든 재사용된다. 레지스트리는 src/index.ts, 구현은 src/tools/.
대부분의 에이전트가 더 똑똑한 모델을 좇을 때, dao-code는 프리픽스를 안 흔드는 것만으로 요금을 두 자릿수 배 줄인다. "왜 시스템 프롬프트를 매번 똑같이 유지해야 하나"를 이 레포로 체득하면, LLM 앱의 청구서를 보는 눈이 완전히 달라진다. /audit cache가 '무엇이 캐시를 깼는지'를 4차원 지문으로 짚어 준다.
에이전트가 파일을 마구 고쳐도 안심인 이유. 별도 .dao/shadow.git에 스냅샷을 떠 두고, /restore로 직전 턴을 한 번에 되돌린다. 내 진짜 .git 히스토리는 절대 건드리지 않는다. 구현은 src/session/checkpoint.ts. '위험한 자동화에 안전벨트를 다는 법'의 좋은 예.
"AI에게 어디까지 허용할까"를 규칙으로 통제하는 실전 설계다. 우선순위는 deny > ask > allow > 모드 기본값. 특히 cd /tmp && rm -rf x 같은 복합 명령을 조각조각(per-segment) 검사해 한 조각이라도 deny면 전체를 막는 부분이 백미다. 코드는 src/permissions/.
권한 규칙 문법은 도구(대상) 꼴이다. 복사만 하면 되니 겁먹지 말자:
# .dao/settings.json — "이건 허용, 저건 금지" 규칙 예시
Bash(npm run test:*) # npm run test 로 시작하는 명령만 허용
Edit(src/**) # src 아래 파일 수정 허용(gitignore식 glob)
WebFetch(domain:example.com) # 이 도메인만 웹 접근 허용
mcp__<server>__<tool> # 특정 MCP 서버의 특정 도구
# 우선순위: deny(하드 차단) > ask(물어봄) > allow(자동) — deny는 YOLO에서도 안 뚫림
순수 소프트웨어 도구라 GPU도 특수 하드웨어도 필요 없다.
| 항목 | 요구사항 |
|---|---|
| 런타임 | Node.js ≥20 (npm 설치 시). 단일 바이너리로 받으면 Node 불필요. |
| 모델 접근 | DeepSeek API 키 1개. 발급 즉시·쓴 만큼 결제(가입 후 바로). |
| OS | macOS(arm64/x64) · Linux(arm64/x64) · Windows(x64). 릴리스에 각 바이너리 제공. |
| 터미널 | 일반 터미널이면 충분. TTY가 아니면 자동으로 순수 텍스트 REPL로 폴백. |
| 비용(체감) | 실측상 기능 1개 완수 ≈ ¥0.07~0.21. 사실상 '커피 한 잔에 수백 작업' 수준. |
읽기만 하지 말고 손에 익히는 단계. 난이도순.
npx dao-code로 실행 → DeepSeek 키를 붙여 넣고 아무 질문. 그다음 /cost로 토큰·캐시 적중률을, /help로 명령 목록을 관찰한다. "캐시 적중률이 대화가 길어질수록 오르는가"를 눈으로 확인하는 게 목표.
아무 작은 저장소에서 /init을 실행해 DAO.md(프로젝트 개요·컨벤션)를 자동 생성해 본다. 이 파일이 다음 세션부터 자동 로드되는 걸 확인하고, 한 줄 규칙을 손으로 추가해 동작이 바뀌는지 본다.
.dao/settings.json에 Bash(npm run test:*)는 allow, Edit(//etc/**)는 deny로 넣어 본다. 그다음 에이전트에게 테스트 실행과 시스템 파일 수정을 각각 시켜, 하나는 자동 통과·하나는 차단되는지 확인. 복합 명령도 시험해 보자.
.dao/agents/<name>.md에 이름·설명·허용 도구·모델을 frontmatter로 적고 본문에 역할 프롬프트를 쓴다. 그런 뒤 tasks[]로 여러 개를 병렬 실행하거나 background:true로 뒤에서 돌려, 완료 알림이 <task-notification>으로 되돌아오는 흐름을 관찰한다.
EVAL_RUNS=1 node evals/run.mjs로 스모크 테스트를 돌려, 실제 오픈소스 버그가 fail→pass로 뒤집히는지 본다. 테스트 파일을 에이전트에게 숨겼다가 나중에 주입하는 reward-hacking 방지 설계가 왜 필요한지 체감하는 게 핵심.
한 주씩, 이 레포를 '해부 교보재'로 삼아 따라가는 계획.
| 주차 | 주제 | 학습 자료 / 볼 곳 |
|---|---|---|
| 1주차 | 코딩 에이전트 큰 그림 + 로컬 실행 | README 정독 · dao 실행 · /help·/cost 관찰 |
| 2주차 | 에이전트 루프의 뼈대 | src/agent/loop.ts · "도구 요청→승인→되먹임" 흐름 추적 |
| 3주차 | 프롬프트 캐시 경제학 | DeepSeek 캐시 요금 문서 · byte-stable prefix 개념 · /audit cache |
| 4주차 | 도구·권한 시스템 | src/tools/ · src/permissions/ · Zod→JSON Schema 패턴 |
| 5주차 | 기억 · 반성 레이어 | src/memory/ · challenger/refocuser 설계 읽기 |
| 6주차 | 확장(스킬·MCP·훅) + 내 앱에 이식 | MCP SDK 문서 · Claude Code 호환 포맷 비교 |
본문에 나온 용어 빠른 참조.
| 용어 | 의미 |
|---|---|
| prefix cache | 모델에 보낸 앞부분(프리픽스)의 계산 결과를 서버가 저장해 재사용 → 그 부분 요금이 급감. dao-code 비용 마법의 근원. |
| byte-stable prefix | 그 앞부분을 한 바이트도 바꾸지 않고 유지하는 규율. 조금만 달라져도 캐시가 '실패' 처리돼 요금이 튄다. |
| cache-reusing fork | 메인 대화의 캐시된 프리픽스를 그대로 물려받은 '분신'. 반성·기억을 여기서 돌려 추가 비용 ≈ 0. |
| agent loop | "모델에 질문 → 도구 요청 실행 → 결과 되먹임 → 반복"의 핵심 순환. src/agent/loop.ts. |
| approval gate | 쓰기·실행 같은 위험 동작을 실제 수행 전에 사람 승인으로 거르는 관문. |
| permission mode | 승인 강도 설정: default(그때그때) / acceptEdits(수정 자동) / auto(AI가 안전분류) / plan(읽기전용) / YOLO(전부 자동, deny만 예외). |
| Ink / TUI | React로 터미널 화면을 그리는 라이브러리 / 그렇게 만든 글자 기반 UI. |
| MCP | Model Context Protocol. 에이전트에 외부 도구·데이터를 표준 방식으로 붙이는 규약. |
| Zod | 데이터 모양을 코드로 검증하는 TS 라이브러리. 도구 규격의 단일 출처. |
| shadow git | 사용자 .git과 분리된 별도 스냅샷 저장소. 되돌리기(/restore)의 안전벨트. |
| compaction | 1M 문맥 한계 근처에서 오래된 대화를 요약으로 압축해 자리를 비우는 것. |
| reflection layer | 막힘/드리프트 자가 교정. challenger(전제 의심) · refocuser(목표 재확인) · reply-challenger(같은 문제 재질문 감지). |
| DoD (Definition of Done) | "완료의 정의". /dod로 설정한 명령이 성공(exit 0)해야만 작업을 끝난 것으로 인정. |
| fail2pass / pass2pass | 평가 이중 검증: 수정 후 대상 테스트가 실패→통과로 뒤집히고(fail2pass), 기존 기능 테스트는 여전히 통과(pass2pass). |
| steering | 모델이 답하는 도중에 사용자가 미리 타이핑해 두면 큐에 쌓였다가 현재 턴이 끝나면 자동 처리되는 기능. |
| DeepSeek V4 (pro / flash) | 기반 모델. pro는 주력 추론, flash는 값싼 보조(기억 distill 등)에 쓰는 경량판. |