원문 캡처 · github.com
원문 캡처 · github.com

dbprint는 데이터베이스 구조와 실제 값의 통계, 사람이 덧붙인 설명을 저장소에 텍스트로 기록해 코딩 에이전트가 데이터베이스에 연결하지 않고도 읽게 하는 도구다. 제작자는 여러 코드베이스에서 진행한 테스트에서 주석이 달린 출력물을 읽은 에이전트가 오답을 80% 적게 냈고, 정답 하나당 비용은 17% 낮았다고 밝혔다. 출력물에만 적힌 단서가 필요한 질문에서는 오답이 90% 줄었다고 주장한다.

프로젝트는 한 번 데이터베이스를 측정하고, 에이전트가 그 수치의 의미를 코드와 읽기 전용 쿼리로 확인해 저장소에 기록하는 방식으로 동작한다. 이후 세션은 MCP 서버, 패키지형 스킬 또는 dbprint context를 통해 데이터베이스 연결과 에이전트의 자격 증명 없이 결과를 읽는다. 저장소에 기록된 출력물은 코드 검토와 CI 검사에도 사용할 수 있다.

  • PostgreSQL, MySQL, Snowflake, BigQuery, Databricks, Redshift, ClickHouse, duckdb를 지원한다.
  • 테이블 DDL, 선언되거나 추론된 조인 관계, 열별 널 비율·값 목록·범위·분포·값 형태 등을 기록한다.
  • 데이터베이스에 연결하는 프로파일링 단계에서는 실제 값이 저장소에 기록될 수 있으므로, 민감한 값을 가리거나 제외하거나 해시하는 설정과 접근 권한을 확인해야 한다.

에이전트가 읽는 정보

dbprint context --purpose query는 SQL을 작성하기 전 에이전트에 전달할 테이블 문맥을 만든다. 저장소의 참조 출력물에 포함된 예시에는 900행, 8열인 arboretum.seedbank.germination_trial 테이블이 나온다. accession_id는 선언된 관계이고 collector_id는 추론된 관계로 표시된다. 데이터 사전은 각 행이 한 accession에서 가져온 배치에 대해 수행한 발아 시도를 나타낸다고 설명한다.

이 예시에서 medium 열에는 6개 값이 있고 값 목록의 범위는 100%다. sand tray는 sand tray와 Sand Tray 두 표기로 저장돼 있어 한 표기만 검색하면 25행을 놓친다. control은 물리적 배지가 아니라 무처리 대조군이라는 설명도 붙어 있다. 첫 두 사실은 dbprint가 측정하고, 마지막 의미는 사람이거나 에이전트가 한 번 기록하면 이후 세션에서 읽는다.

데이터베이스 연결이나 설정 없이 직접 확인하려면 uv만 있으면 된다.

uvx dbprint context arboretum.seedbank.germination_trial --purpose query \\
 --project https://github.com/jakubro/dbprint/blob/main/docs/format/v1/examples/production/.dbprint.yaml

설치와 첫 실행

Python 3.13 이상이 필요하다. 사용할 데이터베이스에 맞는 드라이버 추가 기능을 지정해 설치한다.

uv tool install 'dbprint[postgres]' # or [mysql], [snowflake], [duckdb], [clickhouse], [redshift], [databricks], [bigquery]

MCP, 문서 사이트 또는 dbt 기능도 쓰려면 같은 설치 명령에 [mcp], [docs], [dbt] 추가 기능을 함께 적는다. 이후에 다시 설치하면 이전 추가 기능에 더해지는 것이 아니라 대체되므로, 예를 들어 다음처럼 한 번에 지정해야 한다.

uv tool install 'dbprint[postgres,mcp]'

PostgreSQL 어댑터는 DDL을 얻기 위해 pg_dump를 실행하므로 PostgreSQL 클라이언트 바이너리가 PATH에 있어야 한다.

