<!-- canonical: https://docs.axelabs.ai/ops/runbook/release-flow -->
<!-- source: content/ops/runbook/release-flow.mdx -->

---
title: Release flow (axe ship)
description: 코드 변경 → 운영 반영까지의 release-gate. `git push origin main` 대신 `axe ship` 한 명령으로 docs-check + push + deploy 를 묶음.
playbook: true
---

# Release flow — `axe ship`

## AI 요청 프롬프트

```
https://docs.axelabs.ai/ops/runbook/release-flow 따라 본 repo 변경 release 해줘.

진행:
1. 현재 repo + branch + 변경 상태 진단 (git status + git log origin/main..HEAD + 동반 docs 갱신 commit 존재 여부)
2. 페이지 "Service 매핑" 표 확인 — 본 repo 의 deploy hook 자동/수동 분기
3. 페이지의 각 Step (docs-check → branch clean → push preview → confirm → push → deploy hook) 매 step 결과 받고 다음. 특히 Step 4 confirm 직전 사용자 확인
4. 함정 발생 시 페이지 "함정" 표 따라 우회 (docs commit 누락 / cross-repo drift / feature branch)
5. 배포 완료 후 production 검증 + (선택) updates.mdx Ship Log 한 줄 추가
```

본인 AI session = Claude Code / Cursor / ChatGPT 데스크탑 / Claude.app / 기타.

페이지 본문 = 사람이 직접 read 도 가능, AI 도 참고. AI 가 본 페이지 fetch 후 위 진행 순서대로 사용자와 step-by-step interactive 풀어나감.

> **Problem**: 코드 변경 후 docs (`axelabs-docs/content/*.mdx`) 갱신을 깜빡하면 production 사이트가 거짓말을 함. 매 commit 마다 hook 으로 강제하면 WIP commit 이 막혀서 `--no-verify` 우회 습관이 생김 → hook 사실상 무력화.
>
> **Solution**: release 시점에만 강제. `git push origin main` 의 자리에 `axe ship` 를 둬서, **production 으로 나가는 모든 push 가 docs-drift 검증을 통과해야** 함. WIP / feature branch push 는 raw git 으로 그대로 사용.

## 한 줄 요약

```bash
# 이전 습관
git push origin main && ssh axe-macmini "cd /Users/axe/<service> && docker compose ..."

# 새 습관
axe ship          # 현재 repo 자동 감지 → docs-check → push → deploy
axe ship frame    # 명시
axe ship docs     # docs SSOT 자체 배포
```

## 무엇을 하는가

| Step | 동작 | 실패 시 |
|---|---|---|
| 1 | `axe docs-check --since origin/main` (현재 repo) | abort — 누락 mdx 페이지 출력 후 종료 |
| 2 | branch == `main` && working tree clean | abort |
| 3 | `git log origin/main..HEAD` 출력 (push 될 commit 미리보기) | nothing-to-push → abort |
| 3b | `axelabs-docs` 에 unpushed commit 있나? 있으면 경고 | (계속 진행, 단순 hint) |
| 4 | `yes/no` confirm 프롬프트 | abort |
| 5 | `git push origin main` | git push 자체 실패면 abort |
| 6 | service 별 deploy hook (아래 표) | (배포 실패는 알림, push 는 이미 완료) |

## Service 매핑

| `axe ship SERVICE` | repo | deploy hook |
|---|---|---|
| `frame` | `/Users/axe/frame` | `cmd_deploy` (blue/green swap, plan §3 D-config-13) |
| `blueprint` | `/Users/axe/blueprint` | `cmd_blueprint_upgrade` (sequential blue/green) |
| `docs` | `/Users/axe/axelabs-docs` | `docker compose up -d --build` (단일 컨테이너, ~30-60s 다운) |
| `hive` | `/Users/axe/hive` | (자동화 X) manual hint 출력 |
| `stream` | `/Users/axe/stream` | (자동화 X) manual hint 출력 |
| `magnet` | `/Users/axe/magnet` | (자동화 X) manual hint 출력 |

`hive/stream/magnet` 의 blue/green CLI 가 `axe deploy` 에 들어오면 매핑 갱신.

## 옵션

```
axe ship [service]
  --dry-run     # 실행 안 함, 어떤 step 이 무엇을 할지만 출력
  --no-deploy   # docs-check + push 까지만, 배포 hook skip (배포는 나중에 수동)
```

**escape hatch 없음**. `--skip-docs-check` 같은 플래그는 의도적으로 만들지 않음. drift 가 있다면:

1. `axelabs-docs/content/PAGE.mdx` 수정
2. `cd /Users/axe/axelabs-docs && git add -A && git commit -m 'docs: ...'`
3. `axe ship docs` (production 반영)
4. 원 repo 로 돌아와 `axe ship SERVICE` 재실행

## docs SSOT 의 특수성

`axe ship docs` 는 docs-check 를 **skip** 함 (자기가 SSOT 인데 자기 자신과 drift 비교는 무의미). 대신:

- branch + working tree clean 검사는 동일
- push 후 `docker compose up -d --build` 로 즉시 production 반영
- 배포 시간 ~30-60s, 단일 컨테이너 (blue/green X)

## 운영 순서

코드 변경이 docs 영향이 있는 경우 (대부분):

```bash
# 1. 코드 작업 (frame 예시)
cd /Users/axe/frame
# ... 작업 ...
git add -A && git commit -m "feat(frame): add foo MCP tool"

# 2. docs 갱신
cd /Users/axe/axelabs-docs
vim content/services/frame.mdx   # MCP Tools 표에 foo 추가
git add -A && git commit -m "docs(frame): document foo MCP tool"

# 3. docs 먼저 배포 (frame ship 의 docs-check 가 통과되도록 origin/main 에 docs commit 도달)
cd /Users/axe/axelabs-docs
axe ship                          # docs 자동 감지, push + rebuild

# 4. frame 배포
cd /Users/axe/frame
axe ship                          # frame 자동 감지, docs-check 통과, push + blue/green swap
```

## 함정

| 함정 | 결과 | 회피 |
|---|---|---|
| `axe ship` 대신 `git push origin main` 직접 | docs-check 미실행 → drift 누적 | release-worthy push 는 반드시 `axe ship` |
| feature branch 에서 `axe ship` | "current branch is X, expected main" abort | merge to main 먼저 |
| docs commit 안 한 채 `axe ship frame` | docs-check fail, push 거부 | docs 먼저 commit + ship |
| `axe ship docs` 전에 `axe ship frame` | docs commit 은 frame repo origin/main 에서 보임 → check 통과, but production 사이트는 옛 mdx | docs 먼저 ship (cross-repo 경고가 출력됨) |
| 다른 사람의 mdx 변경이 origin/main 에 있음 | docs-check 통과 (이미 mdx 있음) | 정상 — 다른 push 가 이미 docs 채움 |

## 왜 pre-commit hook 이 아닌가

자세한 의사결정 근거: [`D-ops-N` (release-gate-not-precommit)](/ops/decisions). 요약:

- pre-commit hook 은 WIP commit 마다 발화 → 노이즈 → `--no-verify` 습관화 → hook 사실상 죽음
- release-gate (`axe ship`) 는 운영자가 의도해서 호출하는 단 한 곳에 검증을 집중 → 우회 유혹 적음
- 솔로 운영자 + Claude Code 주 개발자 환경에서 ROI 가 가장 높은 지점

## 관련

- [`axe docs-check`](/ops) — drift 감지기 (ship 의 step 1 내부에서 호출)
- [DECISIONS](/ops/decisions) — release-gate 결정 근거
- [Blue/green deploy](/ops/runbook/deploy) — frame/blueprint 배포의 내부 동작
