Community코딩 & 개발github.com

c4

코드베이스에서 시스템 컨텍스트, 컨테이너, 컴포넌트 수준의 C4 아키텍처 뷰를 수집하고 시각화 캔버스에 계층적 사다리 구조로 표현합니다.

c4란 무엇인가요?

이 스킬은 코드베이스에서 C4 아키텍처 다이어그램을 생성합니다. 세 가지 확대/축소 수준(시스템 컨텍스트 L0, 컨테이너 L1/L1b, 컴포넌트 L2/L2b)으로 구성된 레벨 사다리를 제공하며, 각 레벨은 시각화 캔버스 위에 컨테이너 박스로 표현됩니다. 스킬은 먼저 코드베이스를 읽는 정찰(scout) 하위 에이전트를 실행하여 요소, 관계, 경계 및 레벨 할당에 대한 증거 기반 인벤토리를 수집합니다. 그런 다음 이러한 사실을 조정하여 단일 원장(ledger)으로 만든 후, 우선순위 규칙에 따라 각 레벨에 그릴 관계를 결정합니다. 결과물은 5개 섹션(레벨당 하나)으로 구성된 캔버스로, 명확한 소유권 경계와 증거 참조를 제공합니다. 이 스킬은 특히 Claude Code, Cursor, Codex와 같은 AI 에이전트 플랫폼에서 사용하도록 설계되었으며, 저장소에 대한 사전 지식 없이 작동하며 정찰을 통해서만 정보를 학습합니다. 가상의 요소, 관계 또는 경계를 절대 발명하지 않으며, 모든 것이 코드베이스에서 인용 가능해야 합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aviralmansingka/dotfiles/tree/HEAD/agents/.agents/skills/c4

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

c4은(는) 무엇을 하나요?

c4는 "이 시스템이 무엇인지, 무엇으로 구성되어 있는지, 누가 누구를 호출하는지"를 세 가지 확대/축소 수준으로 설명합니다. 표면 엔진은 visualize입니다: 하나의 rataflow 캔버스, 레벨당 하나의 설명 섹션, 소유권을 위한 containers 박스. 렌더러 자체에 대해서는 agents/.agents/skills/visualize/SKILL.md를 참조하십시오. 이 스킬은 c4가 추가하는 것만 다룹니다.

c4는 visualize가 수행하지 않는 세 가지를 추가합니다:

  1. 레벨 사다리. L0 컨텍스트, L1/L1b 컨테이너, L2/L2b 컴포넌트. 각 레벨은 다음 레벨을 동기 부여하기 위해 존재하며, 독자가 현재 있는 레벨은 범례가 아닌 박스에서 볼 수 있습니다.
  2. 사실 수집. c4는 누가 무엇을 왜 호출하는지에 대해 완전해야 합니다. 정찰은 코드베이스를 읽고 사양이 존재하기 전에 증거 기반 요소 및 관계 인벤토리를 생성합니다.
  3. 포함 관계를 주장으로. 컨테이너 박스는 해당 컴포넌트의 자체 부품만을 보유하며 다른 것은 포함하지 않습니다. 이것은 소유권 주장이므로 출처가 필요하며, 독자가 박스를 코드와 비교하여 확인할 수 있어야 합니다.

요소, 관계 또는 경계를 발명하지 마십시오. 정찰이 인용할 수 없으면 그려지지 않습니다.

라우팅

질문사용법
실제 코드베이스 내 컴포넌트의 C4 레벨이 스킬
이미 알고 있는 사실로부터 하나의 관계 그래프visualize
채팅 응답 내 다이어그램mermaid 도구
정적 ANSI / PNGmermaid 스킬
아키텍처 프로즈 페이지 또는 데크artifact 스킬

/c4 <컴포넌트> 또는 "X의 C4 뷰를 보여줘"가 호출 방식입니다. 스킬은 이전에 본 적이 없는 저장소에서 작동합니다: 정찰이 정보를 배우는 유일한 방법이므로, 여기서는 코드에 대한 사전 지식에 의존하지 않습니다.

0단계 — 컴포넌트 고정

정찰을 실행하기 전에 다음을 명시하십시오:

