스킬 관계 그래프 — 구조와 운영
스킬이 수십 개를 넘어서면 "어떤 스킬이 무엇을 전제로 하는가"가 조직의 기억 밖으로 사라진다. 이 문서는 8장 §2에서 소개한 스킬 관계 그래프의 구체적 구조 — 데이터 원천, 스키마, 관계 어휘, 생성 파이프라인, 검증과 운영 워크플로우 — 를 하나의 장으로 정리한다.
출처: ai-workspace-standards ADR-0060 Skill Relationship Graph as Generated Projection (Amendments 1–6) · ADR-0061 Decision Record Standard · scripts/generate-skill-graph.ts v1.7.1
- 그래프가 왜 1차 저장소가 아니라 "항상 재생성되는 투영"인가
- 관계를 유도하는 다섯 가지 데이터 원천과 우선순위
- 노드/엣지 스키마와 10개의 타입화된 관계 어휘
- 명시적·실험적·투영의 3계층 관계 모델과 90일 규칙
- 생성·검증·동기화 파이프라인과 실전 관계 추가 절차
개요 — 왜 그래프인가
스킬·에이전트·ADR 사이의 관계("이 스킬은 저 스킬을 먼저 실행해야 한다", "이 에이전트는 저 스킬을 쓴다")를 자유 텍스트로 적어 두면 세 가지가 반드시 일어난다. 첫째, 원천이 바뀌어도 문서는 그대로 남아 낡는다. 둘째, 관계가 파일 여기저기 흩어져 검색이 안 된다. 셋째, 사람이 목록을 고유지 않는 한 검증도 안 된다.
스킬 관계 그래프는 이를 "직접 쓰지 않고 유도한다"로 풀었다. 관계의 원천은 이미 존재하는 구조화 데이터(SKILL.md 프론트매터, 에이전트 파일, variant 매니페스트)이고, 그래프는 그 투영(projection)이다. 그래프 파일은 언제 지워도 좋다 — 제너레이터를 다시 돌리면 정확히 같은 방식으로 다시 태어난다. ADR-0060이 이 원칙을 Generated Projection이라는 이름으로 못 박은 이유다.
데이터 원천과 우선순위
제너레이터는 다음 원천을 우선순위 순으로 훑는다. 앞의 원천일수록 의도가 명시적인 것이고, 뒤로 갈수록 암시적 유다.
- SKILL.md 프론트매터 —
prerequisites(필수 선행 스킬)와 타입화된relates_to(관계 어휘 + 대상 + 선택적 메모). 가장 명시적인 원천이다. - 에이전트 파일의
required_skills— 에이전트 → 스킬의used_by관계를 만든다. variant.json의skill_manifest— variant가 어떤 스킬을 어떤 에이전트·페이즈에 물리는지의 매니페스트.phase관계의 원천이다.- 문서 본문의 백틱 참조 — 문서가 스킬 이름을 정확한 백틱 이름으로 언급하면
references엣지가 된다(오탐을 막기 위해 정확 일치만 인정). docs/skill-graph.overrides.json— 위 원천으로는 유도되지 않는 관계를 추가하거나, 자동 유도된 관계를 억제하는 탈출구. 스코프별 오버라이드도 지원한다.
프론트매터에서 온 엣지에는 provenance: {file, field, index?}가 붙는다. "이 관계가 왜 있나"를 추적하면 언제나 원천 파일의 몇 번째 필드로 돌아갈 수 있다.
노드와 엣지 스키마
그래프의 커밋 아티팩트는 두 개다 — 기계용 docs/skill-graph.json과 사람이 읽는 관계 표 docs/skill-graph.md. JSON의 최상위 구조는 {version, nodes[], edges[]}다.
{
"version": "1.7",
"nodes": [
{ "id": "handbook", "type": "skill", "layer": "common" },
{ "id": "handbook-reviewer", "type": "agent", "layer": "common" },
{ "id": "ADR-0060", "type": "adr", "layer": "L0" }
],
"edges": [
{
"from": "handbook",
"to": "research",
"type": "requires",
"provenance": {
"file": "skills/handbook/SKILL.md",
"field": "prerequisites",
"index": 0
}
},
{
"from": "handbook-reviewer",
"to": "handbook",
"type": "used_by"
}
]
}
노드는 id·type·layer를 갖는다. 타입은 skill, agent, adr, decision, procedure, output_type 등이고, 계층은 L0(워크스페이스 루트), common(공통 템플릿), variant:<name>, L3(개별 프로젝트)다.
엣지 타입 상세
Amendment 1–6에 걸쳐 자란 관계 어휘 전체다. 방향과 대칭성, 원천을 함께 정리한다. 모든 엣지는 자문적(advisory) — 라우팅과 계획에 정보를 주지만 실행을 강제로 막지는 않는다.
| 엣지 | 의미 | 방향/대칭 | 원천 |
|---|---|---|---|
requires | B는 A의 필수 선행 스킬이다 | A→B (비대칭) | 프론트매터 prerequisites |
relates_to | 일반적 연관(레거시) | A→B | 프론트매터 relates_to |
composes_with | 같은 에이전트 안에서 함께 쓰이는 조합 관계 | 대칭 (symmetric: true 단일 엣지) | Amendment 8 — 한 에이전트의 required_skills 공동 선언에서 유도 |
follows | 순서만 나타냄. 의존성을 함축하지 않는다 | A→B | 프론트매터 |
enables | A의 산출물이 C를 가능하게 한다 | A→C | 프론트매터 |
used_by | 에이전트가 스킬을 사용한다 | agent→skill | 에이전트 required_skills |
phase | 스킬이 워크플로우 페이즈에 배속된다 | skill→phase | variant.json skill_manifest |
supersedes | 문서 계승(구 문서 → 신 문서) | old→new | 문서 메타 |
references | 문서 간 인용 | A→B | 백틱 참조 |
cites_skill | 의사결정 기록이 스킬을 인용 | decision→skill | 결정 기록 본문 |
requires의 방향을 혼동하지 않는 것이 가장 흔한 실수다. A requires B는 "A를 쓰려면 B가 먼저다"이지 "A가 B를 만들어낸다"가 아니다. 방향이 헷갈리면 provenance 필드로 원천 프론트매터를 확인하라.
관계의 3계층 모델
같은 그래프 안에 세 종류의 관계가 섞여 있다. 수명과 신뢰도가 다르므로 계층을 구분해 다룬다.
- L-A 명시적(Explicit) — 프론트매터의 타입화된
relates_to. 의도적으로 영구적이며 그래프의 1차 원천이다. - L-B 실험적(Experimental) — 오버라이드 파일의 관계. 반드시
reason과since를 적어야 하고, 90일이 지나면 낡음 경고가 뜬다. "그래프에 있어야 할 것 같은데 프론트매터에 넣기 전 관찰 중"인 관계의 대기소다. - L-C 투영(Projection) — 생성된 그래프 자체. 항상 재생성되며, 결정론성 검증으로 "같은 입력 → 같은 출력"이 깨지지 않았음을 확인한다.
실험적 관계가 안정됐다고 판단되면 프론트매터로 옮겨 L-A로 올린다. 반대로 L-A를 없애려면 프론트매터에서 지우면 된다 — 그래프 파일을 직접 고치는 경로는 존재하지 않는다.
생성 파이프라인
그래프는 네 지점에서 파이프라인과 맞물린다.
scripts/generate-skill-graph.ts— 원천을 훑어skill-graph.json/.md를 생성.--scope <name>으로 템플릿별 범위 그래프를 만든다(공통 + 각 variant, 총 14개 스코프).scripts/verify-skill-graph.ts— 커밋된 그래프가 원천과 일치하는지(드리프트)와 불변식을 검증.dev-sync.ts4.65단계 — 매/sync마다 전 스코프 그래프를 재생성하고 드리프트를 확인. "그래프를 고르는 작업"이 커밋 흐름에 녹아 있다.new-project.ts7.6단계 — 새 프로젝트 스캐폴딩 시점에 그 프로젝트의docs/skill-graph.json을 즉시 생성. 첫/sync를 기다리게 하지 않는다.
스코프 그래프는 통합 L0 그래프의 범위 뷰다. variant 템플릿이 자기 스코프 그래프를 배송하면, 그 템플릿에서 태어난 프로젝트는 처음부터 자기에게 relevant한 관계 지도를 갖고 시작한다.
선언적 vs 추론적 구축 전략
관계를 어디서 끌어낼 것인가에는 두 전략이 있다.
- 선언적(Declarative) — 프론트매터에 관계를 직접 선언한다(Amendment 3). 의도가 명확하고 검증이 단순하지만, 스킬 작성자의 규율에 의존한다.
- 추론적(Inferential) — 기존 구조화 데이터에서 관계를 유도한다(Amendment 4, co-newbiz 선례). 절차 스키마의 페이즈 인접성이나 규칙 술어를 근거로 삼는다. 프론트매터를 하나도 추가하지 않고 커버리지를 늘릴 수 있다.
비교 실험(scripts/experiments/infer-graph-from-phases.ts, 읽기 전용)의 결론은 절충이다 — 절차 스키마가 풍부한 영역에서는 추론이 잘 동작하지만, 그렇지 않은 템플릿에서는 선언적 전략이 더 낫다. 그래서 새로운 기본 추출 모드는 채택되지 않았고, 두 전략은 공존한다: 스키마가 있는 곳은 유도하고, 나머지는 선언으로 채운다.
의사결정 체인과 검증
그래프가 ADR·결정 기록까지 품는 이유는 "관계"와 "근거"를 한 지도에 올리기 위해서다. ADR-0061의 의사결정 체인 — Agent, Skill, Knowledge, Evidence, Rule, Decision — 을 scripts/validate-decisions.ts가 fail-closed로 검증한다.
- 결정 기록의 필수 프론트매터와 증거 장부(evidence ledger) 참조 존재 여부
- 규칙 ID 형식과 스킬 참조 해결 가능 여부
- 전파 결합 규칙 — L1에 발행된 스킬이 L1에 없는 대상과 관계를 맺는 것을 금지한다. 없으면 하위 복사본마다 매달린 엣지(dangling edge)가 생긴다.
그래프는 supersedes·cites_skill 엣지로 "이 결정이 어떤 스킬 위에서, 어떤 문서를 계승해서 나왔는지"를 보여준다. 관계가 근거 없이 늘어나는 것을 구조적으로 막는 장치다.
실전 워크플로우 — 관계 추가하기
실제로 관계 하나를 추가할 때의 최소 절차다.
- 관계 선언 — 대상 스킬의
SKILL.md프론트매터에 관계를 쓴다:relates_to: - { skill: research, type: requires } - { skill: pdf-export, type: enables, note: "produces layout spec" } - 형식 검증 —
bun scripts/validate-skills.ts(관계 형식 검사) 후bun scripts/generate-skill-graph.ts실행. - 드리프트 확인 —
bun scripts/verify-skill-graph.ts로 드리프트 없음 확인,docs/skill-graph.md에서 해당 스킬의 관계 표를 눈으로 확인. - 최종 커밋 —
/sync가 4.65단계에서 전 스코프 재생성·검증을 대신 해 주므로, 커밋 전에 직접 그래프 파일을 고르지 않았는지만 확인하면 된다.
아직 확신이 없는 관계라면 프론트매터 대신 오버라이드 파일에 적는다. reason과 since를 남기면 90일 뒤 시스템이 "아직 관찰 중인가?"를 물어본다.
로드맵
ADR-0060의 Phase 2+ 비전은 다음과 같다. 현재는 미구현 상태다.
- 생애주기 상태 기계 — 스킬의 draft/active/retired 전이를 그래프 노드 상태로 추적
- 버전 관리·마이그레이션 — 그래프 스키마 버전 간 이동 도구
- 그래프 인텔리전스 — 관계를 이용한 라우팅 제안, 컨텍스트 번들 자동 구성
- 감사 추적 스냅샷 — 시점별 그래프 스냅샷으로 관계 변화 이력 조회
핵심은 지금의 설계가 이 확장을 막지 않는다는 것이다. 그래프가 1차 저장소가 아니라 투영이기 때문에, 소비자를 늘리거나 노드에 상태를 더해도 원천과 제너레이터만 고치면 된다.