1. 배경
Devlime은 개발·스테이지·운영 세 환경으로 운영하고, 이를 관리하는 gitops 저장소는 둘입니다. 어느 환경으로 올리든 배포 앞뒤에는 같은 점검이 붙습니다. 이번에 무엇이 올라가는지, DB 반영 사항이 있는지와 그것이 가이드대로 작성됐는지, 서비스끼리 참조하는 라이브러리 버전이 어긋나지 않았는지, 미커밋·미푸시가 없는지 등을 확인하는 일입니다.
점검이 끝나면 반영 내역을 정리합니다. 스테이지에 올린 직후에는 팀이 확인할 항목과 함께 팀 내부에 공유하고, 테스트와 수정을 거쳐 운영에 배포하면 그동안의 내역을 묶어 사용자에게 공지합니다. 운영 반영은 아직 과도기라 스테이지 설정을 운영 설정으로 확인하며 옮기는 일이 하나 더 있습니다.
이 점검과 정리는 어렵지 않습니다. 대신 항목이 많고, 빠뜨리면 바로 사고가 되고, 배포할 때마다 반복됩니다. VoC에 빠르게 대응하느라 배포가 일 단위가 되면서 이 반복이 매일이 됐습니다. 팀은 이미 Claude Code와 Cowork를 개발에 쓰고 있고 플랫폼팀에는 Vizend agent hub라는 팀 하네스도 있지만, 허브는 개발 맥락을 담는 용도라 배포 점검처럼 사람 없이 돌아야 하는 운영 절차에는 다른 구성이 필요했습니다. 이 절차 자체가 과도기적이라 크게 구축하지 않고 필요한 만큼만 만들기로 했고, 이 글은 그 처음 구성과 고칠 때가 됐다는 신호, 그 뒤의 개선에 대한 것입니다.
그림 1. Devlime 배포 루프. 아래 점선 상자가 AI에게 맡긴 일입니다.
2. 기술 선택 배경
|
계층 |
기능 |
무엇을 하는가 |
공식 문서가 말하는 도입 시점 |
|---|---|---|---|
|
L1 |
CLAUDE.md · rules · 메모리 |
세션 시작 시 자동으로 읽히는 규칙과 맥락 |
같은 규칙을 두 번 이상 틀릴 때 |
|
L2 |
스킬 · MCP · LSP |
절차를 파일로 고정, 외부 시스템을 도구로 연결 |
같은 프롬프트를 세 번째 치고 있을 때 |
|
L3 |
서브에이전트 · 워크플로우 |
부수 작업을 별도 컨텍스트로, 병렬 실행 |
부수 작업이 대화를 출력으로 채울 때 |
|
L4 |
훅 |
도구 호출 전후에 셸 명령으로 강제·검사 |
묻지 않아도 매번 일어나야 할 때 |
|
L5 |
스케줄 (/loop · Desktop 작업 · Cloud Routines) |
사람이 없어도 실행 |
반복 점검이 정기화됐을 때 |
|
L6 |
플러그인 · 마켓플레이스 · 관리 설정 |
구성 요소를 묶어 배포·버전 관리 |
두 번째 저장소가 같은 설정을 필요로 할 때 |
|
L7 |
validate · eval |
스킬이 발동하는지, 결과가 나아졌는지 측정 |
플러그인을 배포하기 전 |
Claude Code 공식 문서 "Extend Claude Code"와 "Run prompts on a schedule"의 항목을 제가 계층으로 다시 묶은 표입니다. 도입 시점 문구는 문서의 표현을 따랐고, L1~L7 번호는 설명 편의상 제가 붙인 것입니다.
일곱 계층 중 처음에 쓴 것은 L2 스킬과 L5 스케줄 작업 둘입니다. 판단 기준은 셋이었습니다.
첫째, 문서의 도입 시점을 그대로 따랐습니다. 실제로 밟은 트리거가 "같은 절차를 세 번째 설명하고 있다"와 "점검이 배포마다 반복된다" 둘이었습니다. 훅의 트리거인 "매번 강제돼야 하는 규칙"은 절차를 몇 번 돌려 봐야 무엇인지 알 수 있는 것이었습니다.
둘째, 되돌릴 수 없는 행위는 사람이 합니다. 머지·커밋·푸시·태그와 운영 환경 변경은 팀 원칙상 사람이 하므로 "혼자 돌아도 되는 범위"가 자연스럽게 정해졌습니다. 확인, 문서 작성, 커밋 직전까지의 파일 수정입니다.
셋째, 규모에 맞췄습니다. 이 점검을 도는 사람은 지금 저 한 명이고 절차는 과도기적입니다. 한 명이 쓰는 과도기 절차에 플러그인 버전 관리와 평가를 먼저 붙이는 것은 순서가 맞지 않습니다. 대신 나중에 옮길 수 있게 절차를 스킬 파일에 완결되게 적고, 스케줄 프롬프트는 스킬을 호출하는 형태로 두었습니다.
스케줄 방식도 같은 기준으로 골랐습니다. Claude Code 문서가 안내하는 방식은 세 가지이고, 그중 Desktop 스케줄 작업(Cowork)을 골랐습니다.
|
방식 |
실행 위치와 시작 조건 |
이 글의 점검에 맞는지 |
|---|---|---|
|
Cloud Routines |
클라우드에서 저장소를 새로 clone해 실행. cron(최소 1시간), API 호출, GitHub 이벤트로 시작. 권한 프롬프트 없음 |
저장소가 사내 GitLab에 있어 클라우드 세션에 자격 증명이 필요. 지금 단계에서는 하지 않기로 함 |
|
Desktop 스케줄 작업 |
내 PC에 연결된 폴더를 새 세션에 마운트해 실행. 작업별 권한 설정. 시각을 정하거나 사람이 실행 |
선택. 저장소가 이미 PC에 있고, 최신화는 실행 전에 사람이 함 |
|
/loop |
열어 둔 세션 안에서 반복. 세션에 종속 |
"눌러 두고 다른 일을 하는" 점검과 맞지 않음 |
Cloud Routines가 가장 매끈하지만 저희 저장소는 사내 GitLab에 있어 클라우드 세션에 자격 증명을 두어야 하고, 지금 단계에서는 그 구성을 하지 않기로 했습니다. Desktop 작업은 제 PC에 연결된 폴더를 새 세션에 마운트해 실행하고, 저장소 최신화(fetch)는 실행 전에 제가 합니다.
실행 시점을 시각으로 정하지 않은 데는 배포가 정기적이지 않다는 이유도 있습니다. 지금은 일 단위에 가깝고 안정화 후에는 정기 배포에 핫픽스가 섞일 텐데, 어느 쪽이든 시작 조건은 시각이 아니라 "최신화를 마쳤다"는 사건입니다. 그래서 두 작업 모두 cron을 비워 두고 실행 버튼을 사람이 누릅니다.
3. 처음 구성
처음 구성은 스킬 둘과 스케줄 작업 둘입니다.
|
구성 |
내용 |
|---|---|
|
스킬 2개 |
스테이지 반영 전 점검과 반영 내역 정리 하나, 스테이지·운영 gitops 대조와 반영 하나. 각각 마크다운 파일 한 개 |
|
스케줄 작업 2개 |
스킬과 1:1. 시각을 정하지 않고 실행 버튼을 사람이 누름. 새 세션에서 자동 승인으로 돌고 끝나면 알림 |
|
규칙 |
"커밋·푸시·태그는 사람", "확인 못 한 것은 확인 못 함으로". 스킬과 프롬프트 안의 문장 |
|
기억 |
프로젝트 문서. 다음 실행이 이전 공지 문서를 읽어 번호를 채번하고 화면 표기를 재사용 |
스킬 파일에 적은 것은 절차보다 판단 쪽이었습니다. 점검 순서는 어디에나 있지만, 어느 값은 옮기면 안 되는지, 무엇을 번역하지 말고 어디서 찾아야 하는지, 갈릴 때 어떻게 낼지는 저희 환경에서만 통하는 이야기입니다. 예를 들어 스테이지 gitops의 디렉터리 이름도 prd라서 디렉터리가 아니라 저장소로 구분해야 한다거나, 화면 이름은 저장소에 없고 lingo 라벨에서 내려오므로 번역하지 말고 라벨에서 찾아야 한다는 것 같은 판단입니다. 이런 것을 파일에 적어 두면 새 세션이 매번 같은 기준으로 점검합니다.
동작은 단순합니다. 저장소를 최신화하고 실행 버튼을 누르면 새 세션이 스킬을 읽고 변경 범위, DB 반영 사항, 버전 정합을 점검한 뒤 보고서와 공지 초안을 남깁니다. 저는 보고서를 읽고 결정이 필요한 항목만 고릅니다. 처음부터 큰 구성을 하지 않은 것은 의도였습니다. 다만 몇 번 돌리고 나니 이 구성이 어디까지 버티고 어디서부터 고쳐야 하는지가 보이기 시작했습니다.
4. 고칠 때가 됐다는 신호
신호는 다섯 가지였습니다. 그중 셋은 공식 문서가 적어 둔 도입 시점 그대로였습니다.
본문이 절차가 아니라 셸 조각으로 차 있다
스킬 두 파일이 400줄 안팎이 됐는데, 그 절반이 코드 블록이었습니다. 저장소 스냅샷, 이미지 태그 대조, DB 마이그레이션 파일명 검사, 버전 행렬, 화면 경로 추출 같은 결정론적인 일을 AI가 본문의 셸 조각을 보고 매번 다시 타이핑해 실행하는 구조였습니다. 실행마다 조금씩 달랐고, 이전 실행이 남긴 파일을 읽어 거짓 불일치를 낸 적도 있었습니다. 공식 문서의 표현을 빌리면 "정렬을 토큰으로 하는 것보다 정렬 알고리즘을 돌리는 것이 싸다"입니다. SKILL.md 본문은 발동할 때 전부 컨텍스트에 실리지만, 스크립트는 실행만 되고 출력만 토큰을 씁니다.
같은 규칙의 사본이 여러 곳에 있다
git 규칙이 스킬 둘과 스케줄 프롬프트 둘, 네 곳에 있었습니다. 프롬프트에 "스킬이 없으면 아래 절차를 따른다"며 절차 전체를 복제해 둔 탓입니다. 이중화 의도는 좋았지만 규칙을 한 번 고치는 데 네 곳을 만져야 했고, 한 사본은 어긋났습니다.
실행 환경이 사고 하나를 줬다
스케줄 작업이 도는 환경은 연결된 폴더에서 파일 삭제가 막혀 있었습니다. 그런데 git은 읽기만 하는 것처럼 보이는 명령에서도 잠금 파일을 만들었다 지우기 때문에, 지우지 못한 빈 잠금 파일이 저장소마다 남았습니다. "읽기 전용 명령은 괜찮다"고 적어 둔 규칙이 이 환경에서는 틀린 규칙이었습니다. 이 사고에서 배운 것은 잠금 파일 자체보다 둘입니다. 실행 환경의 성질은 설계의 일부라는 것, 그리고 문장으로 적힌 규칙은 공식 문서 말대로 "요청이지 보장이 아니"라는 것입니다. 매번 지켜져야 하는 규칙은 훅이어야 합니다.
절차가 고정됐다
두 스킬의 절 구조가 같아졌습니다. 원칙 → 대상 → 스냅샷·신선도 → 범위 → 차단 조건 → 산출물 순입니다. 어느 단계가 스크립트로 확정할 수 있는 것이고 어느 단계가 AI의 판단인지 나눌 수 있는 상태가 됐다는 뜻이고, 그게 권장 구조(본문은 절차, 규칙은 참조 파일, 코드는 스크립트)로 옮길 때입니다. 처음부터 그 구조로 시작했다면 무엇이 결정론이고 무엇이 판단인지 몰라서 잘못 나눴을 겁니다.
다음 사용자를 위한 형태가 아니다
스킬은 제 계정에 동기화돼 있고, 알려진 편차와 표기 사전은 산문 목록이고, 본문에 날짜가 박힌 문장이 있었습니다. 저 혼자 쓰는 동안은 문제가 아닙니다. 그런데 이걸 제가 따로 쓰는 하네스에 녹이거나 팀·조직의 AI 활용에 얹으려면 플러그인 단위여야 하고, 설정은 데이터여야 하고, 규칙은 한 곳이어야 합니다. 과도기 절차라고 해서 버려질 형태로 두면 다음 단계에서 다시 만들게 됩니다.
5. 개선
개선의 방향은 한 문장입니다. 규칙이 정해진 검사는 스크립트가 하고, 판단은 AI가 스킬을 따라 하고, 규칙은 한 곳에만 두고, 지켜져야 하는 규칙은 훅이 강제합니다. 스킬 둘을 이 기준으로 다시 나눠 플러그인 하나로 묶었습니다.
devlime-release-ops/
├── skills/ release-check · release-notes · prd-gitops-sync
│ (각 50줄 안팎, 체크리스트 + 판단)
├── references/ repos · git-rules · flyway-check · configmap-compare
│ notice-style · known-deviations · history · ledger
├── config/ 저장소 표 · gitops 대조 규칙 · 기준값 · 버전 상호 참조
│ 알려진 편차 · ledger (JSON)
├── scripts/ snapshot · freshness · changes · flyway_lint · version_matrix
│ cm_pair · routes · locate · ledger · notice_lint · image_tags
│ configmap_diff · plan_validate · plan_apply · plan_verify
├── hooks/ hooks.json + guard.py (명령 실행 전 규칙 검사)
├── evals/ 스킬별 평가 + 트리거 질의
└── tests/ 합성 저장소 생성 + 검사
검사는 스크립트가 하고 종료 코드로 말합니다. 저장소 최신화 여부, 변경 범위, DB 반영 사항의 형식, 라이브러리 버전 정합, 이미지 태그 대조처럼 규칙이 정해진 검사는 파이썬 스크립트가 맡습니다. 결과는 파일로 남기고, 종료 코드로 "통과 / 차단 / 확인 필요 / 오류"를 알립니다. 차단이면 스킬은 보고서 맨 위에 올리고 멈추고, 확인 필요는 판단으로 넘깁니다. 스킬 본문은 이 스크립트들을 순서대로 부르는 체크리스트와, 판단이 필요한 항목을 어떻게 볼지에 대한 설명만 남았습니다.
Release check:
- [ ] 1. 스냅샷 snapshot.py
- [ ] 2. 신선도 freshness.py (낡았으면 멈추고 최신화 명령을 사용자에게)
- [ ] 3. 변경 범위 changes.py
- [ ] 4. DB 반영 사항 flyway_lint.py (판단이 필요한 항목만 가이드 문서를 읽고 판정)
- [ ] 5. 버전 정합 version_matrix.py
- [ ] 6. 보고서 조립 → 문서 저장
되돌릴 수 없는 변경은 계획, 검증, 적용, 확인의 네 단계로 나눕니다. 운영 설정을 고치는 일은 대조 결과를 보고 바로 파일을 고치던 방식에서, AI가 먼저 계획 파일(어느 파일의 어느 값을 무엇으로, 왜)을 만들고 검증 스크립트가 그 계획을 규칙과 현재 파일에 대조한 뒤에야 적용하는 방식으로 바뀌었습니다. 계획에 결정이 미뤄진 항목이 하나라도 있으면 실행하지 않고, 사용자가 승인한 값이 그 사이 바뀌었으면 멈춥니다. 사내 블로그의 "결정 게이트"와 "스냅샷 기반 승인"을 그대로 가져온 것입니다. 적용 후에는 실제 변경이 계획과 정확히 같은지 다시 확인합니다.
규칙은 한 곳에 두고 훅이 강제합니다. 네 곳에 흩어져 있던 규칙은 참조 파일 하나가 원본이 됐고, 스킬과 스케줄 프롬프트는 그 파일을 가리키기만 합니다. 같은 규칙을 훅이 도구 호출 단계에서 검사해, 어긋나는 명령은 이유와 함께 거부합니다. 문장으로 적힌 규칙은 AI가 따르기를 기대하는 것이지만, 훅은 따르지 않을 수 없게 만듭니다. 스케줄 작업의 프롬프트는 절차를 복제하지 않고 "스킬을 실행한다, 없으면 멈춘다" 두 줄이 됐습니다. 날짜가 붙은 경위는 별도 파일로 옮기고 본문에는 규칙만 남겼습니다.
전후 비교
|
항목 |
처음 구성 |
플러그인 |
|---|---|---|
|
스킬 본문 |
400줄 안팎 × 2, 절반이 코드 블록 |
50줄 안팎 × 3, 체크리스트와 판단만 |
|
규칙이 정해진 검사 |
AI가 본문의 셸 조각을 다시 타이핑해 실행 |
스크립트 13개, 종료 코드로 통과·차단·확인 필요 구분 |
|
규칙 |
네 곳에 사본, 문장 |
참조 파일 한 곳 + 훅 |
|
설정·사전 |
본문 산문 |
설정 파일(JSON). 스크립트와 스킬이 같은 파일을 읽음 |
|
운영 설정 변경 |
대조 후 바로 수정 |
계획 → 검증 → 적용 → 확인 |
|
승인 근거 |
최신화 시각 |
최신화 시각 + 저장소별 커밋 해시 |
|
스케줄 프롬프트 |
스킬 호출 + 절차 전체 복제 |
호출 두 줄, 미설치 시 중단 |
|
검증 |
없음 |
스킬별 평가 세트, 합성 저장소 테스트 |
6. 마무리
이번 구성은 스킬 셋, 스크립트 열셋, 훅 하나, 그리고 그것을 묶은 플러그인 하나입니다. Claude Code가 제공하는 확장 기능 일곱 계층으로 보면 여전히 일부이고 사용자는 한 명입니다. 그런데 이 범위는 부족해서가 아니라 순서를 정해서 나온 것입니다. 공식 문서가 각 기능의 도입 시점을 적어 두었기 때문에, 어느 트리거를 밟았고 어느 트리거를 아직 밟지 않았는지 말할 수 있고, 다음 기능이 언제 필요해지는지 미리 압니다.
처음 구성에서 플러그인까지 오면서 가장 많이 바뀐 것은 점검 항목이 있는 자리입니다. 제 머리와 메시지 이력에 있던 것이 파일로 옮겨졌고, 그 파일의 절반은 사람이 읽는 규칙이고 나머지 절반은 스크립트가 실행하는 검사가 됐습니다. 그래서 같은 순서로 같은 것을 보게 됐고, 결정을 미룬 항목이 매번 같은 자리에 남게 됐고, 승인한 값이 그 사이 바뀌면 멈추게 됐습니다. 배포 점검을 AI와 같이 하면서 얻은 것은 시간보다 이쪽이 컸습니다.
다음은 실제 저장소에서 이 구성을 검증하는 일입니다. 이 구성을 어떻게 관리하고 언제 팀으로 올리는지는 다음 글 "개인 AI 구성을 팀 자산으로 올리는 기준"에서 다룹니다.
Juno