RicoCheese기술 뉴스와 기록
목록으로
뉴스PUBLISHED · 2026년 9월 1일·15 MIN READ

발행 과정을 통째로 스킬로 만들었다 — Claude Code publishing-kit

마크다운 한 파일로 dev.to, AWS Builder Center, Medium, LinkedIn 네 곳의 원고를 만들고 검증까지 하는 Claude Code 스킬. 만든 사람은 이 스킬로 이 글 자체를 발행했다.

#claudecode#writing#devtools#ai
Streamline Publishing with a Claude Code Skill

개요 #

기술 글 하나를 네 곳에 올리려면 손이 꽤 많이 간다. 플랫폼마다 요구하는 커버 이미지 크기가 다르고, Medium은 표를 제대로 못 받아서 이미지로 바꿔 넣어야 하고, AWS Builder Center는 이모지를 싫어한다. API가 없는 편집기에는 긴 마크다운을 사람이 직접 붙여넣어야 한다. 그러다 보면 조금씩 다른 파일이 네 개 생기고, 어느 게 최신인지 알 수 없게 된다.

xbill이 공개한 publishing-kit 은 이 과정 전체를 Claude Code 스킬 하나와 작은 스크립트 묶음으로 정리했다. 원고 파일 하나를 쓰고 Claude에게 "발행해줘"라고 말하면 나머지가 굴러간다.

눈에 띄는 대목은 따로 있다. 이 글 자체, 그리고 이 글의 커버 이미지와 네 플랫폼 원고 전부가 이 스킬로 만들어졌다. 개발자들이 말하는 도그푸딩을 글까지 끌고 간 셈이다.

스킬이 실제로 하는 일 #

스킬은 Claude에게 발행 절차를 가르치고, 언어 모델이 손으로 하면 안 되는 작업은 스크립트가 맡는다.

원고 네 벌을 자동으로 파생시킨다 #

소스 파일 하나에서 dev.to용 마크다운, 이모지를 걷어내고 AWS 고지 문구를 붙인 Builder Center용 원고, 표를 전부 PNG로 렌더링한 Medium용 HTML, 그리고 LinkedIn 게시글이 나온다. 각각 make-builder.py, make-medium.py, make-linkedin.py가 담당한다.

여러 권의 책이 진열된 모습 Photo by Ian Ramírez on Pexels

커버는 한 번만 만든다 #

make-cover.py --flow --sizes devto,builder 를 실행하면 파이프라인을 일러스트로 그려서 플랫폼별 요구 크기로 전부 뽑아낸다. 파일 이름은 바이트 해시로 정한다. 재미있는 건 마지막 출력이다. 320px짜리 피드 카드에서 어떤 글자 크기가 살아남는지 알려준다. 커버가 실제로 사람 눈에 닿는 크기가 그 정도인데, 라벨이 작은 다이어그램은 거기서 뭉개진다.

숫자마다 근거를 요구한다 #

check-facts.py는 원고에서 가격, 측정값, 버전 같은 숫자를 뽑아낸 뒤 근거 파일에 없는 것들을 지목한다. 그 숫자가 맞는지는 판단하지 않는다. 어떤 숫자를 기억에만 의존해 쓰고 있는지 알려줄 뿐이다. 작성자는 근거 없는 숫자가 나오는 경로를 셋으로 나눈다. 측정은 했지만 저장을 안 했거나, 계산 결과인데 계산이라고 표시를 안 했거나, 기억으로 썼거나. 그리고 틀리는 건 늘 세 번째다.

발행 직전 점검 #

preflight.py --live가 전부 돌리고 실패하면 종료 코드로 알린다. 커버가 커밋됐고 HEAD와 일치하는지, 크기가 맞는지, 프론트매터가 빠짐없는지, 문단이 하드랩되지 않았는지 본다. 마지막으로 이미 발행된 URL을 실제로 받아와 디스크의 파일과 바이트 단위로 비교한다.

API가 있는 곳은 스크립트가, 없는 곳은 브라우저가 #

dev.to는 publish-devto.py --create로 끝난다. 프론트매터를 그대로 페이로드로 쓰기 때문에 제목, 태그, 커버가 본문과 함께 넘어가고, --org-slug를 주면 커뮤니티 채널로 라우팅된다. 브라우저를 열 일이 없다.

