프로젝트 수정을 템플릿 저장소로 올리는 에이전트 스킬
게임 프로젝트는 H5 프레임워크 템플릿 저장소를 받아 시작한다. 개별 게임을 만들다 보면 템플릿에서 온 공용 코드를 고치게 되는데, 내 게임에서 고친 내용이 템플릿에는 그대로 남는다. 그러면 다음 게임을 새로 만들 때 같은 문제를 다시 만나고, 저장소마다 우회 코드가 따로 쌓인다.
템플릿으로 반영하는 일은 손이 많이 간다.
- 프로젝트와 템플릿이 별개 저장소라 그냥 커밋해서는 넘어가지 않는다.
- 공용 파일에 게임 전용 변경이 섞여 있어 파일을 통째로 복사할 수 없다.
- 급하게 템플릿
master에 직접 푸시하면 되돌릴 방법이 revert뿐이라 히스토리에 흔적이 남는다. 실제로 그렇게 커밋 4개가 남은 적이 있다.
이 과정을 AI 에이전트가 대신 하도록 스킬과 슬래시 커맨드 /upstream으로 묶었다. 템플릿에서 프로젝트로 받아 오는 방향의 반대, 즉 프로젝트에서 고친 것을 템플릿으로 돌려보내는 방향이다.
스킬 저장소에서 npx로 설치기를 바로 실행한다. 클론할 필요가 없고, 어느 저장소에도 의존성이 추가되지 않는다. 필요한 스킬만 골라 받는다.
npx --yes git+https://<스킬 저장소>.git install upstream-to-templatenpx가 저장소를 임시로 받아 설치기만 실행하고 끝낸다. install 대신 list를 넣으면 스킬 목록을 본다. 설치기는 홈 디렉터리에서 에이전트를 감지한다. ~/.cursor가 있으면 Cursor에, ~/.claude가 있으면 Claude Code에 넣고, 둘 다 있으면 양쪽에 넣는다. 대상을 직접 정할 때는 --agent cursor나 --dir <경로>, 미리 확인만 할 때는 --dry-run을 쓴다.
설치되는 파일은 세 개다.
skills/upstream-to-template/SKILL.md 에이전트가 읽는 절차서skills/upstream-to-template/scripts/template_mr.py GitLab API 호출을 담당하는 헬퍼commands/upstream.md 슬래시 커맨드SKILL.md에는 절차만 적고 실제 통신은 헬퍼 스크립트가 한다. 헬퍼는 Python 3.8 이상의 표준 라이브러리만 써서 pip install이 필요 없다. 같은 명령을 다시 실행하면 갱신되고, 위 파일을 지우면 삭제된다.
GitLab 토큰은 MR 생성까지 하려면 api 스코프, 조회만 하려면 read_api 스코프로 발급한다. 토큰은 프로젝트가 아니라 사람 단위라 하나로 같은 GitLab의 모든 저장소에 통한다. 사용자 환경변수로 한 번 등록해 두면 새 셸에서도 유지된다.
[Environment]::SetEnvironmentVariable('GITLAB_TOKEN', 'glpat-...', 'User')토큰은 환경변수로만 다루고 커밋하지 않는다. 스크립트도 토큰을 출력하지 않는다.
채팅창에 /upstream과 올릴 대상을 적는다. 파일 경로, 커밋 SHA, 방금 한 작업 중 무엇이든 된다. 대상을 적지 않으면 지금 프로젝트에서 템플릿과 벌어진 공용 파일 목록을 뽑아 보여 주고 무엇을 올릴지 묻는다. /upstream 없이 “이 수정 템플릿에도 반영해줘”라고만 말해도 스킬 설명의 키워드에 걸려 잡힌다.
templateremote를 확인하고, 없으면 추가한 뒤 fetch한다.- 공용 경로에 한정해
template/master와의 차이를 뽑아 후보를 제시한다. - 격리된
git worktree를 만든다. - 고른 부분만 패치로 적용한다.
- 검증한다.
- 커밋한다.
- 멈춰서 최종 diff를 보여 주고 승인을 받은 뒤 푸시하고 MR을 만든다.
- AI 리뷰 봇의 리뷰를 확인하고 대응한다.
- worktree를 정리하고 MR URL을 보고한다.
공용 경로는 src/common/, src/network/, util/와 루트 설정 파일(tsconfig.json, vite.config.ts, project.config.ts 등)이다. src/game, src/intro, raw-assets, scripts는 게임 전용이라 대상에서 뺀다.
안전장치
섹션 제목: “안전장치”손으로 하다 사고가 났던 지점을 규칙으로 굳혔다.
template/master에는 직접 푸시하지 않고 항상 브랜치와 MR을 거친다.- 브랜치 전환이나 stash 없이 별도 worktree에서만 작업한다. 하던 작업을 그대로 두고 실행해도 된다.
- 파일을 통째로 복사하지 않고 hunk 단위로 골라 담는다. 게임 코드를 import하는 줄이 섞여 있으면
references-game-code플래그로 걸러 낸다. - 자격증명이 섞여 나가지 않게 막는다.
.npmrc,.gitlab-ci.yml처럼 토큰이 들어갈 수 있는 파일은may-carry-credentials로 표시하고, 추가된 줄이 실제 토큰처럼 보이면SECRET-IN-DIFF로 경고한다. 템플릿 저장소는 public이라 한 줄만 새도 MR을 여는 순간 공개된다. - 브랜치 생성과 커밋까지만 자동이고, 원격에 나가기 직전에 멈춰 승인을 받는다.
- MR을 만들기 전에 사전 점검을 한다. 작업하는 동안 템플릿
master가 움직여 대상 파일이 옮겨졌으면 전송하지 않고 멈춘다. 공용 파일 하나가 다른 디렉터리로 옮겨지면서 MR을 통째로 다시 만든 적이 있어 넣은 규칙이다.
rename과 하위 프로젝트 검색
섹션 제목: “rename과 하위 프로젝트 검색”메서드나 클래스 이름을 바꿔 올릴 때는 남은 호출부 검색이 필수다. 템플릿에서는 멀쩡히 컴파일되는데, 템플릿을 받아 쓰는 다른 게임이 다음 동기화 때 깨질 수 있다.
python "<스킬 폴더>/scripts/template_mr.py" search <옛 이름> --downstream--downstream은 템플릿을 쓰는 파생 게임 저장소들을 GitLab 코드 검색으로 훑는다. 새 게임이 템플릿을 쓰기 시작하면 스크립트의 DOWNSTREAM_PROJECTS에 추가한다.
이 검색만 믿으면 안 된다. GitLab 코드 검색은 각 저장소의 기본 브랜치만 본다. 기본 브랜치가 아닌 곳(예: 기본은 master인데 작업은 develop)에서 개발하는 게임은 심볼이 있는데도 0건으로 나온다. 실제로 이렇게 두 저장소가 누락됐다. 그래서 스킬은 zoekt 기반 코드 검색 MCP를 함께 돌려 두 결과의 합집합을 답으로 삼는다. zoekt는 인덱싱된 모든 브랜치를 보지만 템플릿 자신과 일부 저장소는 아직 인덱싱되어 있지 않다. 그래서 어느 한쪽으로 대체하지 않고 병행한다.
헬퍼 스크립트
섹션 제목: “헬퍼 스크립트”에이전트를 거치지 않고 헬퍼를 직접 실행해도 된다.
python "<스킬 폴더>/scripts/template_mr.py" <서브커맨드> [옵션]로컬 저장소에는 쓰지 않고, 원격에 쓰는 동작은 create-mr 하나뿐이다.
| 서브커맨드 | 용도 |
|---|---|
info --repo PATH |
template remote와 fetch 상태 확인. 설정이 없으면 해결 명령을 그대로 출력 |
candidates --repo PATH |
공용 경로에서 템플릿과 벌어진 파일 목록과 위험 플래그 |
search TERM [--downstream] |
템플릿과 파생 게임 코드 검색. 각 저장소의 기본 브랜치를 함께 표시 |
create-mr ... |
사전 점검 후 MR 생성. --dry-run으로 전송 없이 확인 |
review --iid N [--watch] |
MR의 AI 리뷰 조회. 아직 없으면 --watch로 대기 |
알아 둘 점
섹션 제목: “알아 둘 점”- 템플릿에 머지되어도 다른 게임에 자동으로 반영되지 않는다. 파생 프로젝트는 파일을 복사해 가지고 있어서 같은 수정이 필요하면 저장소별로 따로 처리한다.
templateremote가 없는 프로젝트도 있다. 없으면 1단계가 추가 명령을 알려 준다. 로컬 설정 변경일 뿐이라 저장소에는 영향이 없다.- 템플릿 저장소에도 AI 리뷰 웹훅이 걸려 있어 MR을 만들면 자동 리뷰가 MR 코멘트로 달린다. 빠르면 수십 초 안에 올라오고, 스킬이 8단계에서 조회하고 대응한다.
- MR은 squash로 머지되므로
master에 남는 메시지는 커밋 제목이 아니라 MR 제목이다. 어떤 심볼이나 파일을 왜 건드렸는지가 제목만으로 드러나게 쓴다. - 절차서는 마크다운이라 누구나 고칠 수 있다. 순서나 규칙은
SKILL.md에서, 공용 경로 목록이나 파생 프로젝트 목록처럼 코드에 박힌 값은scripts/template_mr.py상단 상수에서 바꾼다. 스킬 저장소master에 머지되면 각자 install 명령을 다시 실행해 갱신한다.