9 min read

GitHub를 기억으로 쓰는 Content OS 구축기: 스킬, 점수, 자동 발행

관심 주제와 문체, 조사·작성 규칙을 GitHub에 저장하고 ChatGPT·Codex가 매번 읽어 글을 검증·발행하는 Content OS 구조를 설명합니다.

AI에게 “좋은 글을 계속 써 달라”고 요청하는 것만으로는 블로그가 운영되지 않습니다. 대화가 바뀌면 관심 주제와 문체가 사라지고, 이미 쓴 글을 다시 만들거나 출처가 약한 소식을 억지로 발행하기 쉽습니다. Restato Content OS는 이 문제를 해결하기 위해 GitHub를 장기 기억과 운영 규칙의 원본으로 사용하고, ChatGPT·Codex를 실행 엔진으로 분리한 구조입니다.

핵심은 프롬프트를 길게 쓰는 것이 아닙니다. 정책, 기억, 스킬, 후보 상태를 저장소의 파일로 나누고 모든 실행이 같은 순서로 그 파일을 읽게 만드는 것입니다.

GitHub 저장소
├─ 정책과 워크플로
├─ 관심 주제와 발행 기록
├─ 역할별 SKILL.md
├─ 콘텐츠 후보와 점수
└─ 실제 MDX 글


ChatGPT / Codex
조사 → 기획 → 작성 → 검토 → 커밋


GitHub Pages

이 글에서는 실제 restato/restato.github.io 저장소에 구성한 파일과 판단 규칙을 기준으로 설명합니다. 이전의 자동 개발 블로그 생성기가 한 번의 대화에서 글을 만드는 명령이었다면, Content OS는 무엇을 쓸지, 왜 지금 써야 하는지, 기존 글을 고칠지 새로 만들지까지 관리하는 운영 계층입니다.

GitHub를 데이터베이스가 아니라 운영 원본으로 선택한 이유

콘텐츠 운영 데이터는 복잡한 트랜잭션보다 변경 이력과 사람이 읽을 수 있는 구조가 더 중요했습니다.

GitHub에 두면 다음 장점이 있습니다.

  • 정책 변경과 발행 기록이 커밋으로 남습니다.
  • ChatGPT, Codex, Claude Code가 같은 파일을 읽을 수 있습니다.
  • 문체와 관심 주제를 코드 리뷰하듯 수정할 수 있습니다.
  • 글과 운영 규칙이 같은 저장소에서 함께 버전 관리됩니다.
  • 특정 AI 제품에 기억을 종속하지 않습니다.

반대로 모든 것을 하나의 거대한 프롬프트에 넣으면 어떤 규칙이 바뀌었는지 추적하기 어렵고, 매 실행마다 필요 없는 문맥까지 전달하게 됩니다. 그래서 Content OS는 역할에 따라 파일을 작게 나눴습니다.

1. 정책은 모든 에이전트보다 위에 둡니다

최상위 규칙은 .agents/CONTENT_POLICY.md에 있습니다.

# Restato Content Policy

- 사실과 공식 출처를 우선한다.
- 직접 확인하지 않은 경험과 수치를 만들지 않는다.
- 기존 글과 검색 의도가 같으면 업데이트를 우선한다.
- 출처가 약하거나 주제가 빈약하면 발행하지 않는다.
- 독자가 적용할 코드, 절차, 판단 기준을 제공한다.

이 파일은 작성 스타일보다 먼저 적용됩니다. 문장이 자연스럽고 SEO 점수가 높아도 사실 오류가 있거나 새 정보가 없으면 발행할 수 없습니다.

실제 운영에서는 점수보다 금지 조건이 중요합니다.

95점 + 사실 오류       → 발행 금지
90점 + MDX 빌드 실패   → 발행 금지
82점 + 사용자 직접 요청 → 즉시 조사, 품질 검토 후 발행 가능

사용자가 직접 지정한 주제는 우선 처리하지만, 사실 검증까지 생략한다는 뜻은 아닙니다.

2. WORKFLOW.md는 역할의 실행 순서를 고정합니다

