JSON·RSS·npm으로 배포하는 "콘텐츠=데이터" 큐레이션awesome-mac는 "macOS용 좋은 앱·도구를 카테고리별로 모아 한 문서에 정리한 커뮤니티 큐레이션 리스트"다. 텍스트 에디터·IDE·디자인 도구·AI 도구·브라우저·유틸리티까지 29개 대분류, 40여 개 소분류로 약 1,300개 앱이 알파벳순으로 나열되고, 각 항목은 한 줄 설명 + 공식 링크 + 아이콘 배지(오픈소스/무료/앱스토어/네이티브/Awesome)로 이뤄진다.
여기까지는 sindresorhus/awesome 계열의 흔한 "Awesome 리스트"다. awesome-mac이 특별한 건 이 마크다운을 "읽는 문서"가 아니라 "기계가 파싱하는 데이터"로 설계했다는 점이다. README에 숨겨진 <!--start-->/<!--end--> 마커 사이 영역을 remark로 파싱해 dist/awesome-mac.json을 만들고, 그걸 npm 패키지로 배포한다. 즉 "맥 앱 명단"이 곧 import 해서 쓰는 데이터셋이 된다.
보통 Awesome 리스트는 정성껏 손으로 쓴 맛집 노트다 — 사람이 읽기엔 좋지만, 노트일 뿐이다. awesome-mac은 이 노트를 한 번 쓰면 자동으로 여러 형태로 퍼지는 편집 시스템으로 만들었다.
노트(README)를 고치면 → 기계가 항목을 뜯어 깔끔한 데이터 카드(JSON)로 바꾸고 → 그걸로 검색되는 웹사이트를 짓고(idoc), 새로 추가된 집만 골라 뉴스레터(RSS)로 보내고, 개발자가 코드에서 불러 쓸 수 있게 상자(npm 패키지·Docker)에 담아 배송한다. 사람은 노트만 잘 쓰면 되고, 나머지 배포는 파이프라인이 한다.
sindresorhus/awesome에서 시작된 특정 주제의 고품질 자료를 엄선해 마크다운으로 정리하는 오픈소스 문화. "많이"가 아니라 "엄선"이 핵심이라 기여 규약(한 항목당 PR 하나, 알파벳순, 중복 금지, 한 문장 설명)이 엄격하다. awesome-mac은 그중 macOS 앱에 특화된 대표 리스트다.awesome-mac은 새로 뜬 신상이 아니다. GitHub에서 손꼽히게 오래·널리 별을 받은 macOS 큐레이션으로, 수년째 꾸준히 갱신돼 온 클래식이다. 이런 노장이 2026년 7월 TrendShift Daily 상위(#6)로 다시 올라온 건, 리스트 자체의 방대함에 더해 최근의 "데이터화 + 자동화 + AI 유지보수" 리뉴얼이 개발자들의 관심을 끌었기 때문이다. (TrendShift의 굵은 숫자는 별 수가 아니라 사회적 언급 모멘텀이다.)
텍스트 에디터부터 데이터 복구·프록시/VPN·양자화 로컬 LLM 도구까지, macOS에서 쓸 만한 거의 모든 범주를 커버한다. 본문(README.md) 하나가 약 1,300개 항목 · 2,000개 이상의 링크로 구성되고, 영어·중국어·일본어·한국어 4개 언어판을 동시 유지한다. "맥 새로 샀는데 뭐 깔지?"에 대한 사실상의 표준 답안지라, 검색 유입과 재방문이 끊이지 않는다.
단순 열람용 문서가 아니라 npm i awesome-mac로 설치해 JSON 데이터를 코드에서 import할 수 있다. "맥 앱 추천기"나 "카테고리 브라우저" 같은 걸 만들 때, 남의 잘 관리된 데이터셋을 그대로 끌어다 쓸 수 있다는 실용성이 개발자에게 매력적이다. 언어별 서브패스(awesome-mac/ko 등)까지 제공한다.
최근 저장소에 .codex/skills/awesome-mac-maintainer라는 AI 에이전트 스킬이 추가됐다. Codex 같은 코딩 에이전트에게 "이 앱을 적절한 카테고리에 추가하고 4개 언어 README에 동기화해줘"라고 시키면, 스킬이 카테고리 선택·알파벳 정렬·한 문장 설명·다국어 동기화 규칙을 지키며 편집한다. "오픈소스 큐레이션 + AI 유지보수"라는 2026년다운 조합이 화제성을 더했다.
master에 푸시만 하면 GitHub Actions가 JSON 생성 → RSS 갱신 → GitHub Pages 배포 → 태그·체인지로그 → npm 배포(provenance) → Docker 이미지 빌드·푸시까지 한 번에 처리한다. "마크다운 한 줄 고쳤을 뿐인데 웹사이트·패키지·도커·RSS가 전부 최신화"되는 이 흐름 자체가 CI/CD 학습용 좋은 레퍼런스다.
awesome-mac의 코드는 크지 않다. 핵심은 build/의 두 스크립트와 설정 파일 몇 개뿐. 하지만 "마크다운 하나를 여러 제품으로 바꾸는" 파이프라인의 각 단계가 서로 다른 도구로 잘 분업돼 있어, 스택 지도를 그리면 현대 문서-데이터 워크플로우의 축소판이 된다.
순수 마크다운이 전부다. README.md(영어, ~1,667줄) + README-zh.md·README-ja.md·README-ko.md 3개 번역판. 여기에 command-line-apps*.md(CLI 앱)·editor-plugin*.md(에디터 플러그인) 같은 곁가지 리스트가 붙는다. 데이터로 뽑을 영역은 <!--start-->와 <!--end--> HTML 주석으로 구획된다.
| 도구 | 역할 |
|---|---|
| remark + remark-gfm | 마크다운을 AST(구문 트리)로 파싱하는 unified 생태계 파서. GFM(GitHub 확장 문법)까지 이해한다. build/ast.mjs의 심장. |
| to-vfile | 파일을 remark가 먹는 "가상 파일(vfile)" 객체로 읽어들이는 어댑터. |
| fs-extra | outputJsonSync 등으로 JSON을 편하게 쓰는 fs 확장. |
| build/ast.mjs | README → dist/awesome-mac{,.zh,.ja,.ko}.json 변환기. (§4에서 정독) |
| build/feed.mjs | git 로그를 훑어 "최근 추가된 앱" RSS(feed*.xml)를 증분 생성. |
| 도구 | 역할 |
|---|---|
| idoc | 저자(jaywcjlove)가 직접 만든 정적 사이트 생성기(SSG). idoc.yml 설정만으로 README들을 검색 가능한 문서 사이트로 빌드. 메뉴·다국어·RSS 링크·GA를 주입한다. |
| Docker | lipanski/docker-static-website(수 MB급 초경량 정적 서버) 위에 dist를 얹은 이미지. docker run -p 9881:3000으로 오프라인 열람. |
| npm registry | awesome-mac 패키지로 발행. main/exports가 JSON을 가리켜, 코드에서 import ... with { type: 'json' }으로 소비. |
| GitHub Pages | peaceiris/actions-gh-pages로 dist를 jaywcjlove.github.io/awesome-mac에 배포. |
.github/workflows/ci.yml이 master 푸시에서 전 과정을 오케스트레이션한다. Node 24 · jaywcjlove/create-tag-action(package.json 버전으로 자동 태깅) · jaywcjlove/changelog-generator(체인지로그) · npm publish --provenance(공급망 증명) · Docker Hub 푸시까지. 그리고 .codex/skills/awesome-mac-maintainer/가 AI 에이전트용 큐레이션 규칙을 담는다.
이 저장소는 라이선스 표기가 일관되지 않다. 루트 LICENSE 파일은 CC0 1.0(사실상 퍼블릭 도메인), package.json의 license 필드는 CC-BY-SA-4.0(저작자표시·동일조건), idoc 푸터는 CC BY 4.0(저작자표시)로 각각 다르다. 리스트 데이터를 상업적으로 재활용하거나 재배포할 계획이라면, 세 표기 중 어느 것이 유효한지 이슈로 확인하는 편이 안전하다.
README 최상단에는 스폰서 배너와 저자 본인이 만든 유료 macOS 앱 수십 개(App Store 링크)가 배치돼 있다. 본문의 큐레이션 항목 자체는 커뮤니티 PR로 채워지지만, 문서의 얼굴 부분은 마케팅 공간이라는 점은 감안하고 보는 게 좋다. Awesome 리스트가 개인 브랜딩·수익화와 결합된 흔한 형태다.
전체 구조는 "하나가 여럿을 낳는" 팬아웃 파이프라인이다. 사람이 만지는 건 왼쪽 끝(마크다운) 하나뿐이고, 오른쪽의 모든 산출물은 자동 생성된다.
ast.mjs는 트리에서 <!--start-->와 <!--end--> 주석 노드의 위치를 찾아, 그 사이 자식들만 잘라내 데이터로 삼는다. 덕분에 상단의 스폰서 배너·설명·목차 같은 "장식"은 데이터에서 자연히 빠진다. 문서에 사람용 콘텐츠와 기계용 콘텐츠를 한 파일에 공존시키는 깔끔한 방법이다.
// build/ast.mjs — 데이터 영역만 슬라이스
const startIndex = tree.children.findIndex(
item => item.type === 'html' && /<!--start-->/.test(item.value))
const endIndex = tree.children.findIndex(
item => item.type === 'html' && /<!--end-->/.test(item.value))
const data = tree.children.slice(startIndex + 1, endIndex)
FS.outputJsonSync(outputFile, getMdToAST([...data]))
각 앱 뒤의 배지(![Open-Source Software][OSS Icon] 등)는 사람 눈엔 그림이지만, ast.mjs의 getIconDetail이 이걸 imageReference 식별자로 인식해 icons:[{type:'oss', url}] 형태로 뽑아낸다. 즉 마크다운의 시각 기호가 곧 구조화된 메타데이터가 된다 — "무료냐/오픈소스냐/앱스토어냐"를 코드로 필터링할 수 있는 이유다. 취소선(~~폐기~~)이 있으면 delete:true로 표시된다.
| 배지 | 의미 | JSON type |
|---|---|---|
| OSS Icon | 오픈소스 (아이콘 클릭 시 저장소) | oss |
| Freeware Icon | 무료 / 무료 개인 라이선스 | freeware |
| app-store Icon | App Store 링크 | app-store |
| Native Icon | 네이티브 앱 | (마커) |
| awesome-list Icon | 대응하는 Awesome 리스트로 연결 | awesome-list |
feed.mjs는 별도 캐시·상태 파일을 두지 않는다. 대신 이미 존재하는 feed*.xml 자체에서 이전 상태를 읽어 증분 계산하고, README별로 최근 50커밋만 스캔한다(--commit-limit·--item-limit 기본 50). 매번 전체 히스토리를 걷지 않아 실행이 빠르고 예측 가능하다. "상태를 산출물에 내장"하는 영리한 무상태(stateless) 설계다.
.codex/skills/awesome-mac-maintainer/SKILL.md는 사람이 암묵적으로 지키던 큐레이션 규칙을 에이전트가 따를 명시적 절차로 적어둔 문서다: ① 비슷한 앱을 검색해 카테고리 결정 → ② 각 언어 파일의 지역 구조 확인 → ③ 4개 언어에 추가 → ④ 설명은 한 문장 → ⑤ rg·git diff로 검증. "설명 스타일"까지 예시로 못박아, AI가 마케팅 문구를 쓰지 않게 가드레일을 건다.
눈여겨볼 점: 실행 코드는 build/ 두 파일이 거의 전부이고, 나머지는 콘텐츠(마크다운)와 자동화 설정이다. 이것이 이 프로젝트의 정체성을 요약한다 — "코드가 주인공인 소프트웨어"가 아니라 "콘텐츠가 주인공이고, 코드는 콘텐츠를 배포하는 얇은 도구"다. feed/는 커밋되지만 dist/는 무시된다는 구분(생성 시점이 다름)도 실무 감각을 보여준다.
이 저장소의 진짜 교육 가치는 앱 추천이 아니라 "콘텐츠를 어떻게 유지보수 가능한 데이터 제품으로 만드는가"다. 기술별로 정리하면:
마크다운을 문자열 정규식으로 파싱하면 금세 무너진다. ast.mjs는 remark로 구문 트리(AST)를 얻어 노드 타입(heading/listItem/link/imageReference)별로 안전하게 순회한다. unified 생태계(remark/rehype)는 문서 자동화의 핵심 무기 — 여기서 "트리로 생각하기"를 익힐 수 있다.
README를 유일한 진실원으로 두고 JSON·사이트·RSS·패키지를 파생시키는 구조는, 문서·API 명세·설정 관리 등 "한 곳만 고치면 나머지가 따라오는" 시스템 설계의 축소판이다. 중복 원본이 없으니 불일치가 생기지 않는다.
idoc로 만든 정적 결과물을 lipanski/docker-static-website(수 MB) 위에 얹는 패턴은, "무거운 nginx 대신 목적에 꼭 맞는 최소 이미지"를 고르는 감각을 보여준다. 정적 배포의 비용·보안 이점도 함께 배운다.
ci.yml 한 파일에 빌드 → 자동 커밋(RSS) → Pages 배포 → 태그 → 체인지로그 → npm provenance 발행 → Docker 빌드·푸시가 순서대로 엮여 있다. 실전 릴리스 자동화를 통째로 읽을 수 있는 드문 교재다. [skip ci]로 무한 루프를 막는 디테일도 눈여겨볼 것.
SKILL.md는 "에이전트에게 규칙을 어떻게 글로 못박나"의 좋은 예다. 워크플로우·큐레이션 규칙·설명 스타일(좋은 예/나쁜 예)·검증 절차·스코프 경계를 명시해, 비결정적 AI에 결정적 가드레일을 씌운다. 자기 프로젝트용 스킬을 쓸 때 참고할 만한 골격이다.
CONTRIBUTING의 규칙(AP 스타일 제목, 알파벳순 삽입, 중복 검색, 한 문장 설명, PR 하나당 제안 하나)과 YAML 이슈 템플릿은, 대규모 커뮤니티 기여를 어떻게 질서 있게 받는가를 보여준다. 코드 리뷰·문서 리뷰 프로세스 설계에도 그대로 응용된다.
| 목적 | 필요한 것 |
|---|---|
| 리스트 열람 | 브라우저만 있으면 됨(GitHub README 또는 GitHub Pages 사이트). |
| 데이터 소비 | Node.js(ESM JSON import는 with { type: 'json' } 지원 버전 권장). npm i awesome-mac. |
| 로컬 빌드 | Node.js(CI는 Node 24) + npm install → npm start(build+ast) / npm run feed. feed는 내부적으로 git CLI를 호출. |
| 오프라인 열람 | Docker. docker run --rm -d -p 9881:3000 wcjiang/awesome-mac:latest 후 localhost:9881. |
| 수록 앱 실행 | 리스트에 오른 앱들은 대부분 macOS 대상(일부 크로스플랫폼). 빌드 자체는 OS 무관. |
정리하면 GPU·대용량 메모리 같은 요구는 전혀 없다. "무거운 소프트웨어"가 아니라 "문서 + 얇은 빌드 도구"이기 때문이다. 학습 목적이라면 Node와 git만 있으면 충분하다.
npm i awesome-mac 후 JSON을 import 해서 카테고리 개수·앱 개수·오픈소스 비율을 세어보자. mark.icons에 type:'oss'가 있는 항목만 필터링하면 "오픈소스 맥 앱 목록"이 나온다. 데이터 소비의 첫걸음.
작은 README.md에 <!--start-->·<!--end--> 마커와 몇 개 항목을 넣고, ast.mjs를 복사해 돌려보자. 마크다운이 JSON으로 바뀌는 순간을 직접 확인하면 "콘텐츠=데이터"가 체감된다.
remark로 README를 파싱해 CONTRIBUTING 규칙 위반을 잡는 CI 린터를 짜보자 — 설명이 한 문장을 넘는 항목, 알파벳 순서가 어긋난 항목, 링크 중복 등을 검출. "문서 품질을 코드로 강제"하는 경험.
feed.mjs의 발상을 흉내 내, 임의 마크다운 리스트에서 최근 커밋으로 새로 추가된 줄만 뽑아 RSS/JSON으로 내보내는 스크립트를 만들어보자. "상태를 산출물에서 파생"하는 무상태 설계를 연습한다.
dist/awesome-mac.json을 데이터로 삼아, 카테고리 사이드바 + 실시간 검색 + "오픈소스만/무료만" 토글이 되는 정적 SPA를 만들어 GitHub Pages에 올려보자. 남의 잘 관리된 데이터셋 위에 자기 UI를 얹는 실전.
| 주차 | 주제 | 핵심 질문 · 자료 |
|---|---|---|
| 1주차 | 마크다운 & AST | remark/unified로 문서를 트리로 파싱하기. mdast 명세, 노드 타입, visitor 패턴. → build/ast.mjs 한 줄씩 읽기. |
| 2주차 | 콘텐츠=데이터 파이프라인 | 단일 원본 → 다중 산출물 설계. 마커 구획, 아이콘→메타데이터 추출, 언어별 분기. → ast.mjs·ES6-IMPORT-GUIDE.md. |
| 3주차 | 정적사이트 · RSS · Docker | SSG(idoc) 설정, 증분 RSS 생성, 초경량 컨테이너. → idoc.yml·feed.mjs·Dockerfile. |
| 4주차 | CI/CD & AI 유지보수 | 릴리스 자동화(태그·체인지로그·provenance), 에이전트 스킬 설계. → ci.yml·.codex/skills/…/SKILL.md. |
먼저 마크다운이 어떻게 트리가 되는지(1주차)를 손에 익혀라. 그게 이 레포의 핵심 지력이다. 그다음 "그 트리를 어떤 산출물로 바꾸나"(2·3주차)가 실용 감각이고, "그 과정을 어떻게 무인화하나"(4주차)가 운영 지혜다. 앱 목록 자체를 외울 필요는 전혀 없다 — 이 레포는 "내용"이 아니라 "내용을 다루는 방법"을 가르치는 교재다.
같은 "Awesome 큐레이션"이라도 접근이 다르다. sindresorhus/awesome는 이 문화의 원조이자 규약의 출발점이고, awesome-mac은 그 위에 데이터화·자동화를 얹었다. 1c7/chinese-independent-developer는 "날짜순 로그 + LLM 자동 PR"이라는 또 다른 자동화를 택했고, awesome-swift-macos-apps(같은 저자)는 Swift 앱에 특화한 자매 리스트다. 이들을 나란히 보면 "리스트를 어떻게 살아있게 유지하는가"의 서로 다른 답이 보인다.
sindresorhus/awesome에서 출발한, 특정 주제의 자료를 엄선해 마크다운으로 정리하는 오픈소스 문화. "엄선"이 핵심이라 기여 규약이 엄격하다.remark-gfm은 표·취소선 같은 GitHub 확장 문법을 이해하게 하는 플러그인.![라벨][참조] 형태 이미지 참조. awesome-mac은 이 배지(OSS/Freeware/App Store 등)를 파싱해 icons[] 메타데이터로 구조화한다.idoc.yml로 설정.npm publish --provenance로 "이 패키지가 어느 CI·커밋에서 빌드됐는지"를 증명하는 공급망 보안 기능. 변조·사칭을 막는다.| 구분 | 링크 / 위치 |
|---|---|
| GitHub 저장소 | github.com/jaywcjlove/awesome-mac |
| TrendShift | trendshift.io/repositories/630 |
| 웹사이트 | jaywcjlove.github.io/awesome-mac (idoc 정적사이트) |
| 핵심 파일 | build/ast.mjs (마크다운 → JSON AST 변환) |
| 핵심 파일 | build/feed.mjs (git 로그 → 증분 RSS) |
| 핵심 파일 | .github/workflows/ci.yml (빌드·배포 파이프라인) |
| 핵심 파일 | .codex/skills/awesome-mac-maintainer/SKILL.md (AI 유지보수 규칙) |
| 핵심 파일 | idoc.yml · Dockerfile · package.json(exports) |
| 이웃 프로젝트 | sindresorhus/awesome(원조) · awesome-swift-macos-apps(자매) · 1c7/chinese-independent-developer |
| 연관 개념 | remark/unified · AST · docs-as-data · SSG · 증분 RSS · npm provenance · Codex 스킬 |