컴포넌트: machine manager
저장소 루트: /Users/aviral/modal
앵커:    machine_manager/  (하나의 패키지, 하나의 배포 가능 단위)
  • 컴포넌트는 독자가 코드에서 가리킬 수 있는 하나의 대상입니다: 서비스, 패키지, 하나의 배포 가능 단위. 요청이 여러 배포 가능 단위에 걸친 하위 시스템을 지정하는 경우, 배포 가능 단위 하나를 선택하고 어떤 이웃을 외부 시스템으로 가져오는지 말하십시오.
  • 저장소 루트는 정찰이 시작되는 곳입니다. 체크아웃이 존재하는지 확인하고, 경로를 가정하지 마십시오.
  • 앵커는 컴포넌트가 하나의 단위(패키지 매니페스트, Helm 차트, Terraform 모듈, proto 서비스, main.go)라는 가장 강력한 단일 증거입니다. 하나를 지정할 수 없으면 컴포넌트는 아마도 두 개의 컴포넌트일 것입니다. 추측하지 말고 사람에게 물어보십시오.

최대 하나의 명확성 질문(컴포넌트 경계만이 물어볼 가치가 있습니다)을 하십시오. 그렇지 않으면 결정하고 기록하십시오.

1단계 — 정찰 발사

네 가지 프롬프트가 prompts/에 있습니다. 각각은 완전한 하위 에이전트 작업입니다. subagent 호출로 agent: "scout"(읽기 전용 정찰 — 정찰은 저장소를 편집하지 않아야 함)와 함께 모두 동시에 실행되도록 한 번에 네 개를 발사하고, cwd:는 0단계에서 확인된 저장소 루트로, 컴포넌트 이름은 <컴포넌트>를 대체합니다:

정찰프롬프트반환
범위(Scope)prompts/scope.md요소 인벤토리: id, 한 줄 역할, 진입점, 배포 가능 단위, 저장소, 외부 서비스, 액터, 파일 경로
관계(Relationships)prompts/relationships.mdfrom → to : 동사 + 전송 행, 각각 file:line 포함
경계(Boundary)prompts/boundary.md멤버 대 외부 시스템 + 각 멤버십을 정당화하는 모듈/배포 경계
레벨(Levels)prompts/levels.md요소별 레벨 할당, L1/L1b(L2/L2b)로 분할되어야 하는 레벨

모든 정찰은 file:line 참조가 있는 증거를 반환합니다. 참조가 없는 행은 소문입니다. 삭제하거나 해당 정찰에 출처를 다시 요청하십시오.

저장소 루트에서 정찰을 발사하십시오 — 세션을 그곳에서 실행하거나(또는 cwd:를 세션이 이미 있는 동일한 디렉토리로 설정하십시오). cwd가 시작 세션과 다른 정찰은 프로세스가 시작되기 전에 죽을 수 있으며, 실패는 "해당 창에 pi 프로세스가 나타나지 않음"으로 읽힙니다.

하위 에이전트를 폴링하지 마십시오. 결과는 저절로 도착합니다. 네 개가 모두 돌아오면 계속 진행하십시오. 하나가 실패하면 어느 것인지 말하고, 재시도하거나 생성 기록에 공백을 기록하십시오. 절대 기억에서 구멍을 메우지 마십시오.

2단계 — 하나의 원장으로 조정

네 가지 반환을 생성 기록의 세 테이블로 병합하십시오. 이것이 전체 사실 기반입니다. 사양은 여기에 없는 어떤 것도 포함할 수 없습니다.

요소:   id | 레이블 | 역할 | 클래스(actor|external|member|store) | 증거
관계:  id | from → to | 동사 + 전송 | 레벨 | 증거
경계:   id | 내부/외부 | 정당화 경계 | 증거
  • 충돌은 더 강력한 출처(매니페스트나 배포 차트가 주석보다 우선, 호출 사이트가 독스트링보다 우선)를 인용하여 해결하고, 패배한 주장은 삭제되지 않고 기록됩니다.
  • 해결되지 않은 충돌과 살아남은 출처가 없는 관계는 공개 질문으로 기록됩니다. 침묵은 결함입니다. 눈에 보이는 의심은 그렇지 않습니다.
  • 요소당 하나의 id를 유지하고 레벨 전체에서 재사용하십시오. 따라서 q → reg를 추적하는 독자는 L1과 L2에서 동일한 두 박스를 볼 수 있습니다.