AWS Builder Center와 Medium은 API가 없어서 Chrome을 써야 한다. 스킬은 그 경로까지 알고 있다. window.name으로 페이로드를 넘기고, 양쪽에서 체크섬을 맞추고, 붙여넣기 전에 편집기가 비어 있는지 확인하고, 붙여넣은 뒤에는 랜드마크 개수를 센다.

발행하고 나서야 알게 되는 것들 #

스킬에는 문서에 안 적힌 함정들이 코드로 박혀 있다. 대체로 하루 늦게 깨닫는 종류다.

  • dev.to는 마크다운을 하드 브레이크 켜진 상태로 렌더링한다. 95컬럼으로 줄바꿈한 원고를 올리면 문단마다 엉뚱한 줄바꿈이 생긴다.
  • dev.to는 커버를 직접 호스팅하지 않고 2.381:1 비율로 프록시한다. 1376x768 커버는 위아래로 95px씩 잘려 나간다.
  • Medium은 붙여넣기 과정에서 data: URI 이미지를 버린다. 자체 완결형으로 빌드한 원고는 그림이 하나도 없이 도착한다.
  • LinkedIn Posts API는 초안을 만들 수 없다. 생성 시점에 받는 상태값이 PUBLISHED 하나뿐이다.

책이 진열된 도서전 테이블 Photo by Asad Photo Maldives on Pexels

설치 #

플러그인 마켓플레이스가 가장 빠르다.

untitled
shell
/plugin marketplace add xbill9/publishing-kit
/plugin install publishing@publishing-kit

클론해서 심볼릭 링크를 거는 방식도 된다.

untitled
bash
git clone https://github.com/xbill9/publishing-kit
ln -s "$PWD/publishing-kit/skills/publishing" ~/.claude/skills/publishing

준비물은 세 가지다. 커버와 표 렌더링에 쓸 Pillow가 설치된 Python 3, ~/.devto.key에 넣어둔 dev.to API 키, 그리고 아티클 디렉터리를 담을 공개 저장소. 커버와 Medium 이미지 모두 페이지가 그려질 때 URL로 가져오기 때문에 푸시하지 않으면 깨진다.

스크립트를 직접 실행할 일은 별로 없다. Claude가 대신 돌리고, SKILL.md에 스크립트 위치가 적혀 있다. 손으로 실행하고 싶을 때는 설치 방식에 따라 경로가 달라지므로 skill-footprint.py --where로 스킬 디렉터리를 물어보는 편이 낫다. 클론이면 skills/publishing이고, 마켓플레이스 설치면 버전 번호가 붙은 캐시 경로 아래에 있다. 적어둔 경로가 업그레이드 한 번에 무효가 된다는 뜻이다.

스킬 자체를 고쳐가며 쓸 생각이라면 이 버전 번호를 더 신경 써야 한다. 설치는 스냅샷을 뜨는 동작이고 claude plugin update는 버전 문자열을 비교하기 때문에, 같은 버전에서 수정한 내용은 세션에 절대 반영되지 않는다. 작업 중에는 심볼릭 링크를 쓰라는 게 작성자의 조언이다.

실제 사용 흐름 #

설치하고 나면 Claude Code에 이렇게 말하면 된다.

"이 벤치마크 글로 정리해서 aws-builders 조직으로 dev.to에 올려줘"

Claude가 원고를 쓰고, 커버를 두 가지 크기로 만들고, 원고의 숫자를 실행 결과물과 대조하고, 프리플라이트를 돌린 뒤 실패한 항목을 알려준다. 통과하면 초안으로 올리고 링크를 준다. 이어서 이렇게 말한다.

"이제 Medium이랑 Builder Center 버전도 만들어줘"

파생 원고를 만들고 표를 이미지로 렌더링한 다음 Chrome을 열어 편집기를 채운다. 모든 목적지에서 초안 상태로 멈추고 링크만 돌려준다. 발행 버튼은 사람이 누른다.

잘못 나갔을 때 되짚는 법 #

작성자가 가장 놀랐다고 말한 부분이자, 스킬의 값어치가 실제로 몰려 있는 절반이다.

페이지가 파일이랑 다르게 보인다. 내가 뭘 푸시했는지 따지지 말고 목적지가 실제로 내보내는 걸 받아온다.