저장소 루트에서 프로젝트 기본 구조를 만든다.

dbprint init

이 명령은 커밋할 .dbprint.yaml과 prints/ 디렉터리를 만들고, 자격 증명 템플릿은 저장소 밖의 ~/.dbprint/connections.yaml에 쓴다. 따라서 비밀 정보는 설정 파일 옆에 저장되지 않는다.

자격 증명 파일에 연결 정보를 넣는다.

# ~/.dbprint/connections.yaml
primary:
 host: localhost
 port: 5432
 database: my_db
 user: dbprint_ro
 password: change_me

.dbprint.yaml에는 사용할 어댑터와 읽을 테이블을 지정한다.

# .dbprint.yaml
connections:
 primary:
 adapter: postgres
 auto: true
 tables:
 include:
 - "*.public.*"

자격 증명은 먼저 DBPRINT_<CONNECTION>_<KEY> 환경 변수에서 찾고, 다음으로 ~/.dbprint/connections.yaml, 마지막으로 프로젝트 루트의 .env에서 찾는다. 두 설정 파일의 모든 키는 docs/CONFIG.md에 설명돼 있다.

데이터베이스를 프로파일링하고 출력물과 diff.yaml을 만든다.

dbprint generate

결과를 코드와 함께 커밋한 뒤 데이터베이스에 연결하지 않고 확인한다.

dbprint list

그다음 테이블 주석 작성 안내를 출력하고 에이전트에 전달할 수 있다. 안내에는 주석 작성 스킬의 절차가 담겨 있어 어떤 에이전트 CLI로도 따를 수 있다.

dbprint annotate my_db.public.orders | claude -p

이후 에이전트를 출력물에 연결한다.

데이터베이스 접근과 실제 값

dbprint는 데이터를 읽는다. 프로파일링 대상 테이블에 SELECT 권한이 있는 역할이면 충분하며, 엔진별 어댑터 페이지의 정확한 권한 목록은 첫 출력물 안내에서 확인할 수 있다. 쓰기가 발생하는 경우는 샘플링한 테이블에서 추출한 행을 임시 복사할 때뿐이다. 세션이 끝나면 복사본은 사라지며, BigQuery에서는 만료 시간이 지난 뒤 사라진다. 샘플링할 때만 발생하는 이 쓰기는 read.tables.materialize 설정으로 끌 수 있다.

출력물에는 실제 셀 값이 포함된다. 값 목록과 범위, 백분위수가 저장소에 기록되며 기본적으로 아무 값도 가려지지 않는다. 값 가리기 설정을 이용하면 열 이름, 감지된 민감도(personal_name, national_id 등), 값 형태를 기준으로 값을 마스킹하거나 제외하거나 해시할 수 있다. 이때 개수는 유지된다. 스키마 자체의 뷰 본문, 기본값, 주석에 비밀번호나 키가 들어 있다면 어떤 규칙을 설정했더라도 매 실행의 ddl.sql에서 가려진다.

프로파일링은 한 차례 실행한 뒤 필요한 경우 다시 실행하는 방식이다. 출력물이 최신성 기준보다 오래됐거나 설정이 바뀐 테이블을 다시 읽는다. 샘플링, 행 필터, 카탈로그만 읽는 설정으로 데이터 웨어하우스 비용을 제한할 수 있다. 자세한 내용은 프로파일링 범위 정하기를 참고한다.

출력물의 구성과 의미

에이전트가 읽는 문맥 아래에는 일반 YAML 파일이 놓인다. 다음은 같은 참조 출력물의 statistics.yaml에서 일부 필드를 생략한 예시다.

