| name | omd:sync |
| description | DESIGN.md 변경분을 CLAUDE.md / AGENTS.md / .cursor/rules/omd-design.mdc shim 3종에 전파. 'shim 갱신', 'drift 확인', 'ship', 'publish', 「shimを更新」, 「同步 CLAUDE.md」류의 요청에 트리거. DESIGN.md가 수정됐는데 shim이 오래됐을 때 자동 감지해 제안하기도 함. |
omd:sync — Shim Maintenance
DESIGN.md가 모든 주요 AI 코딩 에이전트(Claude Code, Codex, OpenCode, Cursor)에게 보이도록 shim 파일 3종을 관리한다. CLI 호출 없음 — Read/Write/Edit 툴로 직접 처리.
관리 대상 (3 파일)
| ID | 경로 | 모드 |
|---|
claude | CLAUDE.md | block (managed marker만) |
agents | AGENTS.md | block (managed marker만) |
cursor | .cursor/rules/omd-design.mdc | whole (전체 파일이 omd 전용) |
block 모드는 <!-- omd:start v=1 hash=<sha256:12> --> ~ <!-- omd:end --> 마커 안만 관리, 나머지 사용자 콘텐츠 보존. whole 모드는 frontmatter 포함 전체 파일이 관리 단위.
템플릿 (정확히 이 본문 — 절대 paraphrase 금지)
CLAUDE.md body
# Design System (oh-my-design)
The authoritative brand & UI spec is **@./DESIGN.md**.
Read before any UI/styling/microcopy/motion work.
Preference log (pending corrections): @./.omd/preferences.md
Precedence: DESIGN.md > preferences.md > your defaults.
AGENTS.md body
## Design System (oh-my-design)
**Before any UI, styling, copy, or motion change, open and read `./DESIGN.md` in full.** It is the authoritative brand/design spec. Treat its tokens, voice, and component rules as binding unless the user overrides in chat.
If present, read `./.omd/preferences.md` — pending corrections not yet folded into DESIGN.md. Apply them; flag conflicts.
.cursor/rules/omd-design.mdc (whole, frontmatter 포함)
---
description: Authoritative brand & UI design system. Read DESIGN.md before UI work.
globs:
- "**/*.tsx"
- "**/*.jsx"
- "**/*.vue"
- "**/*.svelte"
- "**/*.css"
- "**/*.scss"
- "**/tailwind.config.*"
- "**/components/**"
- "**/app/**/page.*"
alwaysApply: false
---
<!-- omd:start v=1 hash=<HASH> -->
The authoritative design spec lives at `@DESIGN.md` (repo root). Open and read before generating/modifying UI.
Pending preference corrections: `@.omd/preferences.md`.
Precedence: DESIGN.md > preferences.md > framework defaults.
<!-- omd:end -->
해시 계산
<HASH> = sha256 of the body content (마커 제외, body 텍스트만), 12자 hex prefix:
node -e "console.log(require('crypto').createHash('sha256').update(process.argv[1]).digest('hex').slice(0,12))" "<body 텍스트>"
block 모드 마커 형식 정확히:
<!-- omd:start v=1 hash=ab12cd34ef56 -->
<body>
<!-- omd:end -->
실행 절차
사용자가 어떤 모드를 요청하는지 분기:
- 인터랙티브 (디폴트) — drift 발견 시 사용자에게 묻기
- --force 의도 ("강제 덮어쓰기") — drift 무시하고 덮어씀
- --check 의도 ("상태만 검사") — 파일 상태만 출력, write 안 함
각 shim별로:
Step 1 — Read existing
파일 없으면 → status: missing, 새로 write 진행
파일 있으면 → 내용 파싱
Step 2 — block 모드 파싱
<!-- omd:start v=N hash=H --> 라인 찾기:
- 없으면 → status:
missing (block 부재, 사용자 content 외에 새로 추가 필요)
- 있으면 → marker 사이의 본문 추출. 추출된 본문의 sha256:12를 계산해서 marker의
hash=H와 비교
- 불일치 → status:
drifted (사용자가 수동 편집함)
- 일치 + 본문 == 템플릿 → status:
clean
- 일치 + 본문 != 템플릿 → status:
out-of-date (omd 템플릿이 갱신됨)
Step 3 — whole 모드 파싱
existing 전체 content와 rendered 템플릿 비교:
Step 4 — drift 처리
- 인터랙티브: drift된 shim별로 "${path}는 수동 편집됐어요. 덮어쓸까요? (yes/no/show diff)" 묻기
- --force: drift 무시 덮어씀
- --check: drift 있으면 exit 1 동등 — 사용자에게 "drift detected" 보고 후 종료
Step 5 — Write
- block 모드: existing 안의 marker block만 새 hash + 새 body로 교체. 마커 외부 사용자 content는 보존
- whole 모드: 파일 전체를 새 rendered content로 교체. 디렉토리 (
.cursor/rules/) 없으면 mkdir
Step 6 — sync-lock 갱신
.omd/sync.lock.json 기록 (없으면 만든다):
{
"design_md_hash": "<DESIGN.md sha256:12>",
"targets": {
"CLAUDE.md": "<hash>",
"AGENTS.md": "<hash>",
".cursor/rules/omd-design.mdc": "<hash>"
},
"updated_at": "<ISO timestamp>"
}
DESIGN.md 해시:
[ -f DESIGN.md ] && node -e "console.log(require('crypto').createHash('sha256').update(require('fs').readFileSync('DESIGN.md')).digest('hex').slice(0,12))"
결과 보고
CLAUDE.md (block) — updated
AGENTS.md (block) — unchanged
.cursor/rules/omd-design.mdc — created
DESIGN.md hash: ab12cd34ef56
언제 실행하나
- DESIGN.md 변경 직후 (shim hash 갱신용)
- 새 프로젝트 첫 도입 (3종 생성)
.claude / .cursor 디렉토리 추가 후
- "drift 확인" 요청
금지
- 마커 안 본문에 임의 추가/축약 금지 — 위 템플릿 정확히 사용
- block 모드 파일에서 마커 외부 사용자 content 절대 삭제 금지
.omd/sync.lock.json 무시 금지 — 항상 갱신
- DESIGN.md가 없어도 shim은 만들 수 있음 (DESIGN.md 생성 후에 hash만 채움)