untitled
shell
python3 ../../skills/publishing/scripts/check-links.py article.md
untitled
plaintext
devto-publishing-kit.md  (branch URLs)
  ok    cover.77acc7c4.jpg: HTTP 200, bytes match disk
  ok    img/cover.77acc7c4.jpg: HTTP 200, bytes match disk
  ok    img/devto-publishing-kit-table-1.png: HTTP 200, bytes match disk

여기서 FAIL이 뜨면 "HTTP 200인데 받아온 바이트가 디스크와 다르다"는 뜻이고, 대개 커밋 이후에 이미지를 다시 만든 경우다. 이 킷의 다른 검사는 전부 로컬 상태만 본다. 파일이 있는지, 추적되고 있는지. 그 검사들은 전부 통과하면서도 발행된 URL은 다른 걸 내보내고 있을 수 있다.

문단이 들쭉날쭉하다. check-article.py가 하드랩된 문단과 첫 번째 위치의 줄 번호를 알려준다. publish-devto.py는 내보낼 때 줄바꿈을 풀어주기 때문에 저장소 원본은 95컬럼으로 읽기 좋게 두고 발행된 페이지만 깔끔해진다.

Medium에서 이미지가 안 보인다. -embed.html을 붙여넣은 것이다. 실제 URL을 참조하는 -hosted.html을 쓰고, 이미지를 먼저 커밋해야 한다.

숫자에 근거가 없다. check-facts.py가 이름을 대준다.

다양한 책이 꽂힌 서점 서가 Photo by Verda Yiğit on Pexels

구조 #

SKILL.md 하나, 목적지별 특이사항을 정리한 레퍼런스 파일들, 그리고 작업 단위마다 스크립트 하나. 스킬은 어느 스크립트를 언제 돌릴지 정하고, 스크립트는 각자 따로 돌려도 되고 무엇을 했는지 찍어준다.

자기 스킬에 가져다 쓸 만한 건 references/house-style.md라고 작성자는 짚는다. 목소리, 섹션 순서, 도입부와 마무리 공식이 그 파일 하나에 모여 있고 SKILL.md나 스크립트는 어느 것도 그 파일에 의존하지 않는다. 그 파일만 바꾸면 킷이 다른 사람 문체로 쓴다.

skill-footprint.py는 스킬 자신의 크기와 토큰 비용을 재고, 이런 글에 들어가는 비용 표와 커버 푸터를 만들어낸다. 커밋마다 바뀌는 숫자를 사람이 손으로 고쳐야 하는 산문에 박아둘 이유가 없다는 것이다.

자기 자신을 먹여본 결과 #

커버 이미지에 박힌 숫자 두 개는 실제 측정값이고, 둘 다 킷을 킷 자신에게 돌려서 찾아낸 것이다.

측정값
dev.to 하드랩 문단발행된 글에서 62개 중 47개에 엉뚱한 줄바꿈이 들어가 있었다
Medium data URI 이미지4개 중 0개가 살아남았다. 실제 URL로 바꾸니 4개 중 4개

첫 번째는 몇 달째 자기 글에서 벌어지던 일이었다. 두 번째는 처음 겪었을 때 글 전체를 다시 만들어야 했다. 둘 다 어느 플랫폼 문서에도 없고, 지금은 둘 다 검사 항목이 됐다.

같은 실행에서 킷 자체의 결함 다섯 개도 드러났다. make-medium.py는 다른 프로젝트의 저장소가 기본 이미지 베이스로 하드코딩돼 있었고, check-article.py는 추적은 되지만 다시 생성된 커버를 통과시켰다. make-cover.py는 하이픈으로 시작하는 --tile 값을 argparse에 뺏겼고, check-facts.py127.0.0.1을 버전 번호로 읽었다. 마지막으로 unwrap()이 인용 블록을 건너뛰는 바람에 이 글의 TL;DR이 다섯 줄로 쪼개져 올라갔는데, 그걸 잡아냈어야 할 검사도 인용 블록을 건너뛰고 있어서 문제없다고 답했다.

링크 #

publishing-kit은 커뮤니티 프로젝트이며 dev.to, Medium, AWS, LinkedIn과 무관하다. 글에 나오는 플랫폼 동작은 2026년 8월 31일 기준 측정값이라고 작성자가 밝혔다.


이 글은 위 출처를 바탕으로 한국 독자를 위해 재작성한 기사입니다. 원문의 사실과 수치에 근거하며, 별도의 견해를 포함하지 않습니다.