.agents/WORKFLOW.md에는 다섯 가지 실행 모드가 있습니다.

모드사용하는 상황
On-demand사용자가 특정 주제를 바로 요청
Trend watch공식 발표와 릴리스를 주기적으로 확인
Project log실제 커밋과 구현에서 개발기 추출
Evergreen장기 검색 가치가 있는 실용 가이드
Digest개별 글로 약한 소식을 하나의 정리 글로 결합

실행 파이프라인은 다음과 같습니다.

trend-finder
→ researcher
→ planner
→ writer
→ seo review
→ reviewer
→ publisher
→ memory update

각 단계의 출력이 다음 단계의 입력이 됩니다. 조사와 작성을 한 번에 처리하지 않는 이유는, 글을 쓰기 시작한 뒤에는 처음 선택한 결론을 정당화하려는 방향으로 흐르기 쉽기 때문입니다.

먼저 근거와 공백을 결정하고, 그다음에 글의 구조를 만듭니다.

3. memory는 대화 기억 대신 저장소에 남깁니다

장기 기억은 .agents/memory/ 아래의 Markdown 파일로 관리합니다.

.agents/memory/
├─ topics.md      # 관심 주제와 우선순위
├─ published.md   # 발행한 글과 핵심 가치
├─ ideas.md       # 조사 중이거나 보류한 후보
├─ keywords.md    # 검색 의도와 기존 글 연결
└─ style.md       # 문체와 금지 표현

topics.md

관심 분야를 Priority A와 B로 나눕니다.

## Priority A
- OpenAI API, Codex, Agents SDK
- Claude Code, Anthropic API, MCP
- Gemini CLI, Google AI
- AI 코딩 에이전트와 개발 자동화

단순 키워드 목록만 저장하지 않고 관찰 조건도 둡니다.

  • 새 버전
  • 호환성 변화
  • 가격과 제한 변경
  • 개발 흐름을 바꾸는 기능
  • 보안 또는 폐기 공지

이 조건이 없으면 매일 비슷한 홍보 소식을 후보로 만들게 됩니다.

published.md

발행 기록은 제목만 저장하지 않습니다.

## 2026-07-19 — GPT-5.6 선택 가이드
- type: new
- slug: /blog/example/
- file: src/content/blog/example.mdx
- topics: [OpenAI API, AI Agent]
- sources: [official source]
- commit: SHA
- notes: 기존 글과 다른 핵심 가치

notes가 중요한 이유는 제목이 달라도 검색 의도와 결론이 같은 글을 찾기 위해서입니다. “신모델 소개”와 “신모델 선택 가이드”는 제목은 다르지만 내용이 겹칠 수 있습니다.

ideas.md

발행하지 않은 후보도 버리지 않습니다.

## 아이디어 제목
- status: new | researching | ready | hold | rejected | published
- source:
- why-now:
- target-reader:
- search-intent:
- update-existing:
- notes:

근거가 부족한 후보는 hold로 남기고, 이후 공식 문서나 실제 구현이 생겼을 때 다시 평가합니다. 매번 처음부터 아이디어를 찾는 비용을 줄일 수 있습니다.

4. 스킬은 직업 설명이 아니라 체크 가능한 절차입니다

