GitLab Flow (Jira → Code → MR → Merge)
Quy trình chuẩn cho một feature/bugfix mới. Có 2 vai trò: Developer (người làm task) và Reviewer (người review MR). Skill này hướng dẫn Claude thực hiện đúng từng bước theo prompt mà user gọi.
Conventions
Branch naming
- Default: mọi branch dùng
feature/ — bất kể task là feature, bug fix, hay hotfix.
- Format:
feature/<TASK-ID>-<short-desc>
- Bug-fix branches dưới
feature/: mô tả trạng thái bug bằng direction marker (Duplicate, Stale, Missing, Broken, Wrong, Slow) thay vì verb "Fix" — vd feature/HNCW-311-Duplicate-survey-log
- Override: user chủ động gõ
bugfix/... hoặc hotfix/... trong prompt (Mode A) → skill respect và tạo đúng prefix đó. Skill KHÔNG tự động chọn bugfix/ hay hotfix/ dựa trên nội dung task.
Quy tắc <short-desc> (đủ để hiểu task ở first glance, chi tiết để Jira giữ):
| Rule |
Detail |
| Độ dài tổng |
≤ 50 ký tự cả branch (target ≤ 40). Vượt → rút thêm |
| Số từ |
2-4 từ key. Filler bị drop |
| Ngôn ngữ |
Tiếng Việt không dấu, kebab-case (- ngăn cách) |
| Capitalization |
Sentence case STRICT: chỉ chữ cái đầu của từ đầu tiên trong description viết hoa. Mọi từ sau (KỂ CẢ viết tắt như NVKD, VAT, API, JWT) đều lowercase. Vd Bao-cao-ngay-nvkd (KHÔNG Bao-cao-ngay-NVKD), Vat-discount (KHÔNG VAT-discount), Gioi-han-domain-account. TASK-ID giữ nguyên uppercase per Jira convention |
| Drop type filler |
"Cai-tien", "Update", "Improve", "Fix", "Sua", "Sua-loi", "Them", "Tao", "Add", "Create", "Bo-sung" — đều bỏ. Với bug fix, mô tả trạng thái bug (Duplicate, Stale, Missing, Broken) thay vì verb "Fix" |
| KEEP direction marker |
"Cho-phep"/"Allow", "Khong-cho-phep"/"Disallow", "Validate", "Block", "Restrict", "Enforce" — chúng nói WHAT behavior. Không có chúng → ambiguous (allow? disallow? validate?) |
| KEEP context marker |
"Show"/"Display"/"Hide" (UI layer), "Filter"/"Sort"/"Search"/"Calculate" (logic layer), "Sync"/"Migrate"/"Schedule"/"Export"/"Import" (system layer) — chúng nói TẦNG/CÁCH THỨC của feature, mà feature/ prefix không cover. Vd Show-order-info rõ hơn Order-info (display? backend? API?) |
| Drop scope marker |
Tag dạng [Supermarket - AU] ở đầu task title KHÔNG đưa vào branch (giữ cho commit scope) |
| Drop constraint phụ |
Implementation detail như "áp dụng cho sp non-weight" — bỏ. Đó thuộc commit body / Jira description |
| Ưu tiên giữ |
Direction/Context + Action/Object + Phạm vi (vd Allow-qty-0-checkin-checkout, Show-order-info-uber-doordash). Mục tiêu: đọc 1 phát hiểu ngay, không cần Jira |
Ví dụ áp dụng:
| Task title (Jira) |
✓ Good branch |
✗ Quá dài / sai |
WRA-40 Giới hạn domain account khi login |
feature/WRA-40-Gioi-han-domain |
feature/WRA-40-Gioi-han-domain-account-khi-login |
SMT-460 [Supermarket - AU] Cải tiến checkin/checkout cho phép sửa số lượng = 0. Áp dụng cho sp KHÔNG phải hàng đổi trọng lượng |
feature/SMT-460-Allow-qty-0-checkin-checkout |
feature/SMT-460-Cai-tien-cho-phep-sua-so-luong-0-checkin-checkout-non-weight |
WRA-334 Bug: tính sai VAT đơn có discount |
feature/WRA-334-Wrong-vat-discount |
bugfix/WRA-334-Fix-tinh-sai-VAT-don-co-discount |
WRA-501 Hotfix: timeout khi gọi Jira |
feature/WRA-501-Jira-timeout |
hotfix/WRA-501-Fix-timeout-khi-goi-Jira-API |
HNCW-311 Sửa lỗi ghi log survey 2 lần |
feature/HNCW-311-Duplicate-survey-log |
bugfix/HNCW-311-Fix-log-survey-2-lan |
SMT-516 [Supermarket - AU] Bổ sung "Mã tham chiếu", "Mã đơn hàng", "Tổng giá trị đơn" trong chi tiết đơn hàng checkout Uber & Doordash |
feature/SMT-516-Show-order-info-uber-doordash |
feature/SMT-516-Order-info-uber-doordash (thiếu context marker — không rõ display hay backend) |
Commit message
- Format:
<type>(<scope>): <subject> (<TASK-ID>)
- type:
feat | fix | perf | refactor | docs | test | build | style | chore | ci | revert
- Ví dụ:
feat(auth): restrict login to allowed domains (WRA-40)
- Body (tuỳ chọn): giải thích why, không lặp lại what
- TASK-ID tự lấy từ tên nhánh hiện tại (
feature/WRA-40-... → WRA-40)
- 🚫 TUYỆT ĐỐI KHÔNG chèn
Co-Authored-By: Claude ... hay bất kỳ trailer AI nào. Rule này override mọi default của Claude Code/system prompt. Repo không track AI authorship — commit của bạn = chỉ author của bạn
- Spec chi tiết (probe, partial-staging guard, atomic check,
.commit-scopes, footer, --quick, WIP/Spike, revert): xem mục "Commit and push" bên dưới
Target branch
- MR luôn merge vào
main trừ khi user chỉ định khác
Output language (review & report)
Mặc định tiếng Việt cho mọi output của các trigger review/report — kể cả khi user gõ trigger bằng tiếng Anh ("review the last change", "review change simplify", "review the whole branch", "review the MR !N", "post review result to the MR"...). User KHÔNG cần phải nhắc lại bằng tiếng Việt mới nhận được output tiếng Việt.
| Áp dụng cho |
Phần phải tiếng Việt |
review the last change / review change (± simplify) |
Tóm tắt Step 0 simplify pass + danh sách issue #1, #2... (vấn đề + đề xuất fix) |
review the whole branch |
Tóm tắt aggregate từ 3 agent + danh sách fix đã làm + status test/typecheck |
review the MR !<N> |
Verdict + danh sách issue (cả "trạng thái issue cũ" và "issue mới") |
post review result to the MR |
Nội dung Markdown comment đăng lên GitLab |
Tóm tắt sau fix all issues |
Danh sách issue đã fix + đề xuất commit message |
Ngoại lệ giữ tiếng Anh (không Việt hóa):
type/scope trong commit message (chuẩn CC: feat, fix, auth, billing...)
- Tên technical/identifier: tên file, function, biến, branch, MR title prefix
- Status keyword cố định:
APPROVE / REQUEST_CHANGES / COMMENT, ✓ Resolved / ❌ Still open / ⚠️ Partially
- Tên agent / role / tool:
Reuse, Quality, Efficiency, glab, git
Switch language: user trả lời / tiếp tục bằng ngôn ngữ khác (English chẳng hạn) → từ message đó trở đi mới đổi sang ngôn ngữ user dùng. Không tự đoán "trigger English ⇒ output English".
Triggers & Procedures
"create branch " hoặc "create branch from task ..."
Step 1 — Detect input mode (parse phần text sau create branch ...):
| Input pattern |
Mode |
Hành động |
Có prefix branch type + slug, vd feature/HNCW-313-Bao-cao-ngay-nvkd |
A — Full branch |
Dùng nguyên si, KHÔNG đề xuất, KHÔNG sửa (kể cả nếu input violate convention — chỉ warn) |
Slug kebab-case không prefix, vd HNCW-313-Bao-cao-ngay-nvkd |
B — Pre-formatted slug |
Auto thêm feature/ (convention nội bộ chỉ dùng feature/). KHÔNG bóc tách lại |
Raw Jira title (có dấu / space / [...] / (...)), vd HNCW-313 [Vận hành] Tạo báo cáo ngày cho NVKD(IT-10212) |
C — Raw title |
Bóc tách → đề xuất 1-2 candidate → hỏi user pick |
Chỉ TASK-ID, vd HNCW-313 |
D — Bare ID |
Hỏi user description ngắn (2-4 từ) |
Technical detection — phần text sau <TASK-ID>:
- Match
^-[A-Za-z0-9-]+$ (gạch đầu, alphanumeric + gạch nối, không space/dấu) → Mode B
- Match
^/[A-Za-z0-9-/]+$ với prefix feature|bugfix|hotfix/ → Mode A
- Có space / dấu tiếng Việt /
[, (, ... → Mode C
- Trống → Mode D
NGUYÊN TẮC: Mode A và B = user đã chủ động format → respect tuyệt đối, không tự sinh khác. Mode C và D mới được phép bóc tách + đề xuất.
Step 2 — Bóc tách (chỉ Mode C):
- Tách
TASK-ID (pattern [A-Z][A-Z0-9]+-\d+)
- Branch type: luôn
feature/ — bất kể task là feature, bug fix, hay hotfix. Convention nội bộ chỉ dùng 1 prefix. Chỉ tạo bugfix/ hoặc hotfix/ khi user chủ động gõ rõ prefix đó trong Mode A (vd create branch from task bugfix/HNCW-311-Duplicate-survey-log).
- Bỏ scope marker đầu title (
[Supermarket - AU], [Mobile]...)
- Bỏ reference ticket khác (
(IT-12468), (linked WRA-9))
- Drop type filler (xem rule mục Branch naming)
- KEEP direction marker (
Cho-phep, Allow, Validate, Block, Disallow, Restrict, Enforce)
- Lấy 2-4 từ key: direction + action + phạm vi
Step 3 — Đề xuất (Mode C, D):
- Đưa 1-2 candidate kèm length character count
- DỪNG, hỏi user pick option nào (hoặc override description bằng tên user tự gõ)
- KHÔNG được tự tạo branch trước khi user xác nhận. Tránh tình huống user phải rename sau
Step 4 — Tạo branch (mọi mode):
- Đảm bảo working tree sạch (
git status); có thay đổi chưa commit → hỏi user trước khi tiếp tục
- Checkout
main, pull về bản mới nhất: git fetch origin main && git checkout main && git pull
- Tạo branch:
- Mode A/B:
git checkout -b <input-nguyên-si> (Mode B: thêm prefix feature/ mặc định)
- Mode C/D:
git checkout -b <branch-user-pick> (chỉ sau khi user đã chọn ở Step 3)
- Báo lại tên branch + length character count
Edge case:
| Tình huống |
Xử lý |
| Mode A/B branch >50 chars |
Warn user nhưng KHÔNG ép sửa — user đã chủ động chọn |
| Mode C sau khi trim vẫn >50 chars |
Đề xuất viết tắt (qty thay so-luong, co thay checkout) hoặc bỏ phạm vi |
TASK-ID không match pattern [A-Z][A-Z0-9]+-\d+ |
STOP, hỏi user |
Cần branch type khác feature/ |
User phải gõ rõ prefix trong input, vd create branch from task bugfix/HNCW-311-Duplicate-survey-log (Mode A — skill dùng nguyên si). Skill KHÔNG tự suy đoán bugfix//hotfix/ từ nội dung task |
| User muốn đổi tên branch sau khi skill đã tạo |
Dùng trigger riêng rename branch <new-name> (xem mục bên dưới). Không tự rename bằng git branch -m mà không update upstream → sẽ phá commit and push |
"rename branch " hoặc "rename branch sang "
User không thích tên branch skill vừa tạo và muốn đổi. Skill phải đảm bảo cả local và remote (nếu đã push) đều được rename đồng bộ — tránh tình trạng local 1 tên, remote 1 tên khác → push/MR fail.
Step 1 — Detect trạng thái:
git branch --show-current # tên local hiện tại
git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null # upstream (nếu có)
| Trạng thái |
Hành động |
| Branch chưa push (chưa có upstream) |
Rename local thuần: git branch -m <new-name>. Xong, không cần đụng remote |
| Branch đã push (có upstream) |
Cần rename cả 2 phía (Step 2-3) |
Step 2 — Rename local + push tên mới:
git branch -m <new-name>
git push -u origin <new-name>
Step 3 — Xóa branch cũ trên remote:
Hỏi user: "Branch cũ <old-name> còn tồn tại trên remote. Xóa không?"
- Yes →
git push origin --delete <old-name>
- No → giữ lại (nhưng warn: 2 remote branch trỏ cùng commit, có thể confuse reviewer)
Step 4 — Verify:
git branch -vv # xem local + upstream mới
git ls-remote --heads origin # check remote không còn old-name (nếu đã xóa)
Lưu ý:
- KHÔNG dùng
git branch -m thuần khi branch đã push — sẽ break upstream tracking
- Nếu đã có MR mở trên branch cũ: rename remote sẽ làm MR đứng (URL không đổi nhưng source branch không tồn tại). Phải đóng MR cũ + tạo MR mới với branch mới, hoặc dùng
glab mr update <N> --source-branch <new-name> nếu glab support
Sinh code từ mô tả task
- Khi user paste mô tả task Jira làm prompt, đọc kỹ và xác nhận lại scope trước khi code nếu có chỗ mơ hồ
- Code theo convention của project (tham khảo CLAUDE.md nếu có, hoặc đọc file gần khu vực sửa để bắt chước style)
- Không thêm tính năng/refactor ngoài scope task
- Sau khi xong, tóm tắt ngắn các file đã thay đổi
"review the last change" / "review change" (+ optional "simplify")
Trigger match là lenient: thêm từ simplify bất kỳ vị trí trong câu để bật Step 0; không có thì bỏ qua Step 0.
Step 0 — Simplify pass (chỉ chạy khi trigger chứa simplify):
Capture uncommitted + staged diff (git diff và git diff --cached). Empty → báo skip Step 0 và sang Step 1.
Scan diff theo 3 góc nhìn Reuse / Quality / Efficiency — danh sách flag chi tiết dùng chung với bảng Phase 2 của review the whole branch (xem section bên dưới). Inline Claude, không spawn agent vì scope hẹp.
Auto-fix trực tiếp mọi finding rõ ràng — false positive thì skip, không cãi, không hỏi user từng issue. Fix độc lập ở các file khác nhau → batch parallel trong 1 message.
Báo tóm tắt số issue đã fix + file đã đụng (hoặc "code đã sạch") rồi sang Step 1. KHÔNG tự commit — fix nằm ở working tree, gộp chung với review issues user fix sau.
Step 1 — Capture diff cho review: git diff (hoặc git diff HEAD nếu đã staged). Trong simplify mode, đây là diff sau-fix.
Step 2 — Review theo các tiêu chí:
- Logic đúng với mô tả task không
- Có edge case nào chưa cover không
- Có vi phạm convention/coding standard không
- Có code thừa, dead code, hoặc abstraction không cần thiết
- Có lỗ hổng bảo mật (input validation, auth bypass, injection) không
- Có ảnh hưởng performance đáng kể không
Step 3 — Báo cáo dưới dạng danh sách có đánh số: #1, #2, ... để user dễ tham chiếu khi fix.
Lưu ý: Simplify mode scope hẹp (chỉ uncommitted diff) + inline review. Diff lớn (>500 dòng) → dùng review the whole branch (3 agent song song) thay thế.
"Commit and push"
Spec đầy đủ Conventional Commits + Jira ID + push gate. Self-contained: không cần cài skill commit riêng.
Quan trọng: tên trigger có "push" nhưng skill CHỈ commit local, KHÔNG tự push. Push là hành động remote → bắt buộc hỏi user xác nhận.
Trigger phụ: thêm --quick ("commit and push --quick", "quick commit") → kích Quick mode (xem cuối section).
Inputs
| Input |
Rule |
| TASK-ID |
Auto-extract từ tên nhánh hiện tại (feature/WRA-9-... → WRA-9). Pattern [A-Z][A-Z0-9]+-\d+. Không match → STOP, hỏi user |
| Repo language |
Tiếng Việt (theo git log) — áp dụng cho subject và body |
| Detect "quick" intent |
User nói "nhanh" / "quick" / "tạm" / "small" / "fast" → suggest --quick trước khi commit |
Behavior
| Rule |
Detail |
| Probe trước khi quyết định |
Luôn chạy Step 1 đầy đủ — không skip kể cả commit nhỏ |
Không bao giờ guess type/scope |
Không chắc → STOP, hỏi user. Không coin-flip |
| Quality > speed |
1 câu hỏi xác nhận đỡ 1 commit sai format |
Process
Step 1 — Probe repo state (parallel calls trong 1 message):
| Call |
Mục đích |
git status (không -uall) |
Untracked + modified files |
git diff --cached |
Staged hunks only |
git diff |
Unstaged hunks only — tách biệt để detect partial-staging |
cat "$(git rev-parse --show-toplevel)/.commit-scopes" |
Scope allowlist (works từ subdir) |
Step 2 — Partial-staging guard:
| Khi |
Hành động |
File xuất hiện cả ở index lẫn worktree (MM trong git status) |
STOP, hỏi user |
| User: commit staged-only |
Tiến hành với index hiện tại |
| User: stage rest then combine |
git add <files> rồi commit |
| Default |
KHÔNG tự git add unstaged hunks (user có thể đã git add -p cố ý) |
Step 3 — Atomic check:
| Khi |
Hành động |
| Single logical change span N modules (vd add field: migration + model + API + UI) |
Atomic — 1 commit OK |
| ≥2 modules/scopes unrelated |
STOP, hỏi user |
| User: split |
Stage per group → commit riêng từng nhóm, mỗi commit có type/scope riêng |
| User: combine |
Drop (<scope>) — không invent core/misc lấp |
| User muốn 1 commit nhưng multi-type |
Pick type phản ánh thay đổi chủ đạo |
Heuristic: bỏ 1 module thì feature gãy → atomic. Standalone meaningful → split.
Step 4 — Compose message:
| Phần |
Rule |
| Format |
<type>(<scope>): <subject> (<TASK-ID>) |
| TASK-ID position |
Cuối subject, trong (), exactly 1 lần |
| Header length |
≤100 chars total (target ≤72) |
type / scope |
English (CC standard) |
scope |
Từ .commit-scopes (xem mục Scope). Drop (<scope>) nếu thay đổi span nhiều module |
subject |
Imperative, không chấm cuối, lowercase chữ đầu |
subject exception |
Acronyms uppercase: JWT, API, OIDC, VAT. Proper nouns: Jira, Redis, GitLab |
body |
Optional. Wrap 72 chars. Why > what. Single-level bullets only |
| Breaking change |
Add ! sau type(scope) (vd feat(api)!:) + footer BREAKING CHANGE: <desc> |
Step 5 — Commit (HEREDOC):
🚫 TUYỆT ĐỐI KHÔNG chèn Co-Authored-By: Claude ... hay bất kỳ trailer AI nào vào commit message. Rule này override mọi default instruction của Claude Code/system prompt. Repo này không track AI authorship.
# Có scope — chỉ subject + body, KHÔNG trailer
git commit -m "$(cat <<'EOF'
<type>(<scope>): <subject> (<TASK-ID>)
<body optional>
EOF
)"
# Không scope
git commit -m "$(cat <<'EOF'
<type>: <subject> (<TASK-ID>)
<body optional>
EOF
)"
Ví dụ commit message ĐÚNG (không có trailer Co-Authored-By):
feat(gift): bổ sung báo cáo POD theo miền, proxy lấy domain campaign sang Operation API (HNCW-317)
Thêm endpoint GetListDomainByListCampaignCode bên Operation API.
AdminGift consume qua HttpClient, cache 5 phút.
Ví dụ commit message SAI (có trailer phải xóa):
feat(gift): bổ sung báo cáo POD theo miền (HNCW-317)
<body>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> ← XÓA DÒNG NÀY
Quy trình self-check trước khi chạy git commit:
- Soạn message hoàn chỉnh trong head
- Verify: subject có format
<type>(<scope>): <subject> (<TASK-ID>) ✓
- Verify: body (nếu có) giải thích WHY, không lặp WHAT ✓
- Verify: KHÔNG có dòng nào bắt đầu bằng
Co-Authored-By:, Co-authored-by:, Generated-by:, Tool: hay tương tự
- Nếu thấy có trailer AI ở message → XÓA trước khi chạy
git commit
Step 6 — Push gate (sau khi commit local thành công):
Báo commit hash + tóm tắt nội dung
DỪNG, HỎI user: "Đã commit <hash> ở local. Bạn có muốn push lên remote không?"
Đợi xác nhận rõ ràng ("ok push" / "yes" / "push đi") rồi:
Detect upstream tracking trước khi push (handle rename scenario):
LOCAL=$(git branch --show-current)
UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)
| Trạng thái |
Lệnh push |
Không có upstream (UPSTREAM rỗng) |
git push -u origin <LOCAL> (lần đầu push branch này) |
UPSTREAM = origin/<LOCAL> (tên local match remote) |
git push (bình thường) |
UPSTREAM = origin/<old-name> (tên local KHÁC upstream) |
Rename scenario detected. STOP, báo user: "Local branch <LOCAL> đang track <UPSTREAM> — có vẻ branch đã được rename. Cần dùng trigger rename branch <LOCAL> để sync remote, KHÔNG nên push trực tiếp" |
Sau khi push thành công: báo URL push + gợi ý bước tiếp (vd review the whole branch hoặc create a merge request)
KHÔNG tự push kể cả khi trigger có "push" trong tên
KHÔNG ép push qua rename scenario — bắt user đi qua rename branch flow để cleanup remote đúng cách
Allowed types
| Type |
Ý nghĩa |
Version bump |
feat |
Tính năng mới |
MINOR (1.X.0) |
fix |
Sửa bug |
PATCH (1.0.X) |
perf |
Cải thiện performance |
PATCH |
refactor |
Refactor không đổi behavior |
— |
docs |
Tài liệu |
— |
test |
Thêm/sửa test |
— |
build |
Build system / dependency / packaging |
— |
style |
Format code (whitespace, lint) |
— |
chore |
Maintenance, không fit type khác |
— |
ci |
CI/CD config |
— |
revert |
Revert commit cũ |
— |
Breaking change là modifier, không phải type riêng. Suffix ! hoặc footer BREAKING CHANGE: → MAJOR bump (X.0.0).
Footer
Vị trí: sau body, ngăn bằng dòng trắng. Format: Token: value (CC) hoặc Token #issue (GitHub-style).
| Footer |
Khi dùng |
BREAKING CHANGE: <desc> |
Bắt buộc khi header có !. Mô tả impact + migration |
Closes <TASK-ID> |
Trigger Jira-GitLab auto-close khi merge. Skip nếu đã auto-close từ subject mention (kiểm tra 1-2 ticket merged gần đây để confirm) — tránh trigger 2 lần |
Refs <TASK-ID> |
Reference Jira khác (related nhưng không close) |
Co-authored-by: Name <email> |
Real pair-programming. KHÔNG auto-insert AI |
Reviewed-by: Name <email> |
Optional — chỉ nếu team convention |
| Rule |
Áp dụng |
| Đừng lặp Task ID |
Đã có trong subject (<TASK-ID>) rồi → bỏ ở footer trừ khi cần keyword Closes/Refs |
| Token case |
PascalCase hoặc kebab-case (Reviewed-by, Co-authored-by); BREAKING CHANGE uppercase per spec |
Scope
Lookup: đọc .commit-scopes ở repo root → fallback git log --pretty=format:%s | grep -oE '\([^)]+\):' | sort -u.
| Convention |
Detail |
| Case |
lowercase, kebab-case (-, không _) |
| Token count |
Prefer 1 token; compound <primary>-<sub> để narrow (vd admin-jobs, team-digest) |
| Suffix drop |
email_service → email, ai_engine → ai, Java/.NET Service/Manager tương tự |
| Quyết định new scope |
Hành động |
Synonym đã có trong .commit-scopes |
Reuse — đừng coin trùng (auth vs authentication vs login) |
| Genuinely new concept |
Add vào .commit-scopes cùng PR với commit đầu tiên dùng nó |
| Không update file được lúc đó (hotfix, fast flow) |
Drop (<scope>) (valid CC) hoặc dùng --quick. Update .commit-scopes trước khi merge |
🚫 Đừng invent generic scope (core, misc) để fill format. No-scope flags "needs categorization"; invented scope masks the gap.
.commit-scopes file: plain text — 1 scope/dòng, dòng # là comment, blank/whitespace trimmed.
Quick mode
Trigger: thêm --quick ("commit and push --quick" / "quick commit").
| Aspect |
Rule |
| Format |
<type>: <subject> (<TASK-ID>) — không scope, ever |
| Body |
Skip, kể cả meaningful |
| Header length |
≤72 chars (chặt hơn normal) |
| Mandatory |
type, TASK-ID, imperative subject, không chấm cuối |
Use for: hotfix · dep bump · typo fix · internal tool · small chore
Don't use for: feat/refactor cần why-body · breaking change · multi-module change (drop --quick, dùng no-scope normal)
Dep bump → build (build system / packaging) per CC spec, không chore. chore chỉ cho housekeeping không fit type khác.
WIP / Spike
| Element |
Rule |
| Type |
chore (always) |
| Keyword |
wip hoặc spike — lowercase, từ đầu của subject |
| Scope |
None |
| Format |
chore: <wip|spike> <desc> (<TASK-ID>) |
chore: wip refactor luồng auth (WRA-123)
chore: spike test kết nối Redis (WRA-999)
| Lifecycle |
Rule |
| WIP → main |
Bắt buộc squash/rebase trước merge. Main không bao giờ giữ chuỗi wip raw |
| Spike → main |
Giữ nếu document được decision; xóa nếu throwaway — quyết trong PR review |
| Hotfix |
KHÔNG — đó là fix: thật |
Pair tự nhiên với --quick: "commit and push --quick" (no scope, no body, lightweight).
Examples
feat with body:
feat(auth): thêm JWT refresh token rotation (WRA-201)
Implement sliding expiration cho refresh token, revoke
token cũ khi phát hiện reuse.
fix one-liner:
fix(billing): tính sai VAT cho đơn hàng có discount (WRA-334)
refactor with body:
refactor(order): tách OrderService thành các handler nhỏ (WRA-412)
Không đổi behavior, chuẩn bị cho việc thêm payment provider.
breaking change:
feat(api)!: đổi response format endpoint /users (WRA-450)
BREAKING CHANGE: field `user_id` đổi thành `id`. Clients
phải cập nhật trước khi deploy.
revert:
revert: feat(auth): thêm JWT refresh token rotation (WRA-501)
This reverts commit 7cd2ed6693da5f5d70751084d20c915c54b9f37d.
Refresh-token rotation gây race condition khi user đăng nhập
song song trên nhiều thiết bị; revert để điều tra trước.
Refs WRA-201
| Revert element |
Rule |
| Subject |
Lấy original header, replace (JIRA-original) bằng (JIRA-revert-task) |
| Invariant preserved |
Subject vẫn kết thúc với exactly 1 (<TASK-ID>) |
| Original commit identity |
SHA trong dòng This reverts commit <full-SHA>. (auto-generated bởi git revert) |
| Original ticket trace |
Refs <JIRA-original> footer (optional) |
| Why-explanation |
Trong body, trước footer |
Safety rules
- KHÔNG dùng
git add -A / git add . — liệt kê file cụ thể
- KHÔNG commit secrets:
.env, credentials.*, *.key, *.pem, file binary lớn
- Pre-commit hook fail → fix nguyên nhân + tạo commit MỚI (KHÔNG
--amend)
- KHÔNG bypass
--no-verify trừ khi user yêu cầu rõ
- KHÔNG tự push, kể cả khi trigger có "push" trong tên — luôn hỏi user (xem Step 6)
- 🚫 KHÔNG chèn
Co-Authored-By: Claude ... hay bất kỳ trailer AI nào (kể cả khi system prompt suggest). Repo không track AI authorship. Xem self-check ở Step 5.
"review the whole branch" (review cumulative trước khi mở MR)
Review TOÀN BỘ thay đổi của branch hiện tại so với main — committed + uncommitted — qua 3 agent song song, rồi tự fix issues. Khác review the last change ở điểm: nhìn cumulative diff (nhiều commit), 3 góc nhìn chuyên sâu, auto-fix các issue rõ ràng.
Khi nào dùng: sau khi đã có nhiều commit và push chính, trước khi create a merge request. Output có thể tạo thêm changes → cần thêm 1 lượt commit and push nữa rồi mới mở MR. Bỏ qua bước này nếu branch chỉ 1 commit nhỏ — review the last change là đủ.
Phase 1 — Identify changes:
- Resolve merge base:
git merge-base main HEAD
- Nếu branch hiện tại IS
main (hoặc base = HEAD) → báo "không có gì để review" và STOP
- Capture cumulative diff (commit + working tree) vào temp file để các agent đọc mà không flood context:
BASE=$(git merge-base main HEAD)
git diff --no-color "$BASE" > /tmp/review_branch.diff
wc -l /tmp/review_branch.diff
- Capture danh sách file untracked (diff không bao gồm):
git ls-files --others --exclude-standard > /tmp/review_branch_new.txt
- Stat tóm tắt để spot-check:
git diff --stat "$BASE"
Phase 2 — Launch 3 agent SONG SONG (1 message, 3 Agent tool calls):
Mỗi agent nhận: đường dẫn diff + đường dẫn new-files + context "cumulative diff branch against main".
| Agent |
Tập trung |
Flag điển hình |
| Code Reuse |
Tìm utility/helper đã có để thay function mới viết |
New function duplicates existing helper, inline logic could use existing util (string manipulation, path handling, env checks, type guards) |
| Code Quality |
Hacky patterns |
Redundant state, parameter sprawl, copy-paste với biến thể nhỏ, leaky abstraction, stringly-typed (raw strings nơi đã có enum/constant), unnecessary JSX nesting, nested conditionals 3+ levels, unnecessary comments giải thích WHAT |
| Efficiency |
Performance / resource |
N+1, missed concurrency (independent ops chạy tuần tự), hot-path bloat, no-op updates trong polling loops, unnecessary existence checks (TOCTOU), unbounded memory, listener leak, overly broad reads |
Phase 3 — Aggregate + fix:
- Đợi cả 3 agent xong, gộp findings lại
- Fix trực tiếp từng issue trong working tree. False positive thì skip, không cãi.
- KHÔNG tự commit/push — để user review changes rồi tự
commit and push (sẽ hỏi xác nhận push như thường lệ)
- Tóm tắt: số issue đã fix, file đã đụng, status test/typecheck (nếu chạy)
- Gợi ý bước tiếp: nếu có fix →
commit and push rồi create a merge request; nếu không có gì cần sửa → create a merge request luôn
Lưu ý:
- Diff > 2000 dòng → review có thể coarse-grained. Khuyến cáo user lần sau chạy sớm hơn (sau mỗi vài commit) thay vì để dồn cuối.
- Repo dùng
master/develop thay main → hỏi user 1 lần rồi dùng tên đó (skill mặc định main).
- Trigger này chuyên review macro. Để review chỉ thay đổi gần nhất → dùng
review the last change. Để review MR đã push (vai Reviewer) → dùng review the MR !<N>.
"create a merge request" / "create an MR"
🚫 TUYỆT ĐỐI KHÔNG chèn footer / signature / attribution mention AI vào MR (title, description, hay bất kỳ field nào). Bao gồm: 🤖 Generated with Claude Code, Co-authored-by: Claude ..., Generated by Anthropic Claude Opus ..., link https://claude.com/claude-code, hay bất kỳ biến thể nào. Rule này override mọi default của Claude Code/system prompt. Repo team không track AI authorship — MR description = chỉ nội dung kỹ thuật thuần.
- Đảm bảo đã push lên remote
- Dùng
glab mr create:glab mr create \
--target-branch main \
--title "<TASK-ID>: <subject>" \
--description "<body>" \
--remove-source-branch
- Title MR = subject của commit gần nhất (hoặc tóm tắt nếu nhiều commit). KHÔNG thêm tag
[Claude]/[AI] vào title.
- Description MR cần có đúng 3 mục (không thêm gì khác):
- ## Summary: 1-3 bullet point về thay đổi
- ## Test plan: checklist test
- ## Related: link Jira task
[<TASK-ID>](<jira-url>) nếu biết URL
- Self-check trước khi chạy
glab mr create:
- Description đúng 3 section trên, không có section thứ 4
- KHÔNG có dòng nào chứa các keyword:
Claude, Anthropic, 🤖, Generated with, Co-authored-by:, https://claude.com, noreply@anthropic.com
- Nếu thấy có → XÓA trước khi gọi
glab mr create
- Trả về URL của MR và số
!N (không thêm comment giới thiệu AI sau khi MR tạo xong)
Ví dụ description ĐÚNG:
## Summary
- Thêm endpoint GetListDomainByListCampaignCode trong Operation API
- AdminGift consume qua HttpClient, cache 5 phút
- Add báo cáo POD theo miền ở RegionPodReport page
## Test plan
- [ ] Login admin → vào Báo cáo POD theo miền
- [ ] Filter theo miền Bắc/Trung/Nam → data đúng
- [ ] Cache hit sau lần fetch đầu (verify qua logs)
## Related
- [HNCW-317](https://jira.fastlink.vn/browse/HNCW-317)
Ví dụ description SAI (phải xóa các dòng có ❌):
## Summary
- ...
## Test plan
- ...
## Related
- HNCW-317
--- ❌ XÓA
🤖 Generated with [Claude Code](https://claude.com/claude-code) ❌ XÓA
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> ❌ XÓA
"review the MR !" (vai trò Reviewer)
Yêu cầu glab CLI đã cài: kiểm tra glab --version
Lấy thông tin MR + comment đã có:
glab mr view <N> --comments (hiển thị cả note/discussion đã có)
BẮT BUỘC lấy diff từ remote bằng glab mr diff <N>. KHÔNG thay thế bằng git diff <base>...<source> so với branch local — main (hoặc base) ở local có thể stale, dẫn tới review nhầm hàng trăm commits đã có sẵn trên remote. Nếu thực sự cần dùng git diff (vd để lấy stat), phải git fetch origin <base-branch> trước rồi so với origin/<base-branch>, không phải branch local.
Phân nhánh theo trạng thái comment:
(A) MR CHƯA có comment review nào → review mới hoàn toàn:
- Review toàn bộ diff theo tiêu chí ở mục "review the last change"
- Liệt kê issues
#1, #2, ... mỗi issue có: file + dòng, vấn đề, đề xuất fix
- Đánh giá tổng thể: APPROVE / REQUEST_CHANGES / COMMENT
(B) MR ĐÃ có comment review trước đó → review tiếp nối, KHÔNG review lại từ đầu:
- Đọc kỹ comment cũ, trích xuất danh sách issue đã raise (
#1, #2, ...) kèm verdict gần nhất
- Xác định mốc thời gian / commit của lần review trước (lấy
created_at của note review cuối, hoặc commit SHA mà reviewer reference)
- Lấy commit mới push từ sau mốc đó:
glab mr view <N> → xem commits hoặc git log <last-reviewed-sha>..origin/<source-branch>
- Đối chiếu issue cũ: với mỗi issue
#N đã raise, kiểm tra trong commit/diff mới xem đã được fix chưa. Đánh dấu:
✓ Resolved #N — đã fix đúng
❌ Still open #N — chưa fix, hoặc fix sai/chưa đủ — kèm lý do
⚠️ Partially #N — fix một phần, kèm điều còn thiếu
- Issue mới phát sinh từ commit mới: đánh số tiếp theo (
#N+1, #N+2, ...), không tái sử dụng số cũ
- KHÔNG review lại các phần code không thay đổi từ lần review trước (trừ khi liên quan trực tiếp tới issue cũ)
- Đánh giá tổng thể dựa trên trạng thái mới: APPROVE nếu mọi issue cũ đã
✓ Resolved và không có issue mới nghiêm trọng; REQUEST_CHANGES nếu còn ❌ Still open hoặc có issue mới blocking; COMMENT cho các trường hợp còn lại
Output format thống nhất:
## Review !<N> (lần thứ <K>)
**Verdict:** APPROVE | REQUEST_CHANGES | COMMENT
### Trạng thái issue cũ ← chỉ có ở mode (B)
- ✓ Resolved #1
- ❌ Still open #2 — <lý do>
- ⚠️ Partially #3 — <còn thiếu>
### Issue mới
- #N+1 `path/to/file.js:42` — <vấn đề>. Đề xuất: <fix>
"post review result to the MR"
🚫 KHÔNG chèn AI attribution vào comment (Co-Authored-By Claude, 🤖 Generated with, link claude.com, ...). Comment = chỉ nội dung review thuần, KHÔNG signature/footer.
- Lấy chính output Markdown từ bước "review the MR" trước đó (đã đúng format, không cần soạn lại). Nếu là review tiếp nối (mode B), giữ nguyên cả phần "Trạng thái issue cũ" — đó là context quan trọng cho dev.
- Self-check trước khi
glab mr note: scan output Markdown, đảm bảo không có keyword Claude, Anthropic, 🤖, Generated with, Co-authored-by:, claude.com. Có → xóa.
- Đăng comment:
glab mr note <N> --message "<markdown>"
- Nếu APPROVE:
glab mr approve <N>
- Nếu REQUEST_CHANGES với toàn bộ issue cũ đã
✓ Resolved (chỉ còn issue mới): nói rõ trong comment để dev biết phần fix trước đã OK
"fix all issues" / "fix issue #" / "fix issues #1, #2"
- Đọc lại các issue đã raise (từ comment trên MR hoặc từ output review trước đó)
- Nếu user chỉ định số issue → chỉ fix các issue đó
- Nếu "fix all" → fix tất cả
- Sau mỗi fix, verify ngắn (chạy test/build nếu có)
- Khi hoàn tất TẤT CẢ fix, DỪNG và HỎI user trước khi commit/push:
- Tóm tắt các issue đã fix + file đã thay đổi
- Đề xuất commit message dạng:
fix(<scope>): address review issues #1,#2 (<TASK-ID>)
- Đợi user xác nhận: "ok commit" / "đổi message thành ..." / "chưa, tôi muốn xem lại trước"
- KHÔNG tự động commit/push. Chỉ thực hiện sau khi user xác nhận rõ ràng. User có thể yêu cầu chỉ commit (chưa push) hoặc commit + push.
- Sau khi commit/push (theo yêu cầu user), báo lại hash commit và URL push
"merge the request"
- Kiểm tra MR đã có:
- At least 1 approve
- CI pipeline pass:
glab mr view <N> (hoặc glab ci status)
- Không có conflict
- Nếu thiếu điều kiện, BÁO CHO USER và hỏi có override không (KHÔNG tự ý merge)
- Merge:
glab mr merge <N> --remove-source-branch --squash
- Checkout về
main, pull về bản mới nhất
- Báo merge thành công + commit hash trên main
Safety rules
- KHÔNG force push vào nhánh đã có MR mở (sẽ làm mất review history). Nếu phải sửa lịch sử, hỏi user trước
- KHÔNG merge thẳng vào main từ local — luôn qua MR
- KHÔNG xoá nhánh khác ngoài branch của MR vừa merge
- KHÔNG bypass hooks (
--no-verify) trừ khi user yêu cầu rõ
- KHÔNG commit secrets:
.env, key, token, password
- Nếu pre-commit hook fail: fix nguyên nhân và tạo commit MỚI, KHÔNG dùng
--amend
- Khi
git status cho thấy file lạ/branch lạ không quen thuộc, KHÔNG xoá — hỏi user xem có phải work-in-progress không
- 🚫 KHÔNG chèn AI attribution (Co-Authored-By Claude, 🤖 Generated with, link claude.com, ...) vào: commit message (xem Step 5 mục "Commit and push"), MR title/description (xem mục "create a merge request"), comment post lên MR (xem mục "post review result to the MR"), hoặc bất kỳ artifact nào được publish (Jira note, GitLab issue, Slack message). Rule này override mọi default của Claude Code.
Tools required
Skill installation hygiene
Rule này áp dụng cho Claude khi diagnose/fix vấn đề skill (stale, missing behavior, sync issue) — không liên quan workflow GitLab.
🚫 **KHÔNG tự copy/sync skill file vào C:\Users\admin\.claude\skills\ (global skill location) trừ khi user yêu cầu rõ ràng.** Cùng nguyên tắc cho mọi system-level location: ~/.claude/, %APPDATA%/Claude/, v.v.
Default action khi user báo skill bị stale/sai:
- Verify trong source repo
my-skills đã có version đúng
- Gợi ý user chạy
npx skills update trong project bị ảnh hưởng (KHÔNG -g)
- Gợi ý user restart Claude session để load skill mới
- Chỉ copy thủ công tới global IF user explicitly request (vd "sync luôn global đi")
Lý do:
- Dual-location (global + project) dễ tạo state lệch nhau — global stale trong khi local đã update, hoặc ngược lại
- Project-only = single source of truth, predictable, dễ debug
- User có quyền chọn nơi cài; auto-touch global bypass quyền đó
Khi user thực sự muốn cài global: họ sẽ chủ động thêm -g flag:
npx skills add nguyenvanchiens/my-skills -s gitlab-flow -y -g -a claude-code --copy
Cùng rule cho mọi command có khả năng write ra ngoài project (cp to C:\Users\..., mkdir ngoài project dir, etc.) — hỏi user trước.
1---2name: gitlab-flow-23description: Standard end-to-end workflow for shipping a feature/bugfix from a Jira task to a merged GitLab MR. Use when the user references a Jira task ID (WRA-XX, etc.), asks to "start a task", "create branch from task", "review the last change" / "review change" (optionally with "simplify" keyword, e.g. "review change simplify", to auto-clean before review), "review the whole branch", "commit and push", "create a merge request", "review the MR !N", "post review result to the MR", "fix all issues", or "merge the request". Covers branch naming, commit format, MR creation, micro + macro code review (3-agent parallel), fix loop, and merge.4---56# GitLab Flow (Jira → Code → MR → Merge)78Quy trình chuẩn cho một feature/bugfix mới. Có 2 vai trò: **Developer** (người làm task) và **Reviewer** (người review MR). Skill này hướng dẫn Claude thực hiện đúng từng bước theo prompt mà user gọi.910## Conventions1112### Branch naming13- **Default: mọi branch dùng `feature/`** — bất kể task là feature, bug fix, hay hotfix.14- Format: `feature/<TASK-ID>-<short-desc>`15- Bug-fix branches dưới `feature/`: mô tả **trạng thái bug** bằng direction marker (`Duplicate`, `Stale`, `Missing`, `Broken`, `Wrong`, `Slow`) thay vì verb "Fix" — vd `feature/HNCW-311-Duplicate-survey-log`16- **Override**: user chủ động gõ `bugfix/...` hoặc `hotfix/...` trong prompt (Mode A) → skill respect và tạo đúng prefix đó. Skill **KHÔNG** tự động chọn `bugfix/` hay `hotfix/` dựa trên nội dung task.1718**Quy tắc `<short-desc>`** (đủ để hiểu task ở first glance, chi tiết để Jira giữ):1920| Rule | Detail |21|---|---|22| Độ dài tổng | ≤ 50 ký tự cả branch (target ≤ 40). Vượt → rút thêm |23| Số từ | 2-4 từ key. Filler bị drop |24| Ngôn ngữ | Tiếng Việt không dấu, kebab-case (`-` ngăn cách) |25| Capitalization | **Sentence case STRICT**: chỉ chữ cái đầu của từ đầu tiên trong description viết hoa. **Mọi từ sau (KỂ CẢ viết tắt như `NVKD`, `VAT`, `API`, `JWT`)** đều lowercase. Vd `Bao-cao-ngay-nvkd` (KHÔNG `Bao-cao-ngay-NVKD`), `Vat-discount` (KHÔNG `VAT-discount`), `Gioi-han-domain-account`. TASK-ID giữ nguyên uppercase per Jira convention |26| Drop **type filler** | "Cai-tien", "Update", "Improve", "Fix", "Sua", "Sua-loi", "Them", "Tao", "Add", "Create", "Bo-sung" — đều bỏ. Với bug fix, mô tả **trạng thái bug** (`Duplicate`, `Stale`, `Missing`, `Broken`) thay vì verb "Fix" |27| **KEEP direction marker** | "Cho-phep"/"Allow", "Khong-cho-phep"/"Disallow", "Validate", "Block", "Restrict", "Enforce" — chúng nói **WHAT** behavior. Không có chúng → ambiguous (allow? disallow? validate?) |28| **KEEP context marker** | "Show"/"Display"/"Hide" (UI layer), "Filter"/"Sort"/"Search"/"Calculate" (logic layer), "Sync"/"Migrate"/"Schedule"/"Export"/"Import" (system layer) — chúng nói **TẦNG/CÁCH THỨC** của feature, mà `feature/` prefix không cover. Vd `Show-order-info` rõ hơn `Order-info` (display? backend? API?) |29| Drop scope marker | Tag dạng `[Supermarket - AU]` ở đầu task title KHÔNG đưa vào branch (giữ cho commit scope) |30| Drop constraint phụ | Implementation detail như "áp dụng cho sp non-weight" — bỏ. Đó thuộc commit body / Jira description |31| Ưu tiên giữ | **Direction/Context + Action/Object + Phạm vi** (vd `Allow-qty-0-checkin-checkout`, `Show-order-info-uber-doordash`). Mục tiêu: đọc 1 phát hiểu ngay, không cần Jira |3233**Ví dụ áp dụng**:3435| Task title (Jira) | ✓ Good branch | ✗ Quá dài / sai |36|---|---|---|37| `WRA-40 Giới hạn domain account khi login` | `feature/WRA-40-Gioi-han-domain` | `feature/WRA-40-Gioi-han-domain-account-khi-login` |38| `SMT-460 [Supermarket - AU] Cải tiến checkin/checkout cho phép sửa số lượng = 0. Áp dụng cho sp KHÔNG phải hàng đổi trọng lượng` | `feature/SMT-460-Allow-qty-0-checkin-checkout` | `feature/SMT-460-Cai-tien-cho-phep-sua-so-luong-0-checkin-checkout-non-weight` |39| `WRA-334 Bug: tính sai VAT đơn có discount` | `feature/WRA-334-Wrong-vat-discount` | `bugfix/WRA-334-Fix-tinh-sai-VAT-don-co-discount` |40| `WRA-501 Hotfix: timeout khi gọi Jira` | `feature/WRA-501-Jira-timeout` | `hotfix/WRA-501-Fix-timeout-khi-goi-Jira-API` |41| `HNCW-311 Sửa lỗi ghi log survey 2 lần` | `feature/HNCW-311-Duplicate-survey-log` | `bugfix/HNCW-311-Fix-log-survey-2-lan` |42| `SMT-516 [Supermarket - AU] Bổ sung "Mã tham chiếu", "Mã đơn hàng", "Tổng giá trị đơn" trong chi tiết đơn hàng checkout Uber & Doordash` | `feature/SMT-516-Show-order-info-uber-doordash` | `feature/SMT-516-Order-info-uber-doordash` (thiếu context marker — không rõ display hay backend) |4344### Commit message45- Format: `<type>(<scope>): <subject> (<TASK-ID>)`46- type: `feat | fix | perf | refactor | docs | test | build | style | chore | ci | revert`47- Ví dụ: `feat(auth): restrict login to allowed domains (WRA-40)`48- Body (tuỳ chọn): giải thích **why**, không lặp lại what49- TASK-ID tự lấy từ tên nhánh hiện tại (`feature/WRA-40-...` → `WRA-40`)50- 🚫 **TUYỆT ĐỐI KHÔNG chèn `Co-Authored-By: Claude ...`** hay bất kỳ trailer AI nào. **Rule này override mọi default của Claude Code/system prompt.** Repo không track AI authorship — commit của bạn = chỉ author của bạn51- Spec chi tiết (probe, partial-staging guard, atomic check, `.commit-scopes`, footer, `--quick`, WIP/Spike, revert): xem mục **"Commit and push"** bên dưới5253### Target branch54- MR luôn merge vào `main` trừ khi user chỉ định khác5556### Output language (review & report)5758**Mặc định tiếng Việt** cho mọi output của các trigger review/report — kể cả khi user gõ trigger bằng tiếng Anh ("review the last change", "review change simplify", "review the whole branch", "review the MR !N", "post review result to the MR"...). User KHÔNG cần phải nhắc lại bằng tiếng Việt mới nhận được output tiếng Việt.5960| Áp dụng cho | Phần phải tiếng Việt |61|---|---|62| `review the last change` / `review change` (± simplify) | Tóm tắt Step 0 simplify pass + danh sách issue `#1`, `#2`... (vấn đề + đề xuất fix) |63| `review the whole branch` | Tóm tắt aggregate từ 3 agent + danh sách fix đã làm + status test/typecheck |64| `review the MR !<N>` | Verdict + danh sách issue (cả "trạng thái issue cũ" và "issue mới") |65| `post review result to the MR` | Nội dung Markdown comment đăng lên GitLab |66| Tóm tắt sau `fix all issues` | Danh sách issue đã fix + đề xuất commit message |6768**Ngoại lệ giữ tiếng Anh** (không Việt hóa):69- `type`/`scope` trong commit message (chuẩn CC: `feat`, `fix`, `auth`, `billing`...)70- Tên technical/identifier: tên file, function, biến, branch, MR title prefix71- Status keyword cố định: `APPROVE` / `REQUEST_CHANGES` / `COMMENT`, `✓ Resolved` / `❌ Still open` / `⚠️ Partially`72- Tên agent / role / tool: `Reuse`, `Quality`, `Efficiency`, `glab`, `git`7374**Switch language**: user trả lời / tiếp tục bằng ngôn ngữ khác (English chẳng hạn) → từ message đó trở đi mới đổi sang ngôn ngữ user dùng. Không tự đoán "trigger English ⇒ output English".7576## Triggers & Procedures7778### "create branch <name>" hoặc "create branch from task <TASK-ID>..."7980**Step 1 — Detect input mode** (parse phần text sau `create branch ...`):8182| Input pattern | Mode | Hành động |83|---|---|---|84| Có prefix branch type + slug, vd `feature/HNCW-313-Bao-cao-ngay-nvkd` | **A — Full branch** | Dùng **nguyên si**, KHÔNG đề xuất, KHÔNG sửa (kể cả nếu input violate convention — chỉ warn) |85| Slug kebab-case không prefix, vd `HNCW-313-Bao-cao-ngay-nvkd` | **B — Pre-formatted slug** | Auto thêm `feature/` (convention nội bộ chỉ dùng `feature/`). **KHÔNG** bóc tách lại |86| Raw Jira title (có dấu / space / `[...]` / `(...)`), vd `HNCW-313 [Vận hành] Tạo báo cáo ngày cho NVKD(IT-10212)` | **C — Raw title** | Bóc tách → đề xuất 1-2 candidate → hỏi user pick |87| Chỉ TASK-ID, vd `HNCW-313` | **D — Bare ID** | Hỏi user description ngắn (2-4 từ) |8889**Technical detection** — phần text sau `<TASK-ID>`:90- Match `^-[A-Za-z0-9-]+$` (gạch đầu, alphanumeric + gạch nối, không space/dấu) → **Mode B**91- Match `^/[A-Za-z0-9-/]+$` với prefix `feature|bugfix|hotfix/` → **Mode A**92- Có space / dấu tiếng Việt / `[`, `(`, ... → **Mode C**93- Trống → **Mode D**9495> **NGUYÊN TẮC**: Mode A và B = user đã chủ động format → **respect tuyệt đối**, không tự sinh khác. Mode C và D mới được phép bóc tách + đề xuất.9697**Step 2 — Bóc tách** (chỉ Mode C):9899- Tách `TASK-ID` (pattern `[A-Z][A-Z0-9]+-\d+`)100- **Branch type: luôn `feature/`** — bất kể task là feature, bug fix, hay hotfix. Convention nội bộ chỉ dùng 1 prefix. Chỉ tạo `bugfix/` hoặc `hotfix/` khi user **chủ động gõ rõ** prefix đó trong Mode A (vd `create branch from task bugfix/HNCW-311-Duplicate-survey-log`).101- Bỏ scope marker đầu title (`[Supermarket - AU]`, `[Mobile]`...)102- Bỏ reference ticket khác (`(IT-12468)`, `(linked WRA-9)`)103- Drop type filler (xem rule mục Branch naming)104- **KEEP direction marker** (`Cho-phep`, `Allow`, `Validate`, `Block`, `Disallow`, `Restrict`, `Enforce`)105- Lấy 2-4 từ key: **direction + action + phạm vi**106107**Step 3 — Đề xuất** (Mode C, D):108109- Đưa 1-2 candidate kèm length character count110- **DỪNG, hỏi user pick option nào** (hoặc override description bằng tên user tự gõ)111- **KHÔNG được tự tạo branch** trước khi user xác nhận. Tránh tình huống user phải rename sau112113**Step 4 — Tạo branch** (mọi mode):1141151. Đảm bảo working tree sạch (`git status`); có thay đổi chưa commit → hỏi user trước khi tiếp tục1162. Checkout `main`, pull về bản mới nhất: `git fetch origin main && git checkout main && git pull`1173. Tạo branch:118 - Mode A/B: `git checkout -b <input-nguyên-si>` (Mode B: thêm prefix `feature/` mặc định)119 - Mode C/D: `git checkout -b <branch-user-pick>` (chỉ sau khi user đã chọn ở Step 3)1204. Báo lại tên branch + length character count121122**Edge case**:123124| Tình huống | Xử lý |125|---|---|126| Mode A/B branch >50 chars | Warn user nhưng **KHÔNG ép sửa** — user đã chủ động chọn |127| Mode C sau khi trim vẫn >50 chars | Đề xuất viết tắt (`qty` thay `so-luong`, `co` thay `checkout`) hoặc bỏ phạm vi |128| TASK-ID không match pattern `[A-Z][A-Z0-9]+-\d+` | STOP, hỏi user |129| Cần branch type khác `feature/` | User phải **gõ rõ prefix** trong input, vd `create branch from task bugfix/HNCW-311-Duplicate-survey-log` (Mode A — skill dùng nguyên si). Skill **KHÔNG** tự suy đoán `bugfix/`/`hotfix/` từ nội dung task |130| User muốn đổi tên branch sau khi skill đã tạo | Dùng trigger riêng `rename branch <new-name>` (xem mục bên dưới). Không tự rename bằng `git branch -m` mà không update upstream → sẽ phá `commit and push` |131132### "rename branch <new-name>" hoặc "rename branch sang <new-name>"133134User không thích tên branch skill vừa tạo và muốn đổi. Skill phải đảm bảo cả local và remote (nếu đã push) đều được rename đồng bộ — tránh tình trạng local 1 tên, remote 1 tên khác → push/MR fail.135136**Step 1 — Detect trạng thái**:137138```bash139git branch --show-current # tên local hiện tại140git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null # upstream (nếu có)141```142143| Trạng thái | Hành động |144|---|---|145| Branch chưa push (chưa có upstream) | Rename local thuần: `git branch -m <new-name>`. Xong, không cần đụng remote |146| Branch đã push (có upstream) | Cần rename cả 2 phía (Step 2-3) |147148**Step 2 — Rename local + push tên mới**:149150```bash151git branch -m <new-name>152git push -u origin <new-name>153```154155**Step 3 — Xóa branch cũ trên remote**:156157Hỏi user: "Branch cũ `<old-name>` còn tồn tại trên remote. Xóa không?"158- Yes → `git push origin --delete <old-name>`159- No → giữ lại (nhưng warn: 2 remote branch trỏ cùng commit, có thể confuse reviewer)160161**Step 4 — Verify**:162```bash163git branch -vv # xem local + upstream mới164git ls-remote --heads origin # check remote không còn old-name (nếu đã xóa)165```166167**Lưu ý**:168- KHÔNG dùng `git branch -m` thuần khi branch đã push — sẽ break upstream tracking169- Nếu đã có MR mở trên branch cũ: rename remote sẽ làm MR đứng (URL không đổi nhưng source branch không tồn tại). Phải đóng MR cũ + tạo MR mới với branch mới, hoặc dùng `glab mr update <N> --source-branch <new-name>` nếu glab support170171### Sinh code từ mô tả task172- Khi user paste mô tả task Jira làm prompt, đọc kỹ và xác nhận lại scope trước khi code nếu có chỗ mơ hồ173- Code theo convention của project (tham khảo CLAUDE.md nếu có, hoặc đọc file gần khu vực sửa để bắt chước style)174- Không thêm tính năng/refactor ngoài scope task175- Sau khi xong, tóm tắt ngắn các file đã thay đổi176177### "review the last change" / "review change" (+ optional "simplify")178179Trigger match là lenient: thêm từ `simplify` bất kỳ vị trí trong câu để bật Step 0; không có thì bỏ qua Step 0.180181**Step 0 — Simplify pass** (chỉ chạy khi trigger chứa `simplify`):1821831. Capture uncommitted + staged diff (`git diff` và `git diff --cached`). Empty → báo skip Step 0 và sang Step 1.1841852. Scan diff theo 3 góc nhìn **Reuse / Quality / Efficiency** — danh sách flag chi tiết dùng chung với bảng Phase 2 của `review the whole branch` (xem section bên dưới). Inline Claude, không spawn agent vì scope hẹp.1861873. **Auto-fix trực tiếp** mọi finding rõ ràng — false positive thì skip, không cãi, không hỏi user từng issue. Fix độc lập ở các file khác nhau → batch parallel trong 1 message.1881894. Báo tóm tắt số issue đã fix + file đã đụng (hoặc "code đã sạch") rồi sang Step 1. **KHÔNG tự commit** — fix nằm ở working tree, gộp chung với review issues user fix sau.190191**Step 1 — Capture diff** cho review: `git diff` (hoặc `git diff HEAD` nếu đã staged). Trong simplify mode, đây là diff sau-fix.192193**Step 2 — Review** theo các tiêu chí:194- Logic đúng với mô tả task không195- Có edge case nào chưa cover không196- Có vi phạm convention/coding standard không197- Có code thừa, dead code, hoặc abstraction không cần thiết198- Có lỗ hổng bảo mật (input validation, auth bypass, injection) không199- Có ảnh hưởng performance đáng kể không200201**Step 3 — Báo cáo** dưới dạng danh sách có đánh số: `#1`, `#2`, ... để user dễ tham chiếu khi fix.202203**Lưu ý**: Simplify mode scope hẹp (chỉ uncommitted diff) + inline review. Diff lớn (>500 dòng) → dùng `review the whole branch` (3 agent song song) thay thế.204205### "Commit and push"206207Spec đầy đủ Conventional Commits + Jira ID + push gate. Self-contained: không cần cài skill `commit` riêng.208209> **Quan trọng**: tên trigger có "push" nhưng skill **CHỈ commit local**, KHÔNG tự push. Push là hành động remote → bắt buộc hỏi user xác nhận.210211**Trigger phụ**: thêm `--quick` ("commit and push --quick", "quick commit") → kích Quick mode (xem cuối section).212213#### Inputs214215| Input | Rule |216|---|---|217| TASK-ID | Auto-extract từ tên nhánh hiện tại (`feature/WRA-9-...` → `WRA-9`). Pattern `[A-Z][A-Z0-9]+-\d+`. Không match → STOP, hỏi user |218| Repo language | Tiếng Việt (theo `git log`) — áp dụng cho `subject` và `body` |219| Detect "quick" intent | User nói "nhanh" / "quick" / "tạm" / "small" / "fast" → suggest `--quick` trước khi commit |220221#### Behavior222223| Rule | Detail |224|---|---|225| Probe trước khi quyết định | Luôn chạy Step 1 đầy đủ — không skip kể cả commit nhỏ |226| Không bao giờ guess `type`/`scope` | Không chắc → STOP, hỏi user. Không coin-flip |227| Quality > speed | 1 câu hỏi xác nhận đỡ 1 commit sai format |228229#### Process230231**Step 1 — Probe repo state** (parallel calls trong 1 message):232233| Call | Mục đích |234|---|---|235| `git status` (không `-uall`) | Untracked + modified files |236| `git diff --cached` | Staged hunks only |237| `git diff` | Unstaged hunks only — tách biệt để detect partial-staging |238| `cat "$(git rev-parse --show-toplevel)/.commit-scopes"` | Scope allowlist (works từ subdir) |239240**Step 2 — Partial-staging guard**:241242| Khi | Hành động |243|---|---|244| File xuất hiện cả ở index lẫn worktree (`MM` trong `git status`) | STOP, hỏi user |245| User: commit staged-only | Tiến hành với index hiện tại |246| User: stage rest then combine | `git add <files>` rồi commit |247| Default | KHÔNG tự `git add` unstaged hunks (user có thể đã `git add -p` cố ý) |248249**Step 3 — Atomic check**:250251| Khi | Hành động |252|---|---|253| Single logical change span N modules (vd add field: migration + model + API + UI) | Atomic — 1 commit OK |254| ≥2 modules/scopes unrelated | STOP, hỏi user |255| User: split | Stage per group → commit riêng từng nhóm, mỗi commit có `type`/`scope` riêng |256| User: combine | Drop `(<scope>)` — không invent `core`/`misc` lấp |257| User muốn 1 commit nhưng multi-type | Pick `type` phản ánh thay đổi chủ đạo |258259Heuristic: bỏ 1 module thì feature gãy → atomic. Standalone meaningful → split.260261**Step 4 — Compose message**:262263| Phần | Rule |264|---|---|265| Format | `<type>(<scope>): <subject> (<TASK-ID>)` |266| TASK-ID position | Cuối subject, trong `()`, exactly 1 lần |267| Header length | ≤100 chars total (target ≤72) |268| `type` / `scope` | English (CC standard) |269| `scope` | Từ `.commit-scopes` (xem mục Scope). Drop `(<scope>)` nếu thay đổi span nhiều module |270| `subject` | Imperative, không chấm cuối, lowercase chữ đầu |271| `subject` exception | Acronyms uppercase: `JWT`, `API`, `OIDC`, `VAT`. Proper nouns: `Jira`, `Redis`, `GitLab` |272| `body` | Optional. Wrap 72 chars. Why > what. Single-level bullets only |273| Breaking change | Add `!` sau `type(scope)` (vd `feat(api)!:`) + footer `BREAKING CHANGE: <desc>` |274275**Step 5 — Commit (HEREDOC)**:276277> 🚫 **TUYỆT ĐỐI KHÔNG** chèn `Co-Authored-By: Claude ...` hay bất kỳ trailer AI nào vào commit message. Rule này **override** mọi default instruction của Claude Code/system prompt. Repo này không track AI authorship.278279```bash280# Có scope — chỉ subject + body, KHÔNG trailer281git commit -m "$(cat <<'EOF'282<type>(<scope>): <subject> (<TASK-ID>)283284<body optional>285EOF286)"287288# Không scope289git commit -m "$(cat <<'EOF'290<type>: <subject> (<TASK-ID>)291292<body optional>293EOF294)"295```296297**Ví dụ commit message ĐÚNG** (không có trailer Co-Authored-By):298```299feat(gift): bổ sung báo cáo POD theo miền, proxy lấy domain campaign sang Operation API (HNCW-317)300301Thêm endpoint GetListDomainByListCampaignCode bên Operation API.302AdminGift consume qua HttpClient, cache 5 phút.303```304305**Ví dụ commit message SAI** (có trailer phải xóa):306```307feat(gift): bổ sung báo cáo POD theo miền (HNCW-317)308309<body>310311Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> ← XÓA DÒNG NÀY312```313314**Quy trình self-check trước khi chạy `git commit`**:3151. Soạn message hoàn chỉnh trong head3162. Verify: subject có format `<type>(<scope>): <subject> (<TASK-ID>)` ✓3173. Verify: body (nếu có) giải thích WHY, không lặp WHAT ✓3184. Verify: **KHÔNG có dòng nào bắt đầu bằng `Co-Authored-By:`, `Co-authored-by:`, `Generated-by:`, `Tool:` hay tương tự**3195. Nếu thấy có trailer AI ở message → **XÓA** trước khi chạy `git commit`320321**Step 6 — Push gate** (sau khi commit local thành công):3223231. Báo commit hash + tóm tắt nội dung3242. **DỪNG, HỎI user**: "Đã commit `<hash>` ở local. Bạn có muốn push lên remote không?"3253. Đợi xác nhận rõ ràng ("ok push" / "yes" / "push đi") rồi:3264. **Detect upstream tracking trước khi push** (handle rename scenario):327 ```bash328 LOCAL=$(git branch --show-current)329 UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)330 ```331332 | Trạng thái | Lệnh push |333 |---|---|334 | Không có upstream (`UPSTREAM` rỗng) | `git push -u origin <LOCAL>` (lần đầu push branch này) |335 | `UPSTREAM` = `origin/<LOCAL>` (tên local match remote) | `git push` (bình thường) |336 | `UPSTREAM` = `origin/<old-name>` (tên local KHÁC upstream) | **Rename scenario detected**. STOP, báo user: "Local branch `<LOCAL>` đang track `<UPSTREAM>` — có vẻ branch đã được rename. Cần dùng trigger `rename branch <LOCAL>` để sync remote, KHÔNG nên push trực tiếp" |3373385. Sau khi push thành công: báo URL push + gợi ý bước tiếp (vd `review the whole branch` hoặc `create a merge request`)3396. **KHÔNG tự push** kể cả khi trigger có "push" trong tên3407. **KHÔNG ép push qua rename scenario** — bắt user đi qua `rename branch` flow để cleanup remote đúng cách341342#### Allowed types343344| Type | Ý nghĩa | Version bump |345|---|---|---|346| `feat` | Tính năng mới | MINOR (1.X.0) |347| `fix` | Sửa bug | PATCH (1.0.X) |348| `perf` | Cải thiện performance | PATCH |349| `refactor` | Refactor không đổi behavior | — |350| `docs` | Tài liệu | — |351| `test` | Thêm/sửa test | — |352| `build` | Build system / dependency / packaging | — |353| `style` | Format code (whitespace, lint) | — |354| `chore` | Maintenance, không fit type khác | — |355| `ci` | CI/CD config | — |356| `revert` | Revert commit cũ | — |357358> Breaking change là *modifier*, không phải type riêng. Suffix `!` hoặc footer `BREAKING CHANGE:` → MAJOR bump (X.0.0).359360#### Footer361362Vị trí: sau body, ngăn bằng dòng trắng. Format: `Token: value` (CC) hoặc `Token #issue` (GitHub-style).363364| Footer | Khi dùng |365|---|---|366| `BREAKING CHANGE: <desc>` | Bắt buộc khi header có `!`. Mô tả impact + migration |367| `Closes <TASK-ID>` | Trigger Jira-GitLab auto-close khi merge. Skip nếu đã auto-close từ subject mention (kiểm tra 1-2 ticket merged gần đây để confirm) — tránh trigger 2 lần |368| `Refs <TASK-ID>` | Reference Jira khác (related nhưng không close) |369| `Co-authored-by: Name <email>` | Real pair-programming. KHÔNG auto-insert AI |370| `Reviewed-by: Name <email>` | Optional — chỉ nếu team convention |371372| Rule | Áp dụng |373|---|---|374| Đừng lặp Task ID | Đã có trong subject `(<TASK-ID>)` rồi → bỏ ở footer trừ khi cần keyword `Closes`/`Refs` |375| Token case | PascalCase hoặc kebab-case (`Reviewed-by`, `Co-authored-by`); `BREAKING CHANGE` uppercase per spec |376377#### Scope378379**Lookup**: đọc `.commit-scopes` ở repo root → fallback `git log --pretty=format:%s | grep -oE '\([^)]+\):' | sort -u`.380381| Convention | Detail |382|---|---|383| Case | lowercase, kebab-case (`-`, không `_`) |384| Token count | Prefer 1 token; compound `<primary>-<sub>` để narrow (vd `admin-jobs`, `team-digest`) |385| Suffix drop | `email_service` → `email`, `ai_engine` → `ai`, Java/.NET `Service`/`Manager` tương tự |386387| Quyết định new scope | Hành động |388|---|---|389| Synonym đã có trong `.commit-scopes` | Reuse — đừng coin trùng (`auth` vs `authentication` vs `login`) |390| Genuinely new concept | Add vào `.commit-scopes` cùng PR với commit đầu tiên dùng nó |391| Không update file được lúc đó (hotfix, fast flow) | Drop `(<scope>)` (valid CC) hoặc dùng `--quick`. Update `.commit-scopes` trước khi merge |392393> 🚫 Đừng invent generic scope (`core`, `misc`) để fill format. No-scope flags "needs categorization"; invented scope masks the gap.394395**`.commit-scopes` file**: plain text — 1 scope/dòng, dòng `#` là comment, blank/whitespace trimmed.396397#### Quick mode398399**Trigger**: thêm `--quick` ("commit and push --quick" / "quick commit").400401| Aspect | Rule |402|---|---|403| Format | `<type>: <subject> (<TASK-ID>)` — không scope, ever |404| Body | Skip, kể cả meaningful |405| Header length | ≤72 chars (chặt hơn normal) |406| Mandatory | `type`, TASK-ID, imperative subject, không chấm cuối |407408**Use for**: hotfix · dep bump · typo fix · internal tool · small chore409**Don't use for**: `feat`/`refactor` cần why-body · breaking change · multi-module change (drop `--quick`, dùng no-scope normal)410411> Dep bump → `build` (build system / packaging) per CC spec, không `chore`. `chore` chỉ cho housekeeping không fit type khác.412413#### WIP / Spike414415| Element | Rule |416|---|---|417| Type | `chore` (always) |418| Keyword | `wip` hoặc `spike` — lowercase, từ đầu của subject |419| Scope | None |420| Format | `chore: <wip\|spike> <desc> (<TASK-ID>)` |421422```423chore: wip refactor luồng auth (WRA-123)424chore: spike test kết nối Redis (WRA-999)425```426427| Lifecycle | Rule |428|---|---|429| WIP → main | **Bắt buộc** squash/rebase trước merge. Main không bao giờ giữ chuỗi `wip` raw |430| Spike → main | Giữ nếu document được decision; xóa nếu throwaway — quyết trong PR review |431| Hotfix | KHÔNG — đó là `fix:` thật |432433> Pair tự nhiên với `--quick`: "commit and push --quick" (no scope, no body, lightweight).434435#### Examples436437**feat with body**:438```439feat(auth): thêm JWT refresh token rotation (WRA-201)440441Implement sliding expiration cho refresh token, revoke442token cũ khi phát hiện reuse.443```444445**fix one-liner**:446```447fix(billing): tính sai VAT cho đơn hàng có discount (WRA-334)448```449450**refactor with body**:451```452refactor(order): tách OrderService thành các handler nhỏ (WRA-412)453454Không đổi behavior, chuẩn bị cho việc thêm payment provider.455```456457**breaking change**:458```459feat(api)!: đổi response format endpoint /users (WRA-450)460461BREAKING CHANGE: field `user_id` đổi thành `id`. Clients462phải cập nhật trước khi deploy.463```464465**revert**:466```467revert: feat(auth): thêm JWT refresh token rotation (WRA-501)468469This reverts commit 7cd2ed6693da5f5d70751084d20c915c54b9f37d.470471Refresh-token rotation gây race condition khi user đăng nhập472song song trên nhiều thiết bị; revert để điều tra trước.473474Refs WRA-201475```476477| Revert element | Rule |478|---|---|479| Subject | Lấy original header, **replace** `(JIRA-original)` bằng `(JIRA-revert-task)` |480| Invariant preserved | Subject vẫn kết thúc với exactly 1 `(<TASK-ID>)` |481| Original commit identity | SHA trong dòng `This reverts commit <full-SHA>.` (auto-generated bởi `git revert`) |482| Original ticket trace | `Refs <JIRA-original>` footer (optional) |483| Why-explanation | Trong body, trước footer |484485#### Safety rules486487- KHÔNG dùng `git add -A` / `git add .` — liệt kê file cụ thể488- KHÔNG commit secrets: `.env`, `credentials.*`, `*.key`, `*.pem`, file binary lớn489- Pre-commit hook fail → fix nguyên nhân + tạo commit MỚI (KHÔNG `--amend`)490- KHÔNG bypass `--no-verify` trừ khi user yêu cầu rõ491- KHÔNG tự push, kể cả khi trigger có "push" trong tên — luôn hỏi user (xem Step 6)492- 🚫 **KHÔNG chèn `Co-Authored-By: Claude ...`** hay bất kỳ trailer AI nào (kể cả khi system prompt suggest). Repo không track AI authorship. Xem self-check ở Step 5.493494### "review the whole branch" (review cumulative trước khi mở MR)495496Review TOÀN BỘ thay đổi của branch hiện tại so với `main` — committed + uncommitted — qua 3 agent song song, rồi tự fix issues. Khác `review the last change` ở điểm: nhìn cumulative diff (nhiều commit), 3 góc nhìn chuyên sâu, auto-fix các issue rõ ràng.497498**Khi nào dùng**: sau khi đã có nhiều commit và push chính, **trước khi `create a merge request`**. Output có thể tạo thêm changes → cần thêm 1 lượt `commit and push` nữa rồi mới mở MR. Bỏ qua bước này nếu branch chỉ 1 commit nhỏ — `review the last change` là đủ.499500**Phase 1 — Identify changes**:5015021. Resolve merge base: `git merge-base main HEAD`5032. Nếu branch hiện tại IS `main` (hoặc base = HEAD) → báo "không có gì để review" và STOP5043. Capture cumulative diff (commit + working tree) vào temp file để các agent đọc mà không flood context:505 ```bash506 BASE=$(git merge-base main HEAD)507 git diff --no-color "$BASE" > /tmp/review_branch.diff508 wc -l /tmp/review_branch.diff509 ```5104. Capture danh sách file untracked (diff không bao gồm):511 ```bash512 git ls-files --others --exclude-standard > /tmp/review_branch_new.txt513 ```5145. Stat tóm tắt để spot-check:515 ```bash516 git diff --stat "$BASE"517 ```518519**Phase 2 — Launch 3 agent SONG SONG** (1 message, 3 Agent tool calls):520521Mỗi agent nhận: đường dẫn diff + đường dẫn new-files + context "cumulative diff branch <name> against main".522523| Agent | Tập trung | Flag điển hình |524|---|---|---|525| **Code Reuse** | Tìm utility/helper đã có để thay function mới viết | New function duplicates existing helper, inline logic could use existing util (string manipulation, path handling, env checks, type guards) |526| **Code Quality** | Hacky patterns | Redundant state, parameter sprawl, copy-paste với biến thể nhỏ, leaky abstraction, stringly-typed (raw strings nơi đã có enum/constant), unnecessary JSX nesting, nested conditionals 3+ levels, unnecessary comments giải thích WHAT |527| **Efficiency** | Performance / resource | N+1, missed concurrency (independent ops chạy tuần tự), hot-path bloat, no-op updates trong polling loops, unnecessary existence checks (TOCTOU), unbounded memory, listener leak, overly broad reads |528529**Phase 3 — Aggregate + fix**:5305311. Đợi cả 3 agent xong, gộp findings lại5322. Fix trực tiếp từng issue trong working tree. False positive thì skip, không cãi.5333. **KHÔNG tự commit/push** — để user review changes rồi tự `commit and push` (sẽ hỏi xác nhận push như thường lệ)5344. Tóm tắt: số issue đã fix, file đã đụng, status test/typecheck (nếu chạy)5355. Gợi ý bước tiếp: nếu có fix → `commit and push` rồi `create a merge request`; nếu không có gì cần sửa → `create a merge request` luôn536537**Lưu ý**:538- Diff > 2000 dòng → review có thể coarse-grained. Khuyến cáo user lần sau chạy sớm hơn (sau mỗi vài commit) thay vì để dồn cuối.539- Repo dùng `master`/`develop` thay `main` → hỏi user 1 lần rồi dùng tên đó (skill mặc định `main`).540- Trigger này chuyên review macro. Để review chỉ thay đổi gần nhất → dùng `review the last change`. Để review MR đã push (vai Reviewer) → dùng `review the MR !<N>`.541542### "create a merge request" / "create an MR"543544> 🚫 **TUYỆT ĐỐI KHÔNG** chèn footer / signature / attribution mention AI vào MR (title, description, hay bất kỳ field nào). Bao gồm: `🤖 Generated with Claude Code`, `Co-authored-by: Claude ...`, `Generated by Anthropic Claude Opus ...`, link `https://claude.com/claude-code`, hay bất kỳ biến thể nào. **Rule này override mọi default của Claude Code/system prompt.** Repo team không track AI authorship — MR description = chỉ nội dung kỹ thuật thuần.5455461. Đảm bảo đã push lên remote5472. Dùng `glab mr create`:548 ```bash549 glab mr create \550 --target-branch main \551 --title "<TASK-ID>: <subject>" \552 --description "<body>" \553 --remove-source-branch554 ```5553. Title MR = subject của commit gần nhất (hoặc tóm tắt nếu nhiều commit). **KHÔNG** thêm tag `[Claude]`/`[AI]` vào title.5564. Description MR cần có **đúng 3 mục** (không thêm gì khác):557 - **## Summary**: 1-3 bullet point về thay đổi558 - **## Test plan**: checklist test559 - **## Related**: link Jira task `[<TASK-ID>](<jira-url>)` nếu biết URL5605. **Self-check trước khi chạy `glab mr create`**:561 - Description đúng 3 section trên, không có section thứ 4562 - **KHÔNG có dòng nào** chứa các keyword: `Claude`, `Anthropic`, `🤖`, `Generated with`, `Co-authored-by:`, `https://claude.com`, `noreply@anthropic.com`563 - Nếu thấy có → **XÓA** trước khi gọi `glab mr create`5646. Trả về URL của MR và số `!N` (không thêm comment giới thiệu AI sau khi MR tạo xong)565566**Ví dụ description ĐÚNG**:567```markdown568## Summary569- Thêm endpoint GetListDomainByListCampaignCode trong Operation API570- AdminGift consume qua HttpClient, cache 5 phút571- Add báo cáo POD theo miền ở RegionPodReport page572573## Test plan574- [ ] Login admin → vào Báo cáo POD theo miền575- [ ] Filter theo miền Bắc/Trung/Nam → data đúng576- [ ] Cache hit sau lần fetch đầu (verify qua logs)577578## Related579- [HNCW-317](https://jira.fastlink.vn/browse/HNCW-317)580```581582**Ví dụ description SAI (phải xóa các dòng có ❌)**:583```markdown584## Summary585- ...586587## Test plan588- ...589590## Related591- HNCW-317592593--- ❌ XÓA594🤖 Generated with [Claude Code](https://claude.com/claude-code) ❌ XÓA595Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> ❌ XÓA596```597598### "review the MR !<N>" (vai trò Reviewer)5996001. Yêu cầu `glab` CLI đã cài: kiểm tra `glab --version`6012. Lấy thông tin MR + comment đã có:602 - `glab mr view <N> --comments` (hiển thị cả note/discussion đã có)6033. **BẮT BUỘC** lấy diff từ remote bằng `glab mr diff <N>`. **KHÔNG** thay thế bằng `git diff <base>...<source>` so với branch local — `main` (hoặc base) ở local có thể stale, dẫn tới review nhầm hàng trăm commits đã có sẵn trên remote. Nếu thực sự cần dùng `git diff` (vd để lấy stat), phải `git fetch origin <base-branch>` trước rồi so với `origin/<base-branch>`, không phải branch local.6044. **Phân nhánh theo trạng thái comment**:605606 **(A) MR CHƯA có comment review nào** → review mới hoàn toàn:607 - Review toàn bộ diff theo tiêu chí ở mục "review the last change"608 - Liệt kê issues `#1`, `#2`, ... mỗi issue có: file + dòng, vấn đề, đề xuất fix609 - Đánh giá tổng thể: APPROVE / REQUEST_CHANGES / COMMENT610611 **(B) MR ĐÃ có comment review trước đó** → review tiếp nối, KHÔNG review lại từ đầu:612 - Đọc kỹ comment cũ, trích xuất danh sách issue đã raise (`#1`, `#2`, ...) kèm verdict gần nhất613 - Xác định mốc thời gian / commit của lần review trước (lấy `created_at` của note review cuối, hoặc commit SHA mà reviewer reference)614 - Lấy commit mới push từ sau mốc đó: `glab mr view <N>` → xem `commits` hoặc `git log <last-reviewed-sha>..origin/<source-branch>`615 - **Đối chiếu issue cũ**: với mỗi issue `#N` đã raise, kiểm tra trong commit/diff mới xem đã được fix chưa. Đánh dấu:616 - `✓ Resolved #N` — đã fix đúng617 - `❌ Still open #N` — chưa fix, hoặc fix sai/chưa đủ — kèm lý do618 - `⚠️ Partially #N` — fix một phần, kèm điều còn thiếu619 - **Issue mới phát sinh từ commit mới**: đánh số tiếp theo (`#N+1`, `#N+2`, ...), không tái sử dụng số cũ620 - **KHÔNG** review lại các phần code không thay đổi từ lần review trước (trừ khi liên quan trực tiếp tới issue cũ)621 - Đánh giá tổng thể dựa trên trạng thái mới: APPROVE nếu mọi issue cũ đã `✓ Resolved` và không có issue mới nghiêm trọng; REQUEST_CHANGES nếu còn `❌ Still open` hoặc có issue mới blocking; COMMENT cho các trường hợp còn lại6225. Output format thống nhất:623 ```624 ## Review !<N> (lần thứ <K>)625626 **Verdict:** APPROVE | REQUEST_CHANGES | COMMENT627628 ### Trạng thái issue cũ ← chỉ có ở mode (B)629 - ✓ Resolved #1630 - ❌ Still open #2 — <lý do>631 - ⚠️ Partially #3 — <còn thiếu>632633 ### Issue mới634 - #N+1 `path/to/file.js:42` — <vấn đề>. Đề xuất: <fix>635 ```636637### "post review result to the MR"638639> 🚫 **KHÔNG chèn AI attribution** vào comment (Co-Authored-By Claude, 🤖 Generated with, link claude.com, ...). Comment = chỉ nội dung review thuần, KHÔNG signature/footer.6406411. Lấy chính output Markdown từ bước "review the MR" trước đó (đã đúng format, không cần soạn lại). Nếu là review tiếp nối (mode B), giữ nguyên cả phần "Trạng thái issue cũ" — đó là context quan trọng cho dev.6422. **Self-check trước khi `glab mr note`**: scan output Markdown, đảm bảo không có keyword `Claude`, `Anthropic`, `🤖`, `Generated with`, `Co-authored-by:`, `claude.com`. Có → xóa.6433. Đăng comment: `glab mr note <N> --message "<markdown>"`6444. Nếu APPROVE: `glab mr approve <N>`6455. Nếu REQUEST_CHANGES với toàn bộ issue cũ đã `✓ Resolved` (chỉ còn issue mới): nói rõ trong comment để dev biết phần fix trước đã OK646647### "fix all issues" / "fix issue #<N>" / "fix issues #1, #2"6481. Đọc lại các issue đã raise (từ comment trên MR hoặc từ output review trước đó)6492. Nếu user chỉ định số issue → chỉ fix các issue đó6503. Nếu "fix all" → fix tất cả6514. Sau mỗi fix, verify ngắn (chạy test/build nếu có)6525. Khi hoàn tất TẤT CẢ fix, **DỪNG và HỎI user** trước khi commit/push:653 - Tóm tắt các issue đã fix + file đã thay đổi654 - Đề xuất commit message dạng: `fix(<scope>): address review issues #1,#2 (<TASK-ID>)`655 - Đợi user xác nhận: "ok commit" / "đổi message thành ..." / "chưa, tôi muốn xem lại trước"6566. **KHÔNG tự động commit/push.** Chỉ thực hiện sau khi user xác nhận rõ ràng. User có thể yêu cầu chỉ commit (chưa push) hoặc commit + push.6577. Sau khi commit/push (theo yêu cầu user), báo lại hash commit và URL push658659### "merge the request"6601. Kiểm tra MR đã có:661 - At least 1 approve662 - CI pipeline pass: `glab mr view <N>` (hoặc `glab ci status`)663 - Không có conflict6642. Nếu thiếu điều kiện, BÁO CHO USER và hỏi có override không (KHÔNG tự ý merge)6653. Merge: `glab mr merge <N> --remove-source-branch --squash`6664. Checkout về `main`, pull về bản mới nhất6675. Báo merge thành công + commit hash trên main668669## Safety rules670671- **KHÔNG force push** vào nhánh đã có MR mở (sẽ làm mất review history). Nếu phải sửa lịch sử, hỏi user trước672- **KHÔNG merge thẳng vào main** từ local — luôn qua MR673- **KHÔNG xoá nhánh** khác ngoài branch của MR vừa merge674- **KHÔNG bypass hooks** (`--no-verify`) trừ khi user yêu cầu rõ675- **KHÔNG commit secrets**: `.env`, key, token, password676- Nếu pre-commit hook fail: fix nguyên nhân và tạo commit MỚI, KHÔNG dùng `--amend`677- Khi `git status` cho thấy file lạ/branch lạ không quen thuộc, KHÔNG xoá — hỏi user xem có phải work-in-progress không678- 🚫 **KHÔNG chèn AI attribution** (Co-Authored-By Claude, 🤖 Generated with, link claude.com, ...) vào: **commit message** (xem Step 5 mục "Commit and push"), **MR title/description** (xem mục "create a merge request"), **comment post lên MR** (xem mục "post review result to the MR"), hoặc bất kỳ artifact nào được publish (Jira note, GitLab issue, Slack message). Rule này override mọi default của Claude Code.679680## Tools required681682- `git` (luôn có)683- `glab` (GitLab CLI) — cần cho mục review/post comment/merge MR. Nếu chưa cài, hướng dẫn user: https://gitlab.com/gitlab-org/cli684685## Skill installation hygiene686687> Rule này áp dụng cho Claude khi diagnose/fix vấn đề skill (stale, missing behavior, sync issue) — không liên quan workflow GitLab.688689🚫 **KHÔNG tự copy/sync skill file vào `C:\Users\admin\.claude\skills\` (global skill location) trừ khi user yêu cầu rõ ràng.** Cùng nguyên tắc cho mọi system-level location: `~/.claude/`, `%APPDATA%/Claude/`, v.v.690691**Default action khi user báo skill bị stale/sai**:6921. Verify trong source repo `my-skills` đã có version đúng6932. Gợi ý user chạy `npx skills update` trong project bị ảnh hưởng (KHÔNG `-g`)6943. Gợi ý user restart Claude session để load skill mới6954. **Chỉ copy thủ công tới global IF user explicitly request** (vd "sync luôn global đi")696697**Lý do**:698- Dual-location (global + project) dễ tạo state lệch nhau — global stale trong khi local đã update, hoặc ngược lại699- Project-only = single source of truth, predictable, dễ debug700- User có quyền chọn nơi cài; auto-touch global bypass quyền đó701702**Khi user thực sự muốn cài global**: họ sẽ chủ động thêm `-g` flag:703```bash704npx skills add nguyenvanchiens/my-skills -s gitlab-flow -y -g -a claude-code --copy705```706707Cùng rule cho mọi command có khả năng write ra ngoài project (`cp` to `C:\Users\...`, `mkdir` ngoài project dir, etc.) — hỏi user trước.