3단계 — 그릴 내용 결정(우선순위 지정)

C4 뷰는 중요성에 대한 판단이지, 호출 그래프를 덤프하는 것이 아닙니다. 원장은 정찰이 찾은 모든 관계를 보유합니다. 다이어그램은 독자가 필요로 하는 관계를 보유하고, 무엇을 생략했는지 명시적으로 말합니다.

관계는 다음 조건 중 하나 이상을 충족할 때 자리를 얻습니다:

id테스트예시
I1컴포넌트 경계를 넘음(멤버 ↔ 외부, 외부 ↔ 외부)webapi → Latitude API, machines → sshx.io
I2소스가 호출하는 기본 요청, 제어 또는 데이터 경로(프로비저닝, 하트비트, 감사, 조정, 부팅)컨트롤 플레인 → private gRPC, River 큐 → 워커
I3독자가 필요로 하는 프로토콜 또는 한정자를 전달: RPC 동사, 전송, 포트, 버킷, 간격, 타임아웃등록 + 하트비트 매 1분, gcore 동기화 매 1분
I4독자가 상자에서 추론할 수 없는 데이터 저장소 또는 액터를 설명저장소 → Postgres, ops + mmctl → webapi
I5셀 수 있어야 하는 중복 또는 병렬 경로의 한 다리machines → boot 그리고 boot → machines; 두 개의 독립적인 풀

삭제 클래스 — 관계는 다음 중 하나로만 다이어그램을 떠납니다:

id클래스설명
C1내부 세부 사항하나의 컨테이너 내부에 완전히 있으며, 경계, 프로토콜 또는 액터 정보를 추가하지 않음(워커 → 저장소 쿼리당 행, 저장소의 작성자가 이미 그려져 있는 경우)
C2중복 호출 사이트그려진 관계와 동일한 홉, 작업 유형 또는 인수만 다르며, 그려진 레이블이 이미 포함함
C3헬퍼유일한 작업이 동일한 컨테이너에 재진입하는 요소(그려진 두 박스 사이의 클라이언트 래퍼)
C4중복 다리경로의 추가 병렬 다리로, 독자가 셀 수 있을 필요가 없는 경우(동일한 버킷, 동일한 전송의 두 번째 아티팩트)

판단을 정직하게 유지하는 규칙:

  • 하나의 화살표는 여러 호출 사이트를 전달할 수 있습니다. 레이블이 동사를 포함하는 경우(생성 / 종료 / 수리). 이는 C2 접기(fold)이지 삭제가 아닙니다.
  • 경계 교차가 동점을 이깁니다. (I1이 I3보다 우선, I3이 I2보다 우선). 내부 관계를 위한 공간을 만들기 위해 외부 홉을 삭제하는 다이어그램은 자체 우선순위를 역전시킨 것입니다.
  • 의심스러우면 그리십시오. 그리고 해당 레벨의 설명이 왜 그 관계가 있는지 설명하게 하십시오. 의심은 삭제 이유가 아닙니다. C1–C4가 삭제 이유입니다.
  • 절대 조용히 삭제하지 마십시오. 모든 원장 행은 다음 중 하나로 끝납니다: 그려짐, 다음으로 접힘 <그려진 관계>(접힘이 C2로 정당화됨), 또는 생략됨 — C1|C2|C3|C4와 한 줄 이유. 적용 범위 맵(7단계)은 네 가지 개수를 명시합니다: 그려짐, 접힘, 클래스별 생략, 미설명.
  • 범위 축소는 다른 것이며 호출자의 말이 필요합니다. "컨트롤 플레인 뷰만" 또는 "최대 20개 관계"는 범위 요청입니다: 이를 근거(근거: 호출자 범위, N개 관계)와 계산된 원장과 함께 기록하십시오. 우선순위 지정이 기본값입니다. 하위 집합은 생성자가 추론하는 결정이 아니라 호출자가 내리는 결정입니다.

4단계 — 레벨 사다리

목표 형태는 위에서 아래로 다섯 개의 섹션입니다:

