| name | daily-post |
| description | 매일 아침 실행되는 자율 발행 파이프라인. 최신 AI·IT 뉴스에서 토픽 1개를 자동 선정해 저자(namojo) 문체로 블로그 포스트 1편을 작성·팩트체크·발행(git push)까지 완료한다. "데일리 포스트 실행", "오늘의 글 발행", "데일리 자동 발행", "오늘자 포스트 올려줘", "daily post", "자동 발행 한 번 돌려줘", "데일리 파이프라인 테스트" 같은 요청이나 스케줄된 자동 실행이면 반드시 이 스킬을 사용할 것. 사용자가 토픽·날짜를 구체적으로 지정하는 일반 포스트 요청은 blog-factory 스킬이 담당한다. |
Daily Post — 매일 아침 자율 발행 파이프라인
목적
사람의 개입 없이 하루 1편, 최신 AI·IT 뉴스 평론을 저자의 문체로 발행한다. 이 스킬은 완전 자율 모드로 설계되었다: 질문할 사용자가 없다는 전제로, 모든 판단 기준을 이 문서 안에서 해결한다. 판단이 막히면 "발행하지 않는 것"이 기본값이다 — 공개 블로그에 잘못된 글이 올라가는 것이 하루 결호보다 훨씬 나쁘다.
실행 컨텍스트
- 주 실행 환경: 클라우드 스케줄 에이전트. 레포
namojo/namojo.github.io의 최신 main에서 실행된다. push가 곧 발행이다 (GitHub Actions가 main push 시 빌드·배포).
- 로컬 수동 실행도 지원: 사용자가 "데일리 포스트 한 번 돌려줘"라고 하면 로컬에서도 같은 파이프라인을 수행한다. 로컬 실행 시 작업 디렉토리가
myblog라면 산출물을 namojo.github.io 레포로 복사 후 push해야 발행된다 (아래 "로컬 실행 시 동기화" 참조).
- 에이전트 위임:
.claude/agents/의 news-curator, ghostwriter, fact-checker 정의를 사용한다. Agent 도구로 위임하는 것이 기본이며, 서브 에이전트를 쓸 수 없는 환경이면 각 정의 파일을 직접 읽고 그 역할·원칙을 그대로 따라 순차 수행한다. 역할 정의를 건너뛰고 즉흥적으로 쓰면 문체·팩트 규율이 무너진다.
절대 규칙
- 하루 1편. 오늘 날짜(KST)의
_posts/YYYY-MM-DD-*.md가 이미 존재하면 아무것도 하지 않고 종료한다 (중복 실행 방지 게이트).
- 기존 포스트를 절대 수정·삭제하지 않는다. 이 파이프라인은 파일 1개를 추가할 뿐이다.
public/posts.json을 직접 편집하지 않는다. CI의 npm run build가 _posts/*.md에서 전량 재생성한다. 소스 오브 트루스는 _posts/다.
- 팩트체크를 통과하지 못한 글은 push하지 않는다. 부분 성공은 없다 — 발행 아니면 중단.
- 날짜는 반드시 KST 기준. 클라우드 환경은 UTC일 수 있으므로
TZ=Asia/Seoul date +%F로 오늘 날짜를 얻는다. 시점 규율(글 속 "오늘", "이번 주")도 이 날짜 기준.
Phase 0: 게이트 및 준비
git pull (이미 최신 클론이어도 안전). 사용자가 라이브 Editor로 직접 발행한 글이 원격에만 있을 수 있으므로, 원격이 항상 우선이다.
TZ=Asia/Seoul date +%F로 오늘 날짜 확보. _posts/에 오늘 날짜 파일이 있으면 즉시 종료하고 "오늘자 포스트가 이미 존재해 건너뜀"을 보고.
- 다음 파일을 읽는다:
_style/style-guide.md(문체), _style/topics-written.md(중복 방지), _style/ai-timeline.md(시점 규율), 최근 _posts/ 파일명 10개(최근 다룬 주제 감각).
Phase 1: 토픽 선정 (news-curator 역할)
최근 24~48시간의 뉴스에서 정확히 1개 토픽을 고른다.
- 웹 검색으로 후보를 수집한다. 우선순위:
- 1순위 — AI 업계: 모델 출시, 연구소·빅테크 AI 전략, AI 정책·규제, AI 제품·시장
- 2순위 — IT 확장: 그날 AI 뉴스가 약하면 반도체, 빅테크 일반, 개발자 도구, 플랫폼·보안 등 IT 전반으로 넓힌다. "약하다"의 기준: 후보 중 어떤 것도 '엔지니어 독자가 일주일 뒤에도 기억할 사건'이 아니면 약한 날이다.
_style/topics-written.md와 대조해 이미 다룬 토픽·같은 사건의 재탕을 제외한다. 같은 회사라도 새로운 사건이면 허용.
- 선정 기준: (a) 팩트가 복수 출처로 교차 확인 가능, (b) 저자의 평론 각도가 나올 수 있는 사건(단순 스펙 나열 뉴스 제외), (c) 한국 엔지니어 독자와의 접점.
- 팩트 카드를
_workspace/daily/YYYY-MM-DD-brief.md에 작성: 날짜, 주체, 핵심 숫자, 출처 URL 2개 이상, 맥락, 평론 각도 제안. 출처 URL은 팩트체크 단계가 재검증에 사용하므로 반드시 남긴다.
Phase 2: 작성 (ghostwriter 역할)
_style/style-guide.md와 팩트 카드만을 재료로 _posts/YYYY-MM-DD-{slug}.md를 작성한다.
프런트매터 규격 (기존 포스트와 동일해야 렌더링이 깨지지 않는다):
---
layout: post
title: '제목 — 본문에 "가 들어가면 반드시 작은따옴표로 감싼다'
date: YYYY-MM-DD 09:00:00 +0900
categories: [ai-news]
tags: [태그3~6개, 한국어]
excerpt: "2~3문장 요약. 본문 첫 문단과 겹치지 않게."
coverImage: ""
category: "AI"
---
- 제목에
"가 포함되면 작은따옴표로 감싼다 (build_posts_json.py 파서 제약).
coverImage는 빈 문자열("")로 둔다. 커버는 아래 "커버 생성" 단계에서 public/images/covers/{slug}.jpg로 만들고, build_posts_json.py가 파일명 매칭으로 자동 연결한다. 생성이 실패해도 빌드가 hero-home.jpg로 폴백하므로 발행은 막지 않는다.
- 본문은 기존 포스트 분량(공백 포함 2,500~4,000자) 수준. 소제목은
### ▸ 프리픽스 관례를 따른다.
- 표기 규칙 (스타일 가이드 6절, 2026-07 저자 지시): 영문 병기는
한글(영어) 괄호 형식만(붙여쓰기 반이중half-duplex 금지). 널리 알려진 고유명사·제품명은 영어 단독(OpenAI, ChatGPT, Advanced Voice Mode, Agora — 억지 음차 병기 금지). 불필요하면 병기하지 않는다. 의성어·추임새에 영어 병기 금지("음", "네" — "음mhmm", 흠(Hmmm) 금지). 문장은 간결하게, 이미 설명한 맥락을 반복하지 않는다.
- 인라인 이미지는 넣지 않는다. 데일리 모드는 AI 이미지 생성 수단이 없다. 커버(자동 생성)만으로 충분하다.
커버 생성 (Phase 2 필수 단계) — scripts/generate-cover.mjs:
초고 파일을 저장한 뒤 반드시 다음을 실행한다:
node scripts/generate-cover.mjs _posts/YYYY-MM-DD-{slug}.md
- 슬러그의 영문 키워드 + 카테고리 + 날짜 + 브랜드 팔레트(Ink/Warm/Coral)로 글마다 고유한 커버를 결정적으로 렌더한다. 미리 깔린 Chromium(Playwright)으로 1200×630 JPG를
public/images/covers/{slug}.jpg에 저장한다. 외부 네트워크·AI·폰트 의존이 없다(클라우드 환경엔 한글 폰트가 없어 그림 안에 한글 제목을 넣지 않는 설계 — 제목은 카드/페이지의 텍스트로 노출됨).
- 비차단: 스크립트가 실패하거나(exit 2) Chromium이 없으면 커버 없이도 발행을 계속한다. 이 경우 빌드가
hero-home.jpg로 폴백한다. 실행 보고에 "커버 생성 실패, hero 폴백"을 남긴다.
- 생성된
{slug}.jpg는 Phase 4에서 반드시 git add 한다(이 이미지가 안 올라가면 라이브에서 hero로 폴백된다).
예전 범용 커버 풀(public/images/covers/daily/*.jpg)은 폐기하지 않고 비상 폴백 자산으로만 남긴다. 더 이상 기본 경로로 지정하지 않는다.
시점 규율: 오늘 날짜(KST) 시점에서 쓴다. _style/ai-timeline.md보다 미래의 사건을 과거처럼 쓰지 않았는지, 발표 "예정"과 "완료"를 혼동하지 않았는지 ghostwriter의 시점 점검표를 적용한다.
Phase 3: 팩트체크 (fact-checker 역할)
초고의 모든 날짜·수치·인물·발언·제품명을 팩트 카드의 출처 URL + 추가 웹 검색으로 검증하고, 리포트를 _workspace/daily/YYYY-MM-DD-factcheck.md에 남긴다.
- 치명적 오류 (잘못된 날짜, 존재하지 않는 발언·인물, 수치 자릿수 오류, 시점 붕괴) 발견 시: ghostwriter 역할로 돌아가 해당 부분만 수정하고 1회 재검증한다.
- 재검증에서도 치명적 오류가 남으면 발행 중단: 커밋·push 없이 종료하고, 실행 보고에 중단 사유와 팩트체크 리포트 요약을 남긴다. 초고와 리포트는
_workspace/daily/에 있으므로 다음 실행이나 사용자가 회수할 수 있다.
- 경미한 지적(표현 뉘앙스, 부차적 맥락)은 수정만 하고 발행을 막지 않는다.
Phase 4: 발행
팩트체크 통과 시에만 진행한다.
_style/topics-written.md에 오늘 토픽 한 줄 append (날짜, 제목, 슬러그).
- 업계 지형을 바꾸는 굵직한 사건이면
_style/ai-timeline.md의 해당 월에도 한 줄 append (fact-checker의 다음 실행이 이 파일을 기준으로 삼는다).
- 커밋: 신규 파일(
_posts/, _workspace/daily/, 생성된 커버 public/images/covers/{slug}.jpg)과 _style/ 변경만 스테이징한다. git add -A로 무관한 변경을 쓸어 담지 않는다. public/posts.json은 스테이징하지 않는다(CI 재생성).
- 커밋 메시지:
post: {제목} (데일리 자동 발행)
git push. non-fast-forward로 실패하면 git pull --rebase 후 재push. 충돌이 나면 원격 내용을 보존하는 방향으로 해결한다 (원격에만 있는 글은 사용자가 라이브 Editor로 발행한 글이다).
- 실행 보고: 제목, 슬러그, 선정 사유, 팩트체크 결과 요약, 커밋 해시.
로컬 실행 시 동기화
로컬 myblog에서 수동 실행한 경우, 발행하려면 산출물을 ~/Work/namojo.github.io로 옮겨야 한다:
- 먼저
cd ~/Work/namojo.github.io && git pull — 원격 우선.
- 신규 파일만 개별 복사 (
_posts/오늘자.md, _workspace/daily/*, _style/ 변경분). rsync --delete는 절대 사용 금지 — 원격에만 있는 글이 지워진 사고가 두 번 있었다.
- 커밋·push는 Phase 4와 동일.
에러 핸들링
| 상황 | 대응 |
|---|
| 웹 검색 실패·후보 없음 | 1회 재시도 후에도 없으면 발행 없이 종료·보고. 억지로 오래된 뉴스를 신작처럼 쓰지 않는다. |
| 스타일 가이드 파일 없음 | 즉시 중단. 가이드 없이 쓴 글은 저자 글이 아니다. |
| 팩트체크 재실패 | 발행 중단 (Phase 3 참조) |
| push 실패 반복 | pull --rebase 1회 후에도 실패하면 커밋은 로컬 브랜치 daily/YYYY-MM-DD에 남기고 보고 |
| 커버 생성 실패 (Chromium 없음·렌더 오류, exit 2) | 발행을 막지 않는다. coverImage: "" 그대로 두면 빌드가 hero-home.jpg로 폴백. 실행 보고에 "커버 생성 실패, hero 폴백" 명시 |
테스트 시나리오
정상 흐름: 스케줄 실행 → 오늘자 포스트 없음 확인 → 뉴스 검색에서 "OpenAI 신모델 발표" 선정 → 팩트 카드 → 초고 → 팩트체크 통과 → topics-written 갱신 → commit·push → 보고.
중복 게이트: 같은 날 두 번째 실행 → _posts/2026-07-11-*.md 존재 → 즉시 종료, "이미 발행됨" 보고. 커밋 없음.
팩트체크 중단: 초고에 잘못된 발표일 → 1회 수정 → 여전히 출처 불일치 → push 없이 종료, _workspace/daily/에 초고·리포트 보존, 중단 사유 보고.