2026-07-29 18:29:25 +09:00
2026-07-29 18:29:25 +09:00
2026-07-29 18:29:25 +09:00
2026-07-29 18:29:25 +09:00
2026-07-29 18:29:25 +09:00
2026-07-29 18:29:25 +09:00
2026-07-24 13:58:08 +09:00

ClariDoc Harness 0.2.0

ClariDoc은 기술 블로그와 기술 문서를 계획·작성·검토·수정하는 멀티 모델 하네스다. 처음 brief와 프로젝트 문서를 넣으면 바로 글부터 쓰지 않는다. 로컬 문서 저장소에서 근거를 찾고, 문서 유형에 맞춰 독자가 문제와 선택을 따라갈 순서를 먼저 잡는다. 그다음 Codex, Claude, Google Antigravity가 계획과 작성, 검토와 수정을 나누어 맡는다.

이 과정에서는 두 가지를 끝까지 지킨다.

  1. 근거 추적 정보와 독자용 글을 분리한다. source ID, repository path, access date, prompt tag는 provenance.mdevidence-map.json에만 남는다.
  2. 기술 선택은 이유 없이 선언할 수 없다. “의도적으로 사용한다”, “허용했다”, “금지했다”라고 썼다면 제약, 선택 이유, 대안, 수용 비용, 가드레일까지 이어져야 한다.

해결하려는 실패

최종 문서에서 다음 문장이 보이면 ClariDoc은 실패로 처리한다.

예시는 2026-07-23 기준이다.
Retries can increase load ... [S1]
제공된 근거 팩은 다음 사실을 확인 대상으로 제시한다.
application-core는 Spring DI와 SLF4J를 의도적으로 사용한다.

처음 세 문장에는 독자가 볼 필요가 없는 작성 과정과 provenance가 섞여 있다. 마지막 문장은 Spring DI를 선택했다는 사실만 있고 왜 선택했는지, 무슨 대안을 검토했는지, 어떤 비용을 감수했는지, 어디까지 허용했는지는 알 수 없다.

그래서 ClariDoc 0.2.0은 독자가 읽을 내용과 근거를 추적할 때 필요한 기록을 서로 다른 파일에 남긴다.

reader-facing document.md
  └─ 문제, 제약, 대안, 선택 이유, 동작, 검증, 트레이드오프만 노출

internal provenance.md / evidence-map.json
  └─ source ID, 원본 경로, heading, line range, status, claim/decision ID 보존

전체 흐름

brief.json
   + manual sources.json (선택)
   + local documentation repository
                    │
                    ▼
         [local corpus collector]
  canonical project / concept / branch note /
  official docs / company tech blogs를 chunk 검색
                    │
                    ▼
       [문서 유형별 구조 계약]
                    │  planner: Codex
                    ▼
  질문 기반 outline + decision requirements
                    │  writer: Claude
                    ▼
            reader-facing draft
                    │
         ┌──────────┼──────────┐
         │          │          │
  deterministic   logic/     reader/editor/
     linter       decision   evidence/operations
         │         reviews       reviews
         └──────────┼──────────┘
                    ▼
              quality gate
             실패 │     │ 통과
                  ▼     ▼
          reviser: Claude
                    │
                    ▼
 document.md + quality-report.md
 provenance.md + evidence-map.json + manifest.json

기술 블로그의 기본 논리 구조

technical_blog는 다음 순서를 기본 계약으로 사용한다.

  1. 구체적인 문제 장면: 어떤 상황과 비용이 있었는가
  2. 제약: 단순한 해법을 막은 조건은 무엇인가
  3. 선택지: 어떤 대안과 실패한 시도를 검토했는가
  4. 결정 이유: 왜 골랐고, 무엇을 포기했으며, 어떤 경계를 지켰는가
  5. 메커니즘: 실제 모듈·인터페이스·제어 흐름에 어떻게 반영됐는가
  6. 검증: 어떤 테스트·빌드 규칙·관측값이 무엇을 증명하는가
  7. 트레이드오프: 얻은 것, 잃은 것, 적용하지 않을 조건은 무엇인가
  8. 결론: 다른 환경에서도 가져갈 판단은 무엇인가