L0 · 시스템 컨텍스트      컴포넌트와 그 이웃을 위한 하나의 노드
L1 · 컴포넌트            컴포넌트를 한 번 열어, 그 부품에 대한 컨테이너
L1b · <두 번째 측면>      동일한 깊이, 시스템의 다른 쪽
L2 · 내부 — <슬라이스 A>  멤버 간 관계, 그들에 대한 컨테이너
L2b · 내부 — <슬라이스 B>  동일한 깊이, 다른 슬라이스

이것이 사다리입니다: 다섯 섹션 캔버스가 전달물입니다. 아래 분할 규율이 숫자와 함께 충족되지 않는 한 더 많은 섹션은 결함입니다.

각 레벨은 그 위의 레벨이 존재한 후에만 그리고, 각 레벨에 설명을 제공한 후에 다음으로 넘어가십시오.

레벨그림박스 동작
L0 시스템 컨텍스트컴포넌트를 하나의 일반 노드로, 주변의 모든 액터와 외부 시스템, 그리고 그들 사이의 굵은 화살표컨테이너 없음, focus 없음, 이중 테두리 없음 — 요점은 주변 세계이므로 컴포넌트는 다른 상자처럼 보입니다
L1 컨테이너컴포넌트를 한 레벨 열어: 자체 배포 가능/런타임 단위 내부 하나의 컨테이너; L0 외부 시스템은 외부에 유지멤버에 대한 컨테이너 박스
L1b 사이드 뷰하나의 L1이 진정으로 흐름을 담을 수 없을 때(플릿 끝, 데이터 플레인, 배치 경로) 선택적 두 번째 슬라이스 — 측정 가능하며 결코 새로운 주제가 아님컨테이너, 동일한 규칙
L2 컴포넌트내부 하나의 컨테이너의 관계 — L1의 멤버들, 이제 서로 호출그들 주위의 컨테이너 박스
L2b동일한 깊이의 선택적 두 번째 슬라이스, 하나의 L2가 관계를 라우팅할 수 없거나 두 이야기가 별도의 순위가 필요할 때컨테이너, 동일한 규칙

협상 불가능한 레벨 규칙:

  • L0는 컴포넌트를 하나의 일반 노드로 표시합니다. 전체 컴포넌트를 위한 하나의 박스, 일반 테두리, 주변의 액터 및 외부 시스템을 더합니다. 부품, 리스너, 테이블이 아닙니다. 그것들은 다음 레벨입니다. L0에 컴포넌트 내부에 속하는 노드가 두 개 이상 있으면 컨텍스트 뷰가 아닙니다. L0의 포함 관계는 독자에게 아직 보여지지 않은 내부를 주장하는 것이며, focus는 아직 존재하지 않는 레벨을 가리킬 것입니다.
  • L1/L1b는 L0의 박스를 엽니다. 모든 멤버는 컨테이너 내부에 있습니다. L0에서 외부였던 모든 요소는 컨테이너 외부에 있습니다. 박스의 경계 상자 외부에 그릴 수 없는 멤버는 자체 컨테이너 항목을 얻습니다(연속성 규칙 참조) — 절대 모호하게 처리하지 마십시오.
  • L2/L2b는 하나의 박스 내부에 유지됩니다. 모든 L2 관계의 두 끝점은 컨테이너 멤버입니다. 관계가 박스를 떠나면 L1/L1b에 속합니다.
  • 레벨은 스스로를 설명합니다. 제목은 짧게(L0 · 시스템 컨텍스트). 설명은 박스 내부에 무엇이 있는지, 박스 외부에 무엇이 있는지, 그리고 이웃 레벨과 어떻게 관련되는지를 명시합니다. 2-3개의 줄 바꿈 행을 목표로 하십시오.
  • 움직임은 C4 속성이 아닙니다. 레벨 0-1b는 정적입니다(dots: 0). 관계가 라이브 흐름인 내부 레벨은 경로당 정확히 하나의 점을 가질 수 있습니다(flow: true, dots: 1). 선택을 기록하십시오. 사다리를 장식하기 위해 외부 화살표에 애니메이션을 적용하지 마십시오.

분할 규율 — 레벨은 깊이(DEPTH)이지 주제(TOPIC)가 아닙니다

