설치와 제거
Run은 무인으로 돌기 때문에, 빠진 게 있다면 Ticket 도중이 아니라 시작하기 전에 잡아내야 합니다. init은 Target(명령을 실행한 저장소)을 준비하고, run은 준비되지 않은 Target을 거절하고, remove는 init이 쓴 것과 Run이 남긴 것을 모두 걷어 냅니다. 그러니 내 저장소에 파이프라인을 시험해 봐도 안전합니다.
| 단계 | 명령 | 하는 일 |
|---|---|---|
| 설치 | npm install -g ticket-runner | 머신에 ticket-runner 명령을 설치 |
| Target 준비 | ticket-runner init | 파이프라인 파일을 쓰고, GitHub를 설정하고, 나머지를 알려 줌 |
| 작업 시작 | ticket-runner run | 준비되지 않은 Target은 거절. 실행하기 참고 |
| 걷어 내기 | ticket-runner remove | init이 쓴 것과 Run이 남긴 것을 제거 |
| 삭제 | npm uninstall -g ticket-runner | 머신에서 명령을 삭제 |
요구 사항
| 요구 사항 | 이유 | 확인하는 곳 |
|---|---|---|
| Node 22 이상 | 패키지의 engines 필드 | 설치할 때 npm |
git | Ticket마다 worktree와 branch를 따로 만듦 | – |
Target에 인증된 gh | GitHub 호출은 모두 gh api로 감 | init이 알려 주고, gh가 없는 Host에서는 run이 거절 |
mattpocock-skills 플러그인 1.2.3 이상 버전이 설치된 claude | Stage 하나하나가 claude -p 세션이고, implement Stage가 이 플러그인의 스킬을 실행함 (ADR-0002) | 둘 다 init이 알려 줌. 플러그인은 이름만 확인 |
Claude 요금제로 로그인한 claude | Run을 --api-key로 시작하지 않는 한, Stage는 그 로그인으로 돌고 셸이 export한 ANTHROPIC_API_KEY를 보지 못함 | – |
| Ticket이 계획되어 있는 GitHub 저장소 | Ticket은 보드에서 옴. Planning 참고 | – |
이슈 트래커로 GitHub Issues를 골라 저장소에서 한 번 실행해 둔 /setup-matt-pocock-skills | 이 설정이 있어야 계획용 스킬이 Spec과 Ticket을 GitHub 이슈로 만듦. 실행하면 묻고 나서 docs/agents/issue-tracker.md와 CLAUDE.md의 ## Agent skills 블록을 쓰므로, 이 둘이 있으면 돌린 것 | – |
.github/workflows의 CI 워크플로 | check가 하나도 없는 pull request는 merge되지 않음. gates.ci를 끄면 예외 | init이 알려 줌 |
| 파이프라인이 직접 돌릴 Check | package.json의 test, typecheck 스크립트, 또는 checks에 적은 명령 | init이 알려 주고, 없으면 run이 거절 |
| main checkout에 설치된 Target 자체의 의존성 | Ticket의 worktree는 거기 있는 의존성을 쓰고, 따로 설치해 주는 것은 없음. 없으면 merge-base에서도 모든 Check가 실패하고, Run은 실패하는 base branch로 끝남 | – |
merge는 base branch를 main checkout으로 pull하기만 합니다. 그러니 의존성을 추가하는 Ticket이 merge된 뒤에는 다음 Run 전에 거기서 다시 설치하세요.
플러그인은 Anthropic 공식 마켓플레이스에서 받습니다. 워크스테이션에서도 Operator가 클라우드 Host에 설치할 때와 같은 방법으로 설치합니다. 설치된 버전은 claude plugin list로 확인합니다.
claude plugin marketplace add anthropics/claude-plugins-official
claude plugin install mattpocock-skills@claude-plugins-official설치
npm install -g ticket-runner업그레이드도 같은 명령입니다. 그다음 쓰던 것보다 새로운 버전마다 Release의 After upgrading을 읽으세요. init 다시 실행하기처럼 Target에서 해야 할 일이 적혀 있습니다.
GitHub의 버전 tag에서 바로 설치해도 됩니다. 이 범위는 main이 아니라 가장 높은 tag를 가리키므로, 받는 사본은 언제나 tag가 붙은, 이름 있는 버전입니다(ADR-0007).
npm install -g "github:jjongs2/ticket-runner#semver:*"init과 run은 GitHub Release로 공개된 가장 새로운 버전을 찾아봅니다. 그게 지금 사본이 보고하는 번호보다 높으면 한 줄을 출력할 뿐, 아무것도 거절하지 않습니다.
A newer version is out: 0.5.0, and this is 0.4.0 — upgrade with `npm install -g ticket-runner`.지금 사본이 최신이거나 더 앞서 있을 때, 또는 GitHub에 물어볼 수조차 없을 때(네트워크나 gh가 없을 때)는 아무것도 출력하지 않습니다.
설치 없이 써 보기
npx는 npm 캐시에서 패키지를 실행하므로 전역에 아무것도 설치하지 않습니다. Target에서 시작하고, 이 위키나 파이프라인의 메시지가 ticket-runner라고 하는 자리에 npx ticket-runner를 입력하세요.
cd ~/code/acme
npx ticket-runner init
git add .gitignore CLAUDE.md ticket-runner.json docs/agents .claude/skills/ticket-runner
git commit -m "chore: set up ticket-runner" && git push
npx ticket-runner run
npx ticket-runner remove # 다 써 봤으면| 하려는 일 | 입력 |
|---|---|
| 예전에 캐시된 것 말고 가장 새 버전 쓰기 | npx ticket-runner@latest … |
| 명령마다 같은 버전 쓰기 | npx ticket-runner@<version> … |
npx가 남긴 것 지우기 | ~/.npm/_npx 삭제 |
init으로 Target 준비하기
cd ~/code/acme
ticket-runner initcommit은 하지 않습니다. 첫 Run 전에 쓴 내용을 commit해서 base branch에 push하세요. Ticket의 worktree는 remote에서 branch를 따 오니, Stage는 base branch에 들어간 뒤에야 conventions 문서를 읽고, 클라우드 Host는 push된 것만 봅니다. Ticket을 claim하지 않으므로 Run lock도 잡지 않습니다.
쓰는 것
| 항목 | 위치 | 다음 init에서는 |
|---|---|---|
.gitignore 줄 두 개 | .gitignore: .worktrees/, .ticket-runner/ | 어떤 표기로든 이미 무시하고 있으면 추가하지 않음 |
| 빈 설정 파일 | {}만 담긴 ticket-runner.json | 한번 생기면 건드리지 않음 |
| 버전이 찍힌 conventions 문서 | docs/agents/pipeline-conventions.md | 내용이 다르면 다시 씀 |
| 그 문서를 가리키는 섹션 | CLAUDE.md, 없으면 새로 만듦 | CLAUDE.md가 이미 문서를 가리키면 추가하지 않음 |
| Operator의 스킬 | .claude/skills/ticket-runner/SKILL.md | 내용이 다르면 다시 씀 |
conventions 문서와 스킬은 파이프라인의 글이라, 거기서 고친 내용은 다음 init에서 사라집니다. 예외가 하나 있습니다. 문서 첫 줄에는 숨은 <!-- ticket-runner:version <number> --> 표시가 있는데, 이 표시가 지금 실행 중인 것보다 새 버전을 가리키면 init은 문서와 스킬을 그대로 두고 업그레이드하라고만 알립니다. 다시 쓰면 Target을 과거로 되돌리는 셈이기 때문입니다.
GitHub에서 하는 일
| 설정 | init이 하는 일 |
|---|---|
triage 라벨 여섯 개(needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix, in-progress) | 없는 것만 labels가 정한 이름으로 만들고, 나머지는 그대로 둠 |
| squash merge | 켬. 다른 merge 방식은 건드리지 않음 |
| merge될 때 pull request branch 삭제 | 켬. 클라우드 Host는 branch를 직접 지울 수 없기 때문(ADR-0008) |
gh가 인증되어 있지 않으면 GitHub에서는 아무것도 하지 않고, 보고서에 그렇게 적습니다. 이 설정을 바꾸려면 gh 사용자에게 저장소 설정을 바꿀 권한이 있어야 합니다. merge 시 branch를 지우는지는 GitHub가 그런 사용자에게만 알려 주므로, 다른 사람이 시작한 Run은 그 설정이 꺼진 것처럼 거절됩니다.
알려 주기만 하는 것
ticket-runner 0.5.2 init · /home/me/code/acme
Wrote:
nothing to write
GitHub:
labels: every triage label is already there
merges: squash merging is on, and no other merge method was touched
branches: a pull request's branch is already deleted when it merges
Checked:
✓ `gh` is authenticated
✓ `claude` runs
✓ the `mattpocock-skills` plugin is installed
✗ no CI workflow in `.github/workflows` — a pull request with no checks is never merged
✓ a Check is configured or inferable: npm test, npm run typecheck
Not ready: 1 item is yours to put right..github/workflows에 .yml이나 .yaml 파일이 하나라도 있으면 워크플로가 있다고 봅니다.
| 종료 코드 | 뜻 |
|---|---|
0 | 알려 준 항목이 모두 통과 |
1 | 사람이 고칠 항목이 하나 이상 남음 |
2 | 거절: Stage의 셸이거나 ticket-runner.json이 잘못됨 |
그래서 ticket-runner init && ticket-runner run은 어차피 안 될 Run을 시작하기 전에 멈춥니다.
Target 준비 상태: run이 거절하는 경우
run은 아무것도 고치지 않습니다. init이 뒀어야 할 항목이 있는지 이 순서로 확인하고, 처음 빠진 항목에서 종료 코드 2로 거절합니다. 어느 Host에서나 똑같이 확인하므로, 워크스테이션의 Run이 받아들인 Target은 Operator가 Claude 앱에서 돌려도 받아들여집니다.
| 순서 | 거절하는 경우 |
|---|---|
| 1 | .gitignore가 .worktrees/나 .ticket-runner/를 무시하지 않음 |
| 2 | docs/agents/pipeline-conventions.md가 없거나 버전 표시가 없음 |
| 3 | CLAUDE.md가 그 문서의 경로를 언급하지 않음 |
| 4 | Operator의 스킬이 없음 |
| 5 | gh가 설치되어 있지 않음. 이때는 init보다 설치를 먼저 안내 |
| 6 | labels가 정한 이름의 triage 라벨이 하나라도 없음 |
| 7 | 저장소가 merge된 pull request의 branch를 남겨 둠 |
| 8 | remote의 base branch(예: origin/main)에 2, 3, 4번 항목 중 하나가 없음. worktree는 모두 여기서 만들어지므로, init을 다시 돌리라는 대신 init이 쓴 것을 commit하고 push하라고 안내 |
$ ticket-runner run
This Target is not set up: `.gitignore` does not ignore `.worktrees/`. Run `ticket-runner init` here and start again; a Run puts nothing in place itself.준비 상태 확인은 있는지와 버전 표시만 보고, 내용은 보지 않습니다. 다른 버전이 쓴 conventions 문서는 경고로 그치고, Run은 그대로 진행합니다.
warning: This Target's `docs/agents/pipeline-conventions.md` was left by 0.4.0, and this Run is 0.5.2 — run `ticket-runner init` here to bring it up to date.준비 상태 확인보다 먼저 오는 거절이 하나 있습니다. 클라우드 Host에서, 또는 ANTHROPIC_API_KEY를 export하지 않고 --api-key를 준 경우입니다.
준비 상태 확인 다음에 거절이 두 가지 더 있습니다.
- checkout에 남은 state file. 초기 파이프라인은 Ticket의 재개 상태를
.ticket-runner/state/에 뒀는데, 지금은 Target의 remote에 두고, 옮겨 주는 것은 없습니다. 이 디렉터리에 state file이 남아 있으면 Run은 해당 Ticket을 나열하며 거절합니다. 그 파일을 쓴 버전으로 Ticket을 마무리하거나 사람에게 넘긴 다음, 디렉터리를 지우세요. - Check 없음. Checks 게이트가 켜져 있는데 설정하거나 추론할 수 있는 Check 명령이 없으면, 검사하지 않은 코드를 merge하느니 Run을 거절합니다.
remove로 걷어 내기
cd ~/code/acme
ticket-runner remove # 지울 목록을 보여 주고 물어봄
ticket-runner remove --yes # 묻지 않고 그대로remove는 파이프라인이 뒀다고 증명할 수 있는 것만 걷어 냅니다. commit은 하지 않으니 git status로 바뀐 내용을 살펴보고 직접 commit하세요. 작업하는 동안 Run lock을 잡아서, 해체 중인 Target에서 Run이 시작되지 않게 합니다.
거절할 때는 언제나 다음에 할 일을 알려 줍니다. lock이 잡혀 있으면 누가 잡았든 거절됩니다. 이 Host에서 프로세스가 사라진 Run이 잡고 있어도 마찬가지입니다. remove는 lock을 넘겨받지 않으니, ticket-runner run을 시작해 그 Run이 맡고 있던 일을 마무리하거나 직접 lock을 푸세요(Hand-off, 멈추고 이어 하기). 클라우드 Host는 remote의 branch를 지울 수 없어서 거절합니다. remove는 워크스테이션에서 실행하세요.
사라지는 것과 남는 것
제거하는 것:
docs/agents/pipeline-conventions.md, Operator의 스킬, 그 결과 비게 된 디렉터리init이 쓴CLAUDE.md섹션. 그 섹션뿐인 파일이면 파일째 지웁니다.init이 쓴 주석 아래 그대로 있는.gitignore줄. 그 줄뿐인 파일이면 파일째 지웁니다..ticket-runner/: Run 로그와 transcript.worktrees/ticket-<n>worktree와 그 branch, 다른 로컬agent/branch, 비게 된.worktrees/in-progress라벨. 달고 있던 모든 이슈에서 뗍니다.ticket-runner/statebranch. 이제 재개할 수 없게 된 Ticket을 보고서가 모두 알려 줍니다.ticket-runner.json. 맨 마지막에, 앞의 제거가 모두 성공했을 때만 지웁니다.ticket-runner/lockbranch. 맨 마지막에 지우고, 실패한 제거가 있으면 지우지 않고 lock만 풉니다.
남겨 두는 것:
in-progress를 뺀 triage 라벨 다섯 개. Planning에서도 쓰기 때문입니다.- 문구를 고친
CLAUDE.md섹션. 이제 사람의 것일 수 있어서입니다. - 사람이 단 주석 아래 있는
.gitignore줄 - 다른 것이 들어 있는
.worktrees/, 그리고 그.gitignore줄 - squash merge와 merge 시 branch 삭제 설정.
init전부터 켜져 있었을 수 있습니다. - GitHub의
agent/branch와 거기 열린 pull request - 상설 Notes 이슈, 그리고 Run이 쓴 모든 코멘트. 사람에게 쓴 글이라서입니다.
실패한 제거는 보고하고 나머지는 계속 진행합니다. remove를 다시 실행하면 남은 것을 대상으로 처음부터 다시 하는 셈입니다.
| 종료 코드 | 뜻 |
|---|---|
0 | 모두 사라졌거나, 지울 것이 없었음 |
1 | 제거가 하나 이상 실패 |
2 | 아무것도 바꾸기 전에 거절 |
삭제
npm uninstall -g ticket-runnerTarget마다 먼저 ticket-runner remove를 실행하세요. 명령을 지운 뒤에는 할 수 없습니다.
관련 페이지
- 일 계획하기: 파이프라인이 가져가는 Ticket이 되려면
- 실행하기: Run을 시작하고, 좁히고, 멈추기
- 설정: 라벨을 포함한
ticket-runner.json의 필드 - Hand-off, 멈추고 이어 하기:
remove가 지우는 Run lock과 state branch
참고 자료
src/init.ts,src/labels.ts,src/conventions.ts,src/operator-skill.tssrc/readiness.ts,src/start.ts,src/startup.ts,src/staleness.ts,.github/workflows/version-tag.ymlsrc/remove.ts,src/command-line.ts,src/cli.tsdocs/templates/init-report.txt,docs/templates/remove-report.txt- ADR-0002, ADR-0007, ADR-0008