Agent 자동화에서 “Runtime은 얇게, Domain Skill은 두껍게”라는 말은 코드 양을 뜻하지 않는다. 실패해도 반드시 지켜야 하는 실행 제약은 Runtime에 두고, 업무별로 바뀌는 절차와 산출물 기준은 Skill에 둔다는 경계다. 이 글에서는 그 경계를 이 저장소의 자동 초안 파이프라인에 대입해 확인한다.
Runtime과 Skill을 나누는 기준
여기서 Runtime은 오케스트레이션을 실행하고 작업 사이 상태를 관리하는 코드다. 반면 Skill은 반복 가능한 워크플로를 가르치는 지침과 자료의 묶음이다. 도구 서버를 함께 쓴다면 서버가 데이터·인증·권한·실행을 제공하고, Skill은 도구 호출 순서와 불완전한 결과 처리법, 최종 산출물 형식을 설명한다.
경계가 애매할 때는 실패 결과로 판정한다.
| 실패했을 때 깨지는 것 | 둘 위치 | 예 |
|---|---|---|
| 실행 횟수·저장 상태·권한·감사 기록 | Runtime | 재시도 상한, 파일 쓰기, 승인 여부 |
| 업무 문서의 내용과 검토 방식 | Skill | 필수 절, 용어, 확인 순서, 출력 템플릿 |
| 외부 시스템의 실제 데이터와 동작 | 도구 또는 MCP 서버 | 조회, 수정, 인증된 API 호출 |
“중요한 것은 Runtime” 또는 “자주 바뀌면 Skill”만으로는 부족하다. 업무 지침이라도 위반 시 권한이 뚫린다면 Runtime에서 강제해야 하고, 시스템 설정처럼 보여도 산출물 표현 규칙이라면 Skill에서 관리할 수 있다.
이 저장소에서 Runtime이 맡는 부분
scripts/auto_post.py의 generate_blog_post()는 생성 모델의 판단과 별개로 실행 경계를 소유한다. 최대 시도 횟수를 세고, 각 결과에 결정적 게이트를 적용하며, 검수 실패를 기록하고, 모든 검사를 통과한 결과만 content/에 쓴다. .github/workflows/auto_post.yml은 예약 실행의 공개 상태와 커밋 대상을 정한다.
여기서 Runtime 책임은 다음처럼 확인할 수 있다.
MAX_ATTEMPTS를 넘겨 계속 생성하지 않는다.- 프론트매터·분량·소제목·인용 검사를 코드로 강제한다.
- 반려 사유와 본문 해시를
rejections.jsonl에 남긴다. - 최근 반려 본문은 12개만 진단용으로 보존한다.
- 예약 실행 결과는
draft: true로 저장한다.
모델이 “이번 글은 좋으니 예외로 저장하자”고 판단해도 이 경계를 우회할 수 없다. 이것이 이 저장소에서 말하는 강한 Runtime이다.
Domain Skill에 넣을 내용
Agent Skills 공개 사양의 기본 단위는 SKILL.md가 있는 디렉터리다. 파일의 frontmatter에는 이름과 설명을 두고, 본문에는 지침을 쓴다. 필요하면 별도 참조·스크립트·자산을 함께 둘 수 있다. 따라서 Domain Skill을 긴 프롬프트 하나로 취급할 이유가 없다.
- 어떤 요청에서 이 Skill을 불러야 하는지 설명하는 메타데이터
- 입력에서 먼저 확인할 필드와 누락 시 중단 조건
- 도구를 호출하는 순서와 각 호출의 합격 기준
- 좋은 산출물과 반려 산출물의 짧은 예시
- 조직 용어집, 검토 체크리스트, 문서 템플릿
- 실패했을 때 재시도할 항목과 사람에게 넘길 항목
이 저장소에는 아직 이 구조의 실제 Domain Skill이 없다. verification_contract()로 주제마다 실행 명령·관측 대상·합격 조건을 묶은 부분이 가장 가까운 사례일 뿐이다. 따라서 현재 코드를 “Skill 기반 아키텍처가 구현됐다”고 설명하면 과장이다.
검증 계약이 두 층을 연결한다
Runtime과 Skill을 나눠도 둘 사이 계약이 없으면 검증할 수 없다. 이 저장소의 주제 계약은 세 값을 요구한다.
command: 독자가 실제로 실행할 명령
observe: 명령 뒤 확인할 값이나 파일
pass: 통과와 실패를 가르는 조건Skill은 이 계약을 사용해 글의 재현 절차를 작성할 수 있다. Runtime은 결과 글에 재현 절이 있는지, 실행 항목이 충분한지, 공식 출처가 있는지를 검사한다. 다만 Runtime은 명령이 정말 주제의 핵심을 검증하는지까지 완전히 판단하지 못한다. 10월 예약 실행에서 형식 게이트를 넘은 글도 “파일을 열어 확인하라” 수준의 절차 때문에 AI 검수에서 반려된 것이 그 차이다.
저장소에서 직접 점검하는 순서
다음 명령은 책임 분리가 실제 코드에 존재하는지 확인한다.
rg -n "MAX_ATTEMPTS|validate_content_structure|record_rejection|keep_rejected_draft" scripts/auto_post.py
rg -n "AUTO_POST_DRAFT|git add content" .github/workflows/auto_post.yml
rg -n "verification_contract|command|observe|pass" scripts/auto_post.py scripts/test_auto_post.py
python -X utf8 -u scripts/test_auto_post.py판정 기준은 네 가지다.
- 시도 상한과 저장 조건이 모델 응답 밖의 코드에 있어야 한다.
- 워크플로가 예약 실행을 비공개 초안으로 강제해야 한다.
- 주제 계약에서 실행 명령·관측 대상·합격 조건을 복구할 수 있어야 한다.
- 회귀 테스트가 모두 통과하고 실제 반려 로그는 변경되지 않아야 한다.
예약 실행의 공개 상태와 커밋 조건은 GitHub Actions 워크플로 문법과 대조할 수 있다. Skill 파일 구조는 앞의 Agent Skills 공개 사양을 기준으로 확인한다.
변경과 버전 관리 원칙
둘을 나누면 변경 검토도 달라진다. Runtime 변경은 저장·권한·재시도·공개 상태 회귀 테스트를 먼저 본다. Skill 변경은 같은 입력 묶음으로 산출물 구조와 검토 결과가 어떻게 달라지는지 비교한다. 어느 쪽이든 실행 결과에 코드 커밋과 Skill 버전을 함께 기록해야 나중에 실패를 재현할 수 있다.
- Runtime 변경: 상태 전이, 중복 실행, 실패 복구를 시험한다.
- Skill 변경: 대표 입력, 경계 입력, 반려 예시로 평가한다.
- 도구 변경: 권한 범위와 실제 부작용을 별도로 확인한다.
- 계약 변경: 명령·관측값·합격 조건을 한 묶음으로 갱신한다.
이 구분이 통하지 않는 조건과 한계
Runtime과 Skill의 경계만으로 자동화가 안전해지지는 않는다. Skill 지침은 모델이 해석하므로 권한 검사나 공개 승인 같은 강제 조건을 대신할 수 없다. 반대로 모든 도메인 규칙을 코드 게이트로 옮기면 표현만 다른 정상 결과까지 막을 수 있다. 이 저장소에서도 구조 게이트는 재현 절의 존재를 찾지만, 그 절차가 주제를 실제로 검증하는지는 별도 검수가 필요하다.
또한 이 글의 저장소 사례는 단일 Python 프로세스와 GitHub Actions를 사용한다. 큐, 트랜잭션, 장기 실행 상태 머신을 구현한 사례가 아니므로 그런 시스템의 일관성까지 입증하지 않는다. 여기서 확인한 결론은 제한적이다. 강제해야 할 실행 불변식은 Runtime 코드와 테스트에 두고, 반복 가능한 업무 절차는 Skill로 만들되, 둘 사이에 실행 가능한 검증 계약을 둬야 한다.