row_count: 2500
columns:
 catalogue_url:
 sql_type: character varying(200)
 nullable: false
 null_rate: 0.0
 classification: text
 cardinality: 2500
 cardinality_ratio: 1.0
 inferred:
 looks_like: url
 sampled: 1000
 matched: 1000
 candidate_key: true
 values:
 - value: https://specimens.example.org/accession/1
 count: 1
 - value: https://specimens.example.org/accession/10
 count: 1
 # ... 28 more
 values_coverage: 0.012 # top 30 of 2500 - a value list, not a claim of completeness
 distribution: long_tail

 provenance_country:
 sql_type: character(2)
 classification: categorical
 cardinality: 10
 inferred:
 looks_like: country_code
 sampled: 10
 matched: 10
 values:
 - value: AU
 count: 250
 - value: CA
 count: 250
 - value: DE
 count: 250
 - value: FR
 count: 250
 - value: GB
 count: 250
 # ... 5 more
 values_coverage: 1.0 # the list is the whole domain, not a sample
 distribution: uniform

 received_at:
 sql_type: timestamp(0) with time zone
 classification: temporal
 range:
 min: '2018-01-08T00:00:00Z'
 max: '2024-11-28T00:00:00Z'
 span_days: 2516
 percentiles:
 p01: '2018-02-09T00:00:00Z'
 p25: '2019-10-02T00:00:00Z'
 p50: '2021-06-19T00:00:00Z'
 p75: '2023-03-05T00:00:00Z'
 p99: '2024-10-25T00:00:00Z'

values_coverage: 1.0는 값 목록이 전체 도메인인지 판단하는 핵심 필드다. 위 예시의 국가 코드 10개가 전체 값이므로 데이터베이스에 질의하지 않고도 11번째 값은 없다고 볼 수 있다. 표본으로 프로파일링한 테이블에서는 실제로 읽은 행을 기준으로 범위를 계산한다. 자세한 내용은 아래 범위 지정 프로파일링을 참고한다.

inferred는 dbprint가 데이터베이스에서 직접 읽은 값이 아니라 추론한 내용이다. looks_like: country_code는 판정이며, sampled와 matched는 판정 근거다. 따라서 값 10개로 확인한 형태와 1만 개로 확인한 형태를 구별할 수 있다.

조인 그래프는 relationships.yaml에 기록된다.

refers_to:
- column:
 - collector_id
 target_table: arboretum.seedbank.collector
 target_column:
 - collector_id
 on_delete: RESTRICT
 detection: declared # or `inferred`, when dbprint guessed the edge from naming
 observed:
 fanout_avg: 6.25
 target_coverage: 1.0

측정 결과 옆에 사람이 같은 디렉터리와 커밋에 기록하는 설명도 둔다. 열별 설명은 statistics.annotations.yaml에 쓴다.

columns:
 collector_id:
 note: >-
 FK to collector.collector_id. Field collectors are affiliated with a
 partner institution; collector.institution names it.

통계로 표현할 수 없는 테이블 수준의 서술은 description.md에 쓴다. dbprint는 두 파일을 덮어쓰지 않으며, 통계와 함께 에이전트에 제공한다. 통계로 답할 수 있는 내용은 통계가 우선하고, 설명은 숫자로 답할 수 없는 내용에 대해서만 기준이 된다.

저장소에 생성되는 파일

출력물은 다음 구조를 갖는다.

prints/<connection>/   manifest.yaml                    # inventory, freshness, per-table thresholds   reading.md                       # generated guide - how to read the rest of the print   diff.yaml                        # machine-readable drift from the last run   manifest.annotations.yaml        # optional, connection-level notes you write   <namespace>/<table>/             # one directory per FQN segment, e.g. arboretum/seedbank/accession/     ddl.sql                        # native DDL, normalized for stable diffs     statistics.yaml                # column distributions     relationships.yaml             # declared + inferred foreign keys     description.md                 # optional, you write it     statistics.annotations.yaml    # optional, per-column notes you write     relationships.annotations.yaml # optional, per-edge notes you write