우아한형제들 기술 블로그를 조사하면서 저는 여러 문제 해결 글이 팀과 시스템의 상황 → 구체적인 문제와 비용 → 검토한 접근 → 선택과 구현 → 검증과 한계 순서로 이어지는 것을 확인했다. 여기에 독자와 메시지, 개요와 문단 흐름을 다룬 개발자 글쓰기 자료를 더해 위 순서를 만들었다. 우아한형제들의 공식 편집 규정을 그대로 옮긴 것은 아니다. 어떤 글을 조사했고 어디까지 해석했는지는 research/FOUNDATIONS.md에 기록했다.

지원 문서 유형

document_type 기본 독자 과업 필수 논리 축
technical_blog 문제와 설계 판단 이해 문제 → 제약 → 대안 → 선택 이유 → 메커니즘 → 검증 → 비용 → 판단
tutorial 따라 하며 결과와 개념 학습 결과 → 준비 → 경로 → 단계 → 체크포인트 → 검증 → 다음 학습
how_to 특정 작업을 안전하게 완료 적용 조건 → 사전 조건 → 절차 → 확인 → 롤백 → 문제 해결
explanation 개념과 인과 관계 이해 질문/답 → 익숙한 기준 → 모델 → 메커니즘 → 예시 → 대안 → 한계
reference 정확한 항목 조회 범위 → 구문 → 필드 → 동작 → 오류 → 최소 예시 → 관련 항목
troubleshooting 증상에서 원인·복구로 이동 증상 → 영향 → 안전 → 진단 → 원인 → 조치 → 복구 → 예방
design_doc 대안을 비교하고 결정 승인 요약 → 문제 → 목표 → 제약 → 대안 → 결정 → 구조 → 실패 → 배포 → 관측 → 위험

설치

Python 3.10 이상이 필요하다. core runtime은 외부 Python package에 의존하지 않는다.

python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .

Antigravity provider를 사용할 때만 선택 의존성을 설치한다.

python -m pip install -e '.[antigravity]'

로컬 문서 저장소를 근거로 사용하기

검색기는 기본으로 이 경로를 훑는다.

wiki/projects
wiki/concepts
raw/branch-notes
raw/official-docs
raw/company-tech-blogs

프로젝트 문서 저장소를 직접 지정할 때:

claridoc run \
  --brief examples/briefs/application-core-spring-di-blog.json \
  --source-root /path/to/local-document-repository \
  --config config/pipeline.multi-agent.example.json \
  --output .run/application-core-live

검색 결과만 먼저 확인할 수도 있다.

claridoc collect \
  --root /path/to/local-document-repository \
  --query 'application-core Spring DI 선택 이유 대안 비용 가드레일' \
  --query 'TransactionPort spring-tx 금지 ArchUnit 검증' \
  --top-k 24 \
  --output .run/application-core-sources.json

검색기는 먼저 Markdown 문서를 heading 단위로 나눈다. 그런 다음 BM25 계열 점수에 source type과 status, decision/rationale 용어의 가중치를 더해 관련 chunk를 고른다. Source pack에는 절대 경로를 넣지 않고 저장소를 기준으로 한 상대 경로만 남긴다.

Source hierarchy

source type 주 용도 주의점
canonical-project 현재 프로젝트의 검증된 상태 현재 상태의 우선 근거
canonical-concept 재사용 가능한 개념 프로젝트 구현 사실과 구분
branch-note 선택 배경, 대안, 결정 이력, 로컬 검증 status를 보존하고 현재 canonical과 충돌 여부 확인
official-doc vendor·protocol·표준 동작 프로젝트가 실제 채택했다는 증거는 아님
company-tech-blog 선례와 경험 보고 보편 법칙으로 일반화하지 않음

검색 결과에 같은 기술 이름이 나온다고 바로 선택의 근거로 쓰지는 않는다. Planner는 이유와 대안, 제약과 비용을 실제로 설명하는 chunk를 결정 섹션에 먼저 배치한다. 그런 근거를 찾지 못하면 모델이 이유를 만들어 내지 않고 주장을 좁히거나 빼도록 한다.

독자용 인용 정책

독자에게 출처를 어떻게 보여 줄지는 brief.jsonconstraints.citation_style에서 정한다.

독자용 문서 내부 sidecar
hidden source ID, URL, path, access date를 표시하지 않음 전체 provenance 보존
footnote 공개 가능한 Markdown footnote 내부 provenance도 보존
inline_link 자연스러운 공개 링크 내부 provenance도 보존
source_id [SOURCE_ID] 형식 허용 내부 provenance도 보존

기술 블로그에서 기본값인 hidden을 선택하면 독자용 문서에는 출처 표시가 나오지 않는다. [S1], Labc123..., raw/branch-notes/..., “제공된 근거 팩” 같은 문자열이 남아 있으면 lint가 error로 잡는다.

날짜 정책

날짜와 버전을 본문에 표시할지는 constraints.date_policy에서 정한다.

  • only_when_material: 버전·날짜가 동작, 호환성, 재현성에 영향을 줄 때만 본문에 표시
  • always: 제공된 version context를 자연스럽게 표시
  • never: 날짜·버전 context를 독자용 글에 표시하지 않음

Source의 accessed는 독자에게 보여 주지 않고 내부 provenance에만 남긴다. 그래서 “예시는 2026-07-23 기준이다”처럼 접근 날짜만 알리는 문장은 기본 정책에서 error 또는 warning이 된다.

선택 이유 계약

문서에 다음 한 문장만 있다면 선택 이유가 빠진 것이다.

application-core는 Spring DI를 의도적으로 사용한다.

이 한 문장만으로는 왜 Spring DI를 허용했는지 알 수 없다. ClariDoc은 기술 선택을 설명할 때 적어도 아래 내용을 함께 요구한다.

context / constraint
  → chosen option
  → why it was chosen
  → realistic alternative
  → accepted cost
  → guardrail or boundary

실제 문장으로 옮기면 다음과 같다.

application-core는 use case를 component scanning으로 등록하기 위해
@Service와 @Component를 허용했다.

Spring DI까지 제거하면 use case마다 @Configuration에서 bean을 수동 등록해야 해
조립 코드가 빠르게 늘어나기 때문이다.

대신 application-core가 spring-context와 spring-beans에 의존하는 비용을 수용한다.
그 비용이 transaction·transport·persistence 의존으로 번지지 않도록
spring-tx, Spring Web, JPA는 금지하고 Gradle과 ArchUnit으로 검사한다.

이렇게 쓰면 Spring DI의 장점뿐 아니라 검토한 대안과 감수한 비용, 의존성이 번지지 않게 막은 범위까지 함께 확인할 수 있다.

포함된 application-core 예시

예시 글은 Spring DI 허용 이유를 수동 bean 등록 비용과 연결한다. spring-tx·Spring Web·JPA 금지, TransactionPort, Gradle/ArchUnit 검사, reflection 우회 한계까지 설명한다. corpus에서 명시적인 선택 이유를 확보하지 못한 SLF4J는 독자용 글에서 언급하지 않는다.

Provider 역할

기본 multi-agent 예제에서는 다음과 같이 작업을 나눈다.

역할 provider 책임
planner Codex 구조 계약 정교화, evidence allocation
writer Claude 독자용 완성 초안
logic reviewer Codex 인과·전제·결론 검사
decision reviewer Codex 선택 이유·대안·비용·가드레일 검사
reader reviewer Claude 독자 맥락·인지 부하·정보 누락 검사
editor reviewer Claude 도입·문단 초점·전환·반복·상투적 LLM 문구 검사
evidence reviewer Antigravity source fit·status·과장 검사
operations reviewer Antigravity 절차·안전·검증·롤백 검사
reviser Claude blocker/error 수정

실행하기 전에는 각 provider가 설치되어 있고 인증할 수 있는지 먼저 확인한다.

claridoc doctor --config config/pipeline.multi-agent.example.json

자세한 통합 계약은 docs/PROVIDERS.md를 참조한다.

Mock 실행

Mock을 실행하면 외부 모델을 부르지 않고도 파이프라인 연결과 artifact 생성을 확인할 수 있다.

claridoc run \
  --brief examples/briefs/retry-policy-blog.json \
  --sources examples/sources/retry-policy-sources.json \
  --config config/pipeline.mock.json \
  --output .run/retry-policy-mock

Mock은 source excerpt를 글에 복사하지 않는다. 실행 결과가 PASS여도 문장이 잘 쓰였다는 뜻은 아니다. 여기서 확인할 수 있는 것은 구조와 계약, 파이프라인 fixture가 연결됐다는 점까지다.

명령어

claridoc init [directory] [--force]
claridoc collect --root ROOT --query QUERY [--query QUERY] --output SOURCES
claridoc validate --brief BRIEF [--sources SOURCES] [--source-root ROOT]
claridoc outline --brief BRIEF [--sources SOURCES] [--source-root ROOT] [--output OUTLINE]
claridoc lint DOCUMENT --brief BRIEF [--sources SOURCES] [--source-root ROOT] [--json]
claridoc run --brief BRIEF [--sources SOURCES] [--source-root ROOT] [--config PIPELINE] --output RUN_DIR
claridoc doctor --config PIPELINE [--json]

validate, outline, lint, run은 local corpus 옵션을 공유한다.

--source-root ROOT
--source-include RELATIVE_DIR     # 반복 가능
--source-top-k N
--source-max-per-file N

결정적 lint

주요 검사:

  • 정확히 하나의 H1과 필수 H2의 존재·중복·순서
  • 기술 블로그가 prompt contract가 아니라 구체적 문제에서 시작하는지
  • “제공된 근거 팩”, prompt tag, section-planning narration 누출
  • hidden citation 모드에서 source ID와 repository path 누출
  • access-date/example-date boilerplate
  • 기술 선택 선언 뒤 이유 누락 (RAT001)
  • 대안·수용 비용·가드레일 누락 (RAT002)
  • decision section에 rationale evidence가 배치되지 않은 경우 (RAT003)
  • 코드 fence, heading depth, 문단·문장 밀도
  • 한국어 기술 블로그에서 첫 번째/두 번째/세 번째 + 추상 분류명이 가까운 문단에 반복되는 문장 scaffolding (STYLE001)
  • 절차의 사전 조건, 단계, 검증, 롤백
  • 파괴적 명령 주변의 영향 경고, checkpoint, verification
  • 금지 주장과 미해결 TODO

Lint를 통과했다고 문장의 의미까지 맞는 것은 아니다. Lint가 정해진 규칙을 검사한 뒤에도 모델 reviewer와 프로젝트 소유자가 내용을 다시 확인해야 한다.

산출물

run-dir/
├── inputs/
│   ├── brief.normalized.json
│   ├── sources.normalized.json
│   └── pipeline.normalized.json
├── stages/
│   ├── 01-planner.raw.txt
│   ├── 02-outline.json
│   ├── 02-outline.md
│   └── 03-writer.raw.txt
├── rounds/round-*/
│   ├── draft.md
│   ├── lint.json
│   ├── lint.md
│   ├── review-*.json
│   └── quality-gate.json
├── final/
│   ├── document.md                 # 독자용
│   ├── quality-report.md
│   ├── provenance.md               # 내부용
│   └── evidence-map.json           # 내부용
├── provider-events.jsonl
├── run.json
└── manifest.json

manifest.json은 자신을 제외한 모든 artifact의 크기와 SHA-256을 기록한다.

검증

bash scripts/verify.sh

이 명령은 unit/integration test부터 Python 3.10 grammar parse, JSON과 JSON Schema, Markdown local link, local corpus retrieval, golden example lint를 차례로 확인한다. 이어서 Mock end-to-end, provenance sidecar, manifest 재검산, wheel build/install smoke test까지 실행한다. 최신 결과는 verification/TEST_REPORT.md에서 확인할 수 있다.

한계

  • 로컬 corpus 검색은 lexical ranking이다. 의미가 유사하지만 단어가 다른 근거는 놓칠 수 있다.
  • source chunk가 검색됐다고 그 내용을 바로 본문에 쓸 수 있는 것은 아니다. status와 governing source를 함께 확인해야 한다.
  • LLM reviewer의 합의는 진실의 증명이 아니다.
  • 실제 코드 예시, command, 운영 수치, 보안 주장은 대상 시스템에서 별도로 검증해야 한다.
  • provider binary, SDK, 인증, quota, model ID는 실행 환경마다 다르다.
  • Mock 실행은 문서 품질을 증명하지 않는다.

위협 모델과 prompt-injection 경계는 docs/SECURITY.md에 정리했다.

S
Description
No description provided
Readme MIT
17 MiB
Languages
Python 50.9%
JavaScript 48.9%
Shell 0.2%