.agents/skills/*/SKILL.md는 에이전트 이름만 나누는 용도가 아닙니다. 각 역할이 어떤 입력을 보고 무엇을 출력해야 하는지 정의합니다.

trend-finder

관심 주제에서 후보를 찾고 다음 값을 기록합니다.

topic: ""
why_now: ""
target_reader: ""
new_information: ""
evidence: []
recommended_format: new | update | digest

단순 홍보, 출처 불명, 실질 변화가 없는 소식은 이 단계에서 제거합니다.

researcher

공식 문서, 릴리스 노트, 원본 저장소와 실제 코드를 우선 조사합니다. 확인하지 못한 성능 수치나 경험은 연구 노트에서 제거합니다.

gap-finder

검색 결과가 이미 답하는 내용과 답하지 못하는 내용을 비교합니다.

설치법은 많지만 운영 사례가 없음
기능 소개는 많지만 마이그레이션 절차가 없음
성공 사례는 많지만 실패 조건이 없음
예제는 있지만 테스트·배포·비용이 없음

“한국어 글이 적다”는 이유만으로는 발행하지 않습니다. 실행 가능한 예제나 비교 기준이 있어야 합니다.

scoring-engine

후보를 100점 기준으로 평가합니다.

항목배점
시의성15
독자 가치20
블로그 적합도15
독창성15
검색 지속성10
실증 가능성15
콘텐츠 공백10

자동 탐색 후보의 기본 발행 기준은 85점입니다.

90~100  우선 발행
85~89   발행 가능
70~84   보류하고 근거 수집
0~69    제외

공식 출처가 없으면 30점을 감점하고, 기존 글과 검색 의도가 같으면 25점을 감점합니다. 확인하지 않은 성능과 비용을 단정하면 점수와 관계없이 발행할 수 없습니다.

one-click-publish

사용자가 “이 주제로 글 써서 올려”라고 요청했을 때 전체 파이프라인을 한 번에 실행합니다. 사용자가 주제를 지정했으므로 85점 임계값은 적용하지 않지만, 중복 검사와 사실 검증은 그대로 진행합니다.

5. 후보 상태는 JSON으로 대시보드와 공유합니다

에이전트가 판단한 결과는 src/data/contentCandidates.json에 저장합니다.

{
  "updatedAt": "2026-07-20T09:00:00+09:00",
  "threshold": 85,
  "candidates": [
    {
      "id": "ai-sdk-7-production-agent-guide",
      "title": "AI SDK 7 프로덕션 에이전트 가이드",
      "score": 93,
      "status": "published",
      "action": "new-post"
    }
  ]
}

src/pages/content-os.astro는 이 JSON을 읽어 후보 수, 발행 기준, 점수와 상태를 보여줍니다.

---
import candidateData from '../data/contentCandidates.json';

const candidates = [...candidateData.candidates]
  .sort((a, b) => b.score - a.score);
---

{candidates.map((candidate) => (
  <article>
    <h3>{candidate.title}</h3>
    <p>{candidate.reason}</p>
    <strong>{candidate.score}</strong>
  </article>
))}

대시보드는 실행 엔진이 아닙니다. 현재 구조에서는 GitHub가 상태를 저장하고 ChatGPT·Codex의 요청 또는 예약 실행이 파일을 갱신합니다. 브라우저에서 직접 OpenAI API를 호출하지 않으므로 API 키를 정적 사이트에 노출할 위험도 없습니다.

6. 실제 실행은 두 가지 경로로 나눕니다

즉시 발행

사용자가 주제를 직접 지정합니다.

"AI SDK 7 글 써서 올려"
"최근 커밋으로 개발일지 작성해"
"기존 Claude Code 글 업데이트해"

실행기는 저장소의 정책, memory, 모든 스킬을 먼저 읽고 조사부터 커밋까지 처리합니다.

자동 탐색

예약 실행은 관심 주제의 공식 발표를 확인합니다.

공식 발표 확인
→ 기존 글 검색
→ 콘텐츠 공백 분석
→ 점수 계산
→ 85점 이상만 작성
→ 검토와 스키마 확인
→ GitHub 커밋
→ memory 갱신

새로운 정보가 없으면 글을 만들지 않습니다. 자동화의 성공 기준은 매일 한 편을 발행하는 것이 아니라, 근거 없는 글을 만들지 않는 것입니다.

7. 발행에서 가장 자주 깨지는 부분은 글이 아니라 스키마입니다

Content OS를 만들면서 확인한 중요한 문제는 작성 스킬의 예시와 실제 Astro 컬렉션 스키마가 달라질 수 있다는 점입니다.

현재 저장소의 src/content/config.ts는 다음 필드를 요구합니다.

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.date(),
    tags: z.array(z.string()).default([]),
    image: z.string().optional(),
    draft: z.boolean().default(false),
  }),
});

스킬 문서에 pubDate 예시가 남아 있어도 실제 config.tsdate가 우선입니다. 그래서 publisher 단계에서는 항상 다음 순서를 따릅니다.

  1. src/content/config.ts 읽기
  2. 기존 최신 MDX의 frontmatter 확인
  3. 새 파일의 필수 필드 검증
  4. 내부 링크와 MDX 특수 문법 확인
  5. 가능한 환경에서 npm run build 실행

AI가 글을 잘 써도 frontmatter 필드 하나가 틀리면 전체 배포가 실패합니다. 콘텐츠 자동화에서 빌드 검증은 문법 검사 이상의 발행 권한입니다.

8. 점수만 자동화하면 안 되는 이유

점수 시스템은 일관된 판단을 돕지만 진실을 보장하지 않습니다.

예를 들어 최신 발표는 시의성에서 높은 점수를 받을 수 있습니다. 하지만 공식 문서에 구체적인 API가 없고 기존 글과 차이가 없다면 독창성과 실증 가능성 점수가 낮아져야 합니다.

topic: "작은 UI 변경 공지"
score: 62
decision: reject
reason: "최신 발표지만 개발자의 의사결정을 바꾸지 않고 독립 글로 제공할 실습이 없음"

반대로 3주 전 발표라도 마이그레이션 코드, 운영 체크리스트, 실패 조건을 제공할 수 있다면 90점 이상이 될 수 있습니다. 날짜만 최신인 뉴스보다 실제로 적용할 수 있는 가이드를 우선합니다.

9. 현재 구조의 제한도 남아 있습니다

Content OS가 완성된 CMS는 아닙니다.

  • 대시보드는 읽기 전용입니다.
  • GitHub 커넥터 환경에서는 로컬 빌드를 직접 실행하지 못할 수 있습니다.
  • 실제 검색량과 Search Console 성과는 아직 점수에 반영하지 않습니다.
  • 여러 실행기가 동시에 같은 memory 파일을 수정하면 충돌할 수 있습니다.
  • 스킬 문서와 실제 코드 스키마가 달라질 수 있습니다.

다음 개선은 이 제한을 줄이는 방향입니다.

  1. GitHub Actions의 빌드 결과를 발행 상태와 연결
  2. Search Console 데이터로 기존 글 업데이트 후보 추천
  3. 후보 JSON에 조사 출처와 리뷰 결과 저장
  4. 여러 파일을 하나의 원자적 커밋으로 갱신
  5. 오래된 스킬과 실제 스키마의 차이를 자동 검사

다른 프로젝트에 적용하는 최소 구성

처음부터 모든 역할을 만들 필요는 없습니다. 아래 여섯 파일로 시작할 수 있습니다.

.agents/
├─ CONTENT_POLICY.md
├─ WORKFLOW.md
├─ memory/
│  ├─ topics.md
│  ├─ published.md
│  └─ style.md
└─ skills/
   ├─ researcher/SKILL.md
   └─ writer/SKILL.md

이후 중복 글이 늘면 gap-finder를 추가하고, 자동 발행을 시작할 때 scoring-engine과 후보 저장소를 추가합니다.

좋은 Content OS의 기준은 파일 수가 아닙니다.

  • 새 실행기가 와도 같은 기준으로 판단하는가
  • 이미 쓴 글을 기억하는가
  • 출처가 약하면 발행을 멈추는가
  • 실제 코드 스키마를 확인하는가
  • 모든 변경이 기록으로 남는가

결론

Restato Content OS는 AI가 글을 대신 써 주는 기능보다 AI가 매번 같은 운영 원칙을 읽고, 근거가 있을 때만 행동하게 만드는 구조에 가깝습니다.

GitHub는 관심 주제, 문체, 스킬, 발행 이력을 보존합니다. ChatGPT와 Codex는 그 파일을 읽어 조사와 작성을 수행합니다. Astro와 GitHub Pages는 검증된 MDX를 배포합니다.

프롬프트를 더 길게 만드는 대신 기억과 규칙을 저장소로 옮기면, 모델이나 실행 환경이 바뀌어도 콘텐츠 운영 방식은 유지할 수 있습니다. 자동화의 마지막 단계는 글 생성이 아니라 발행하지 않아야 할 때 멈추는 능력입니다.