코딩 에이전트에서 D2B 사용하기
D2B에는 에이전트용 경로가 두 가지 있습니다. MCP(툴 호출: Claude Code / Claude Desktop / Cursor / VS Code 등)와 CLI(d2b: 셸 기반 에이전트, git 동기화, 일괄 처리). 두 경로의 표면은 같습니다: JSON 출력, suggested_fix가 붙은 오류, 모든 변경에 멱등 키, 대화형 프롬프트 없음.
운용 규범은 서버가 전달합니다. MCP로 연결하면 초기화 응답의 instructions에 「어떤 도구를 어떤 순서로」의 규범이 담기고, 같은 문장을 d2b://guide 리소스로도 읽을 수 있습니다. 리포지토리에 긴 절차를 붙일 필요는 없고, 연결과 경로 선택만 붙입니다(아래).
셋업(사람이 할 일)
섹션 제목: “셋업(사람이 할 일)”- 최소 권한 PAT 발급 — 에이전트에는 workbook 범위 + 속도 제한 토큰을 권장합니다(워크스페이스 단위로 맡기려면
"resource": "workspace:<WS_ID>"; 생성도 그 워크스페이스에 고정됩니다. 토큰은 항상 하나의 계정에 속하며account_id를 생략하면 기본 계정입니다):
curl -X POST $BASE/api/v1/me/tokens -H "Authorization: Bearer $JWT" \ -d '{"name": "agent", "scopes": ["workbooks:read", "workbooks:write"], "resource": "workbook:<WB_ID>", "rate_limit_per_minute": 60}'- 연결 — MCP라면 Claude Code는 명령 하나입니다(다른 호스트: MCP로 연결하기):
claude mcp add d2b --transport http https://d2b.dev/mcp/ --header "Authorization: Bearer $PAT"리포지토리 쪽은 d2b init가 씁니다 — 아래 AGENTS.md 절을 추가하고, 어떤 호스트에도 붙일 수 있는 표준 MCP 항목을 출력합니다. 알려진 호스트는 --host claude-code|cursor|vscode|codex|windsurf|claude-desktop로 설정 파일에 바로 병합하고, 그 외는 --config PATH(JSON / TOML)로 임의의 파일에 씁니다. 토큰은 환경 변수 참조로 두고 파일에는 쓰지 않습니다.
CLI라면 D2B_API_KEY / D2B_BASE_URL을 export하고(Claude Code는 .env를 자동으로 읽지 않습니다) pipx install d2b-sdk 또는 uvx --from d2b-sdk d2b로 설치합니다(프로젝트 의존성이면 uv add d2b-sdk + uv run d2b).
리포지토리에 붙이는 스니펫(연결과 선택만)
섹션 제목: “리포지토리에 붙이는 스니펫(연결과 선택만)”규범은 서버에서 오므로 절차를 여기에 복제하지 마세요. 복제본은 새 도구를 따라가지 못해 낡습니다.
## D2B- 데이터 작업은 D2B로 한다. MCP 서버 `d2b`가 연결되어 있다 — 먼저 `d2b://guide`의 규범을 따른다.- git으로 관리할 때(`d2b pull` / `d2b push`)와 일괄 처리는 CLI `uvx --from d2b-sdk d2b ...`(JSON 출력, 인증은 env의 D2B_API_KEY / D2B_BASE_URL).- 생성 위치·파일 반입·버전 처리는 guide대로. 애매하면 사람에게 확인한다.에이전트가 따르는 규범(서버가 전달)
섹션 제목: “에이전트가 따르는 규범(서버가 전달)”instructions / d2b://guide의 요점과 CLI 대응입니다. 규범은 표면에 의존하지 않고 도구 이름만 다릅니다.
| 규범 | MCP | CLI |
|---|---|---|
| 먼저 전체를 파악한다 | list_my_data → get_schema | d2b workbooks list → d2b tables list --workbook WB |
| 생성 위치를 이름으로 확인한 뒤 만든다 | list_my_workspaces → create_workbook | d2b workspaces list → d2b workbooks create --workspace-id … |
| 파일은 참조로 반입한다(자신의 컨텍스트를 통과시키지 않는다) | ingest_url / request_upload → ingest_upload / import_cloud_file | d2b upload FILE --workbook WB --wait (d2b jobs wait JOB_ID for long runs) |
| 지저분한 표는 구조를 본 뒤 실체화한다 | ingest_file (staged) → analyze_source → update_parse_spec → materialize_source | d2b upload --mode staged → d2b sources analyze → … materialize |
| 파생은 행 편집이 아니라 transform으로 | add_transform / list_transforms | d2b transforms add; d2b pull writes them to transforms/ |
| 409는 다시 읽고 재적용(자동 덮어쓰기 금지) | read_table로 edit_version을 다시 읽는다 | d2b tables rows NAME --workbook WB로 edit_version을 다시 읽는다 |
| 구간마다 버전을 끊어 되돌릴 수 있게 한다 | commit_snapshot / restore_snapshot / undo_op | d2b versions commit / d2b versions revert |
| 보고하기 전에 숫자를 확인한다 | review_table / review_workbook (agent 모드는 작업을 get_job으로 기다림) | d2b review --workbook WB [--table NAME] [--agent] |
| 정리한다 | delete_workbook | d2b workbooks delete WB |
워크북을 git으로 관리하기(CLI)
섹션 제목: “워크북을 git으로 관리하기(CLI)”d2b pull --workbook $WB로 transforms/ sheets/ charts/ + d2b.json이 나옵니다(--data TABLE로 base 테이블의 CSV도). 편집 → d2b push --dry-run으로 확인 → d2b push --commit $(git rev-parse --short HEAD) → d2b.json 커밋. push는 변경분만 보내고(transform은 재실행, data는 3-way merge), 거부되면 pull 후 병합하고 다시 push. charts/는 읽기 전용. 자세한 내용: 워크북을 git으로 관리하기.
원본 서식을 따르는 편집(revise = 해당 행만 고쳐 원본 Excel로 반환)
섹션 제목: “원본 서식을 따르는 편집(revise = 해당 행만 고쳐 원본 Excel로 반환)”“원본 Excel을 통째로 유지한 채, 해당하는 행만 고쳐 새 파일로 내보낸다”는 revise 1회 호출로 할 수 있습니다(내부에서 analyze → materialize → transform → 되써넣기를 접어 넣습니다). 계산은 서버 쪽 SQL 변환으로 남고(lineage 취득 가능), 스타일·차트·다른 시트·영역 밖의 수식은 그대로 유지됩니다.
d2b sources revise equipment.xlsx --workbook $WB \ --transform-name merge_tokyo_sites --range A3:N8 --sheet Summary \ --sql-file merge.sql -o output.xlsxmerge.sql은 {{ artifact_name }} 뷰입니다({{ src }}에 대상 영역 테이블이 바인딩됩니다). 행을 접는 집계의 올바른 작성법:
- 가산 컬럼(대수·건수·금액)은
SUM. - 비율(가동률·완료율)은 평균하지 않습니다. 합산 후에 재계산합니다:
SUM(분자) / NULLIF(SUM(분모), 0). - 평균(MTBF·MTTR 등)은 단순 평균이 아니라 가중 평균:
SUM(값 * 가중치) / NULLIF(SUM(가중치), 0)(가중치는 대수·건수 등 의미 있는 컬럼). - 카테고리(평가 등)는 대표값:
arg_max(rating, units_managed). - 행 위치를 유지하려면
MIN("__d2b_row_id")를 SELECT에 넣습니다(합산 행은 첫 멤버의 위치에 들어가고, 빈 행은 그 자리에서 공백화됩니다. 다른 행은 움직이지 않습니다).
CREATE OR REPLACE VIEW "{{ artifact_name }}" ASSELECT CASE WHEN site IN ('Tokyo Site 1','Tokyo Site 2') THEN 'Tokyo' ELSE site END AS site, SUM(units_managed) AS units_managed, SUM(units_active) * 1.0 / NULLIF(SUM(units_managed), 0) AS utilization, SUM("MTBF(h)" * units_managed) / NULLIF(SUM(units_managed), 0) AS "MTBF(h)", arg_max(rating, units_managed) AS rating, MIN("__d2b_row_id") AS "__d2b_row_id"FROM {{ src }}GROUP BY 1ORDER BY MIN("__d2b_row_id")영역에 합계/소계 행(=SUM(...))이 포함되어 있어도 그 수식 셀은 덮어쓰이지 않고 보존됩니다(Excel이 재계산). 템플릿 영역보다 행을 늘리는 편집은 지오메트리를 깨뜨리기 때문에 거부됩니다(409). MCP에서는 revise_source, SDK에서는 sources.revise(...)가 같은 경로입니다.
상수를 “살아 있는 수식”으로 납품하기(formula column)
섹션 제목: “상수를 “살아 있는 수식”으로 납품하기(formula column)”상수가 놓인 컬럼(예: 가동률)을 export 시에 행별 Excel 수식으로 교체할 수 있습니다. 값 자체는 건드리지 않고, 납품 .xlsx에서의 재도출 방법만 부여하는 “배포 투영”입니다. 참조는 {컬럼명} 플레이스홀더로 작성합니다(A1 셀 주소는 불가 — 정렬이나 필터로 어긋나지 않도록 아이덴티티에 계류). 좌표는 export 시에 서버가 해결합니다.
# Deliver utilization = units_active / units_total as a live per-row formulad2b tables set-formula equipment utilization "{units_active} / {units_total}" --workbook <WB>out = client.tables.set_formula(wb, "equipment", "utilization", "{units_active} / {units_total}")out["verification"] # {checked, rows, matches, mismatches} — does it reproduce the current constants?값이 정본이므로, 쓰기는 검증 리포트를 반환합니다(그 수식이 현재 컬럼 값을 허용 오차 내에서 재현하는지). “상수를 계산식으로 교체한다”를 확인한 뒤에 납품할 수 있습니다. MCP에서는 set_formula_column / list_formula_columns / clear_formula_column. 현재의 적용 대상은 xlsx export({{ ... }}의 SQL 변환이나 revise의 원본 서식 되써넣기와 조합 가능)입니다. 함수(SUM/IF 등)는 구조 검증만 하고 수치 검증은 건너뜁니다. underline은 미지원입니다.
크로스 시트 참조: {table!column}으로 다른 테이블의 컬럼 전체 데이터 범위를 참조할 수 있습니다(여러 테이블을 1개 파일로 export했을 때, 그 컬럼이 있는 시트의 절대 참조 'rates'!$B$2:$B$N으로 컴파일). 집계 함수로 감싸서 사용합니다:
# Revenue share = this row's amount ÷ the sum of rates.weightclient.tables.set_formula(wb, "sales", "share", "{amount} / SUM({rates!weight})")client.export.tables(wb, tables=["sales", "rates"], format="xlsx")# → each share row compiles to =B2/SUM('rates'!$B$2:$B$N) (same-table {amount} relative, cross-refs absolute)참조 대상 테이블이 같은 export에 포함되지 않으면 그 수식은 해결할 수 없어 값으로 폴백합니다. VLOOKUP식 키 결합은 수식이 아니라 **JOIN 변환(add_transform)**으로 표현해 주십시오(lineage가 남습니다).
제약·주의
섹션 제목: “제약·주의”- 클라우드 샌드박스(Codex 등)에서는 egress 제한 때문에 API 도달성에 대한 허용 설정이 필요할 수 있습니다
- Bash 타임아웃이 짧은 에이전트에서는
upload --wait보다 “비동기 upload →jobs wait”의 2단계가 안전합니다