C4 레벨은 하나의 확대/축소에서 하나의 질문에 답합니다. 동일한 깊이의 두 레벨은 하나의 섹션이 내용을 담을 수 없었기 때문에만 존재합니다. 새로운 주제는 섹션을 추가하는 이유가 아닙니다.

  • 절대 L1c, L1d, L1e 또는 다섯 번째 측면을 추가하지 마십시오. 사다리는 세 가지 깊이(컨텍스트, 컨테이너, 컴포넌트)와 첫 번째 아래 각 깊이에서 최대 두 개의 슬라이스를 가집니다. 서브시스템이나 언급당 하나의 슬라이스로 성장하는 캔버스는 레벨 제목을 단 주제 목록입니다.
  • 두 번째 슬라이스는 측정값을 명시해야 합니다: --check가 거부하는 경로, 보고하는 공유 복도, 또는 충돌하는 순위(공통 외부가 없는 두 개의 외부 끝). "비좁았다"는 이유가 될 수 없습니다.
  • 동일 깊이의 슬라이스는 박스, 레이블 및 id를 공유합니다. L1과 L1b는 동일한 컴포넌트를 동일한 멤버 id로 그립니다. L2와 L2b는 동일한 멤버를 그립니다. 가장자리 집합과 순위만 다르며, 각 설명은 어느 슬라이스인지 명시합니다.
  • 슬라이스는 b로 명명됩니다. (l1b, l2b). 깊이를 절대 발명하지 마십시오.
  • L2를 넘는 깊이는 그려지지 않습니다. 컴포넌트 내부가 여전히 분해되면 기록에 그렇게 말하고 중지하십시오: 코드 클래스와 함수는 독자가 요청한 C4 레벨이 아닙니다. 사다리는 요청이 끝나는 곳에서 끝납니다.
  • 원장이 보유하고 사다리가 그리지 않는 모든 것은 기록된 범위 결정입니다 (6단계), 조용한 삭제나 새로운 섹션이 아닙니다.

5단계 — 사양 메커니즘

하나의 캔버스, 하나의 읽기 방향, 레벨당 하나의 섹션:

{
  "direction": "lr",
  "theme": "gruvbox",
  "diagrams": [
    {
      "id": "l0",
      "title": "L0 · 시스템 컨텍스트",
      "description": "시스템 컨텍스트: 관리자는 하나의 박스입니다. ...",
      "nodes": [ ... ],
      "edges": [ ... ]
    },
    {
      "id": "l1",
      "title": "L1 · 관리자",
      "description": "L0의 박스를 한 레벨 열었습니다: ...",
      "containers": [ { "label": "Machine manager", "members": ["api", "q", "db"] } ],
      "layers": [ ["actor"], ["api", "q"], ["db"], ["prov"] ],
      "nodes": [ ... ],
      "edges": [ ... ]
    }
  ]
}
  • direction: "lr"는 한 번만, 캔버스에. 절대 다이어그램별 재정의 없음: 모든 섹션에서 방향을 바꾸는 독자는 사다리를 잃습니다.
  • 다섯 개의 섹션. l0, l1, l1b, l2, l2b, 이 순서대로. 여섯 번째 섹션은 3단계의 측정값이 기록되어야 합니다. 열 개 또는 스무 개 섹션의 캔버스는 주제 목록이지 사다리가 아닙니다. 세 가지 깊이, 각각 두 개의 슬라이스로 접으십시오.
  • containers는 다이어그램별 목록입니다 {label, members}. 박스는 멤버 주위에 자란 실제 이중 테두리 사각형이며, 레이블이 상단 가장자리에 설정됩니다. 다이어그램당 여러 박스가 허용됩니다.
  • 멤버 id는 해당 다이어그램의 nodes에 존재해야 합니다. 노드의 이름을 지정하지 않는 멤버 id는 파서에 의해 조용히 삭제됩니다. 그러면 박스는 사용자가 선언한 것보다 더 적은 노드 주위에 그려지며 --check는 경고하지 않습니다. 선언한 멤버에 대해 그려진 박스를 계산하십시오.
  • 연속성 규칙. 컨테이너는 직사각형입니다...

[번역을 위해 잘림]

관련 스킬