reading.md는 실행할 때마다 새로 작성된다. 각 필드를 어떤 용도로 신뢰할 수 있는지 안내하므로, 처음 보는 에이전트도 출력물의 형식을 이해할 수 있다. .md와 .annotations.yaml 파일 네 개는 사용자가 관리하며 dbprint가 덮어쓰지 않는다. 네 파일 모두 에이전트가 읽는 문맥에 포함된다.

명령어

명령어기능
dbprint init.dbprint.yaml, prints/, 자격 증명 템플릿을 만든다.
dbprint config explain테이블별로 적용되는 프로파일 설정을 출력하고, 각 값의 기본값·연결·규칙 등 출처를 주석으로 표시한다.
dbprint generate데이터베이스를 프로파일링해 출력물과 diff.yaml을 쓴다.
dbprint list커밋된 출력물의 오프라인 요약을 보여준다.
dbprint diff실제 데이터베이스와 커밋된 출력물을 비교한다.
dbprint check구조, 최신성, 통계 단언을 CI에서 검사한다. --online을 추가하면 드리프트와 SQL 단언도 검사한다.
dbprint context한 개 이상의 테이블을 프롬프트에 넣기 좋은 Markdown 문맥으로 출력한다.
dbprint annotate테이블 주석 작성 안내를 출력하거나 --check로 주석을 검사한다.
dbprint docs출력물을 HTML 사이트로 보여준다. [docs] 추가 기능으로 실시간 serve 또는 정적 build를 할 수 있다.
dbprint serve커밋된 출력물을 읽기 전용 MCP 서버로 제공한다. [mcp] 추가 기능이 필요하다.

전체 명령어 설명은 docs/CLI.md에 있다.

에이전트 연결과 원격 프로젝트

MCP 클라이언트가 서버를 직접 실행하므로 작업 디렉터리는 사용자가 아니라 클라이언트가 선택한다. 따라서 프로젝트 경로를 명시해야 한다.

{
 "mcpServers": {
 "dbprint": {
 "command": "uvx",
 "args": ["--from", "dbprint[mcp]", "dbprint", "serve", "--project", "/srv/analytics"]
 }
 }
}

서버는 커밋된 출력물만 읽고 데이터베이스에 연결하지 않으므로 클라이언트에 자격 증명이 필요하지 않다.

--project에는 Git 주소도 지정할 수 있어, 다른 저장소에 커밋된 출력물도 먼저 수동으로 복제하지 않고 읽을 수 있다.

dbprint list --project https://github.com/jakubro/dbprint/blob/main/docs/format/v1/examples/production/.dbprint.yaml
dbprint context arboretum.seedbank.accession --project https://github.com/jakubro/dbprint#main:docs/format/v1/examples/production

dbprint가 저장소를 대신 복제하며 자체 자격 증명은 요구하지 않는다. 비공개 저장소는 기존 SSH 에이전트나 자격 증명 도우미를 이용한다. 원격 프로젝트는 읽기 전용이다. generate, diff, check의 --online 형식, config explain의 --online 형식처럼 데이터베이스에 연결하는 명령은 원격 위치에서 실행되지 않는다. 나머지 명령은 로컬 프로젝트와 동일하게 사용할 수 있다.

추가 기능

  • 의미 추론: 모든 열에 categorical, numeric, temporal, foreign_key_candidate, json 등의 분류를 붙인다. 텍스트, 범주형, 외래 키 열은 uuid, email, phone, ip, country_code 등의 정해진 값 형태 패턴과 비교하며, 판정과 함께 표본 수와 일치 수를 공개한다. 데이터베이스 밖으로 나가면 안 되는 값이 든 열에는 personal_name, postal_address, national_id, credential 등의 민감도 축을 표시한다. 고유성 비율이 0.9999 이상인 열은 candidate_key로 표시하고, 이 기준이 측정 또는 추정된 중복을 허용한 경우 candidate_key_exception도 기록한다. 스키마에 선언되지 않은 외래 키는 이름을 바탕으로 추론해 detection: inferred로 표시한다. 모두 추정값으로 공개되며, 잘못된 추론은 주석에서 철회해 에이전트가 더는 읽지 않게 할 수 있다.
  • 값 가리기: mask, drop, hash(솔트 적용)로 셀 값을 숨길 수 있다. 글로브 패턴, 추론된 민감도, 값 형태를 기준으로 열을 지정할 수 있어 다음 분기에 추가될 personal_name 열에도 미리 작성한 규칙을 적용할 수 있다. 개수, 카디널리티, 분포는 그대로 유지되고 리터럴 값만 숨긴다. 솔트는 커밋되는 설정이 아니라 자격 증명과 함께 저장한다.
  • 단언: YAML로 통계값에 대한 데이터 품질 검사를 작성하거나 원시 SQL을 사용할 수 있다. 통계 단언은 데이터베이스 연결 없이 일반 dbprint check로 커밋된 출력물에서 평가한다. SQL 단언에는 dbprint check --online이 필요하다. 자세한 내용은 docs/ASSERTIONS.md를 참고한다.
  • CI 종료 코드: 0은 정상, 1은 출력물 형식 오류 또는 사용할 수 없는 설정, 2는 오래된 출력물, 3은 드리프트, 4는 연결 실패, 5는 부분 실행, 6은 단언 실패, 7은 전체 실패를 뜻한다. diff, check, context는 모두 --format json|yaml을 지원한다.
  • 범위 지정 프로파일링: 테이블별 규칙으로 표본을 뽑거나 행 필터를 적용하고 측정 항목을 바꿀 수 있다. 엔진에서 시드를 지원하면 테이블 이름을 시드로 사용한다. 테이블 크기에 따라 규칙을 적용할 수도 있어 아직 지정하지 않은 모든 팩트 테이블에 규칙 하나를 적용할 수 있다. 이렇게 읽은 테이블에는 scope 블록과 열별 rows_scanned가 붙으며, 파일에 적힌 모든 개수의 기준은 전체 테이블이 아니라 실제로 읽은 행이다.
  • MCP 서버: dbprint serve는 get_table_context, list_tables, search_columns, resolve_value, get_manifest, get_diff, get_reference 도구와 모든 산출물을 리소스로 제공한다. 커밋된 출력물만 읽으며 데이터베이스 연결을 열지 않는다. 자세한 내용은 docs/MCP.md를 참고한다.
  • Markdown 스킬: Markdown 규칙이나 사용자 지정 지침을 받는 클라이언트에는 커밋된 출력물이 답할 수 있는 질문, 사용할 도구, 각 수치의 범위를 설명하는 스킬 파일을 설치할 수 있다. 실행할 프로세스는 필요하지 않다. 다른 스킬은 각 테이블을 만드는 코드와 읽기 전용 쿼리를 바탕으로 에이전트가 주석 파일을 작성하게 하고, dbprint annotate --check로 검사한다. 두 스킬은 설치 전에 읽을 수 있도록 docs/examples/skill/에 있다.
  • dbt 계보: 연결의 dbt_manifest에 컴파일된 dbt manifest.json을 지정하면 generate가 각 모델 열의 원본 열을 derived_from으로 기록한다. 원본 열에 한 번 쓴 설명을 그 열에서 만들어진 모든 모델에 전달할 수 있다. [dbt] 추가 기능이 필요하며 자세한 설정은 docs/CONFIG.md에 있다.
  • 토큰 예산에 맞춘 문맥: dbprint context arboretum.seedbank.accession --budget 4000처럼 지정하면 우선순위가 낮은 섹션부터 제외해 Markdown 문맥을 토큰 예산에 맞춘다.

비슷한 도구와 차이점

프로젝트·범주기능dbprint와의 차이
dryrun오프라인 PostgreSQL 스키마 스냅샷, MCP 서버, 린팅가장 비슷한 도구다. 스냅샷은 .gitattributes에서 binary로 표시하는 압축 바이너리 묶음이다. dbprint는 여러 데이터베이스 엔진을 지원하고, 명세가 공개된 행 단위 비교 가능한 YAML을 만든다.
dbt-profiler열 프로파일을 dbt YAML 또는 Markdown으로 커밋한다.dbt 프로젝트만 지원한다. DDL, 관계 그래프, 의미 추론, 값 가리기는 제공하지 않는다.
dbhub, postgres-mcp, Supabase, Neon 등 실시간 연결 MCP 서버에이전트 실행 시 데이터베이스를 질의하고 내부 정보를 확인한다.에이전트가 매 세션 자격 증명을 필요로 한다. dbprint는 한 번 프로파일링해 결과를 커밋하고, 데이터베이스에 연결하지 않은 상태로 제공한다.
tbls, SchemaSpy사람을 위한 스키마 문서와 ER 다이어그램구조만 보여주고 데이터 분포는 다루지 않는다. dbprint docs serve는 측정된 열 정보와 외래 키 다이어그램을 같은 탐색형 페이지로 보여준다.

dbprint가 하지 않는 일

  • 마이그레이션 도구가 아니다. DDL 변경을 작성하거나 적용하거나 버전 관리하지 않는다. Alembic, Flyway, Liquibase, sqldef, Atlas를 사용하면 된다.
  • 스키마 관리 도구나 ORM 계층이 아니다. 출력물은 데이터베이스에서 생성하며, 데이터베이스를 만들기 위한 기준 원본이 아니다.
  • 실시간 질의 인터페이스가 아니다. 출력물은 에이전트 대신 SQL을 실행하지 않는다.
  • 데이터 품질 플랫폼이 아니다. 단언 기능은 출력물을 대상으로 하는 CI 검사이지 모니터링, 경보, 계보 관리가 아니다. 그런 용도에는 Soda, Great Expectations, Elementary를 사용할 수 있다.
  • 데이터 카탈로그가 아니다. 호스팅 서비스, 공유 검색 인덱스, 비즈니스 용어집은 없다. dbprint docs는 커밋된 출력물을 루프백 주소에 한정된 로컬 읽기 전용 화면으로 제공하며 관리할 서비스도 없다.

출력 형식과 설정

출력물은 데이터베이스 구조와 열별 데이터 분포를 담은 이동 가능한 스냅샷이다. Git에 커밋해 사람, AI 코딩 에이전트, CI가 오프라인으로 읽을 수 있다. 장기적으로 남는 산출물은 CLI가 아니라 디스크 형식이다. 이 형식은 명세가 공개돼 있고 도구와 별도로 버전이 관리되며, 다른 도구도 출력물을 만들 수 있도록 설계됐다. 명세는 docs/format/v1/SPEC.md에 있다.

JSON 스키마는 설치된 패키지의 src/dbprint/spec/v1/에 포함된다. 생성되는 각 산출물과 사용자가 작성하는 각 주석 파일에 스키마가 하나씩 있다. 적합성 검사기는 데이터베이스, 설정, CLI 없이 공개 API로 사용할 수 있다.

from dbprint.conformance import validate_print

issues = validate_print("prints/production") # conforms iff no error-severity issues

docs/format/v1/examples/의 참조 출력물은 직접 작성한 예시가 아니라 실제 dbprint 실행 결과다.

프로젝트 설정은 커밋하는 .dbprint.yaml에, 자격 증명은 커밋하지 않는 ~/.dbprint/connections.yaml에 둔다. 두 파일의 모든 키와 자료형, 기본값, 해석 순서는 docs/CONFIG.md에 있다. 내부 구조는 docs/ARCHITECTURE.md에 설명돼 있다.

저작권은 Jakub Roman에게 있으며, 2026년 기준 Apache License 2.0으로 배포된다. 라이선스를 확인할 수 있다.