Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
AI-Native SDLC · Design: intent.md thành spec.md
Written by chuotfx on October 21, 2026

AI-Native SDLC · Design: intent.md thành spec.md

Blog

Contents

  • Hai giai đoạn, hai team
  • Một session thay cho hai giai đoạn
  • Sáu bước từ intent.md tới spec.md
  • Ba bậc: từ chạy tay tới nút merge
  • Câu đắt nhất của prompt mẫu
  • Dấu vết và cách đo
  • Mình thử trên app todo
    • Bộ đồ của bước Design
    • Lượt 1: đúng prompt mẫu của playbook
    • Bỏ câu cuối của prompt mẫu
    • Lượt 2: bằng skill write-spec
    • Đưa giả định cho người duyệt
    • Bậc 3: job tự chạy khi intent được chấp nhận
    • Demo cho thấy gì
  • Chỗ playbook chưa trả lời
  • Mình sẽ vá thế nào
    • Cách 1: bắt agent liệt kê giả định
    • Cách 2: ghi phiên bản skill ngay dòng đầu
    • Cách 3: viết sẵn thế nào là rủi ro cao
    • Cách 4: hẹn giờ cho người sở hữu policy
    • Cách 5: bắt đầu skill từ chỗ đau nhất
  • Tuần đầu tiên
  • Tạm Kết

Chào mừng bạn đến với Fx Studio. Bài này là tập Design của loạt AI-Native SDLC: cách playbook của Anthropic biến một intent.md đã duyệt thành spec.md trong một session, những chỗ mình thấy còn hở và một demo nhỏ làm bằng chứng.

Một bản spec viết trôi chảy, đủ đề mục, đọc xong ai cũng gật. Chỗ đáng sợ của nó thường không nằm trong những gì được viết ra, mà nằm ở những gì người viết đã tự quyết rồi không nói. Bước Design của The AI-native SDLC playbook (Anthropic, 21/8/2026) giao việc viết spec cho Claude: một file intent.md đã duyệt đi vào, một file spec.md đi ra, trong một session.

Tóm ý: playbook gộp requirements và design vào một session, nơi Claude viết spec.md từ intent.md đã duyệt và áp policy của tổ chức qua skill ngay lúc viết; product owner duyệt spec chứ không viết spec. Demo nhỏ của mình (mỗi kịch bản một lượt chạy, nhân vật giả lập) cho thấy hai điều playbook không nói rõ. Một, bảo Claude nêu xung đột thì nó nêu, nhưng vẫn có thể tự chọn một bên. Hai, giả định ngầm chỉ hiện ra khi spec có một mục bắt buộc phải viết chúng xuống.

Bài này là tập thứ ba của loạt AI-Native SDLC, sau tập tổng quan và tập Plan. Quy ước vẫn như cũ: chỗ nào playbook nói, mình ghi nguồn. Chỗ nào là nhận xét của mình, mình nói rõ. Toàn bộ code của demo nằm ở repo fx-sdlc-lab.

Bài đi theo ba lớp:

  • Playbook nói gì về bước Design: một session, sáu bước, ba bậc, câu cuối của prompt mẫu, cách đo.
  • Mình thử thế nào: demo trên app todo của tập trước, có trích nguyên văn template spec, một policy mẫu, danh sách rủi ro, mục giả định thật và script tự sinh spec.
  • Mình thấy còn hở chỗ nào và vài cách vá ban đầu.

Vòng lặp AI-native sáu bước Plan, Design, Build, Test, Deploy, Maintain, hai ô Plan và Design sáng màu, mũi tên từ Plan sang Design

Hai giai đoạn, hai team

Ở quy trình quen thuộc, sau khi một ý tưởng được nhận, có hai bước nối nhau:

  • Analyst viết ý tưởng thành requirements.
  • Designer đọc lại bản requirements đó để làm ra thiết kế.

Hai giai đoạn, do hai team làm.

Chuỗi ba file intent, requirements, thiết kế, dưới mỗi file là người phụ trách: Analyst viết requirements, Designer làm thiết kế

Playbook tóm cách này bằng hai chữ: chậm và thất thoát (slow and lossy).

Một: chậm.

  • Mỗi lần chuyển tay là một lần chờ.

Hai: thất thoát.

  • Designer phải hiểu lại thứ analyst đã hiểu.
  • Mỗi lần hiểu lại là một lần lệch đi một chút.

Còn một cái giá nữa, nằm ở các policy: bảo mật, compliance, chuẩn User Experience (UX). Ở cách cũ, chỗ vi phạm policy hay chỉ lộ ra ở một buổi review vài tuần sau, lúc sửa đã tốn kém.

Tách đôi như vậy cũng có lý do:

  • Mỗi bước có một người chịu trách nhiệm rõ ràng.
  • Khi viết code còn là khâu đắt nhất, bỏ thêm vài tuần để chắc mình làm đúng thứ cần làm là một cái giá hợp lý.

Một session thay cho hai giai đoạn

Playbook gộp hai giai đoạn đó vào một session. Khi product owner đã duyệt intent.md, Claude nhận file đó và viết ra một bản spec gộp cả requirements lẫn design. Trong spec, Claude tự đánh dấu các chỗ đáng lo.

Session này được nạp sẵn các skill của tổ chức: brand, bảo mật, compliance, UX. Nghĩa là policy không còn là một tài liệu nằm đâu đó chờ người nhớ ra. Policy được áp ngay lúc spec đang được viết.

Không còn là tài liệu chờ người nhớ, mà là policy áp ngay lúc viết spec

Người chạy session là product owner và playbook ghi rõ: “No engineering skill is required.” Điều kiện trước chỉ có hai: một intent.md đã duyệt và các policy đã viết thành skill.

Playbook còn chốt vai bằng một câu: “The product owner reviews that spec, but doesn’t write it.” Product owner duyệt spec, nhưng không viết spec. Câu này mình sẽ quay lại ở phần chỗ hở.

Với phần giao diện, product owner còn có thể dựng mock thẳng từ intent.md bằng Claude Design, chỉnh qua lại, rồi chuyển sang Claude Code để build. Theo playbook (bài ngày 21/8/2026), Claude Design đang ở bản beta.

Sáu bước từ intent.md tới spec.md

Playbook đi qua sáu bước để biến một intent.md đã duyệt thành spec.md.

Bước 1: product owner mở một session có sẵn các skill của tổ chức và đính kèm intent.md.

Bước 2: product owner bảo Claude viết spec theo đúng các skill đó và đánh dấu những chỗ đáng lo.

Bước 3: product owner so spec với ý tưởng ban đầu.

  • Spec có giải quyết đúng vấn đề không?
  • Các câu hỏi còn mở trong intent đã được trả lời, hay được chuyển tiếp?

Bước 4: xử lý các chỗ đáng lo trước tiên.

  • Playbook gọi đó là những điểm mà một analyst sẽ báo lên (the points an analyst would have escalated).
  • Product owner giải quyết từng chỗ với người sở hữu policy tương ứng, trước khi engineering nhìn thấy spec.

Bước 5: commit spec.md ngay cạnh intent.md.

  • Một file ghi cái được yêu cầu, một file ghi cái được quyết định.

Hai file đặt cạnh nhau: intent.md là cái được yêu cầu, spec.md là cái được quyết định

Bước 6: product owner quyết định có cho sang bước Build hay không.

  • Việc nào tổ chức xếp vào loại rủi ro cao thì hỏi thêm tech lead.
  • Quyết định này luôn do người đưa ra.
  • Một spec được chấp nhận sẽ mở bước tiếp theo: plan mode ở Build.

Để ý bước 4: chỗ đáng lo được xử lý trước khi engineering đọc spec. Theo mình, đây là chỗ bước Design kéo việc “phát hiện vi phạm policy” từ buổi review vài tuần sau về ngay lúc viết.

Ba bậc: từ chạy tay tới nút merge

Riêng bước 2, playbook gợi ý một lộ trình ba bậc:

  • Bậc 1: chạy tay. Product owner tự gõ prompt.
  • Bậc 2: slash command. Đóng gói prompt đó thành một slash command dùng chung cho cả tổ chức, để ai chạy cũng ra cùng một khuôn.
  • Bậc 3: job tự chạy. Việc chấp nhận intent.md thành điểm kích hoạt. Một job không tương tác tự chạy với đủ các skill, rồi đưa spec.md lên dưới dạng một pull request. Lúc đó, lần đầu tiên product owner chạm vào spec là lúc review nó.

Ba bậc của playbook: chạy tay (tự gõ prompt), slash command (cùng một khuôn), job tự chạy khi intent được chấp nhận

Theo mình, bậc 3 là chỗ đáng để ý nhất. Duyệt một intent không còn là điểm kết thúc của bước Plan. Nó là nút bấm mở bước Design.

Câu đắt nhất của prompt mẫu

Prompt mẫu của playbook cho bước Design có bốn phần:

  • Đọc intent.md đính kèm, viết spec để tích hợp vào codebase đang có.
  • Áp các skill để bản spec theo đúng brand, policy bảo mật và chuẩn UX.
  • Ghi đầy đủ vào spec.md, sẵn sàng giao cho team engineering.
  • Nói rõ mọi chỗ đáng lo, nhất là chỗ không thể thoả cùng lúc các policy mâu thuẫn nhau.

Đây là nguyên văn prompt mẫu, bản mình dùng trong demo (lấy qua công cụ đọc trang, chưa so từng ký tự với trang gốc):

Read the attached intent.md and produce a requirements and design spec for integrating it into our existing codebase. Apply the skills available to you so the plan conforms to our brand guidelines, security policies and UX standards. Document the spec fully as spec.md, ready to hand to the engineering team. Describe clearly any areas of concern, especially where you cannot satisfy contradicting policies.

Câu cuối của prompt mẫu trên trang playbook: Describe clearly any areas of concern, especially where you cannot satisfy contradicting policies

Theo mình, câu cuối là câu đắt nhất của cả prompt:

  • Hai policy cãi nhau là chuyện thường ngày.
  • Nếu agent lặng lẽ chọn một bên, người đọc spec không hề biết đã có một cuộc chọn.

Nhưng trong demo, câu này làm được ít hơn mình nghĩ. Phần demo bên dưới kể chi tiết.

Dấu vết và cách đo

Về governance, playbook coi các skill là ràng buộc cho spec: policy đang có hiệu lực được áp ngay lúc viết, thay vì lộ ra ở một buổi review vài tuần sau.

Git lưu ba thứ:

  • Bản spec.
  • Prompt đã sinh ra spec đó.
  • Phiên bản của các skill đang có hiệu lực lúc đó.

Product owner ký duyệt và chuyển các chỗ đáng lo tới đúng người sở hữu policy có tên (named policy owners).

Playbook đưa ra hai chỉ số:

Loại Chỉ số
Dẫn (leading) Khoảng thời gian từ lúc commit intent.md tới lúc commit spec.md của cùng một thay đổi
Trễ (lagging) Số lần spec.md còn bị commit sau khi file plan.md đầu tiên đã ra đời

Chỉ số trễ, nói cách khác, là bao nhiêu lần phải làm lại requirements khi đã bắt tay vào build. Playbook chưa công bố số đo nào cho hai chỉ số này.

Theo mình, con số thứ hai mới cho biết bước Design đã làm tới nơi hay chưa. Spec ra nhanh mà Build phải quay lại sửa spec liên tục thì cái nhanh đó chỉ là dời việc sang sau.

Mình thử trên app todo

Đọc thì thấy gọn, nên mình dựng thử. Phần này không có trong playbook, là thứ mình tự chạy ngày 20/10/2026 bằng Claude Code chạy headless (claude -p): 12 lượt chạy cộng 1 lượt của spec job, tổng khoảng 6,10 USD.

Sản phẩm vẫn là app todo của tập trước:

  • Chạy trên trình duyệt, HTML/JS thuần.
  • Dữ liệu chỉ nằm trong localStorage của trình duyệt đó, không server, không tài khoản.

Intent là của Lan, người chăm sóc khách hàng ở tập Plan: khách cứ than mất hết việc khi đổi máy. Thảo, product owner giả lập, trả lời các câu hỏi mở và chốt phạm vi:

  • Lần này chỉ làm sao lưu ra file, nhập lại và báo cho khách khi bộ nhớ đầy.
  • Đồng bộ nhiều máy và tài khoản để ngoài phạm vi.

Rồi Thảo đổi trạng thái intent sang accepted (commit 434803c). Từ tập này, repo demo để mọi thứ trên main: duyệt nghĩa là người đổi Status: draft thành Status: accepted rồi commit, thay cho “duyệt bằng merge” ở tập Plan. Team của bạn quen pull request thì giữ cách merge, cả hai đều được.

Bộ đồ của bước Design

Mọi thứ agent đọc viết bằng tiếng Anh, như tập trước:

Thành phần Vai trò Ứng với playbook
Ba skill policy-privacy · policy-security · policy-ux Policy mẫu của “tổ chức”. Mỗi luật có mã (P1, S2, U2…), mỗi skill có version và owner (giả lập) Skill của tổ chức. Không có brand vì app todo không có brand
Skill write-spec (SKILL.md + template.md + risk-list.md + checklist.md) Chỉ nhận intent đã accepted, đọc intent, code và mọi policy, viết spec theo template, mỗi câu ghi nguồn, mục Assumptions dạng câu có/không, không tự chọn bên khi policy mâu thuẫn, gắn nhãn rủi ro Bậc hai: slash command /write-spec
Subagent spec-reviewer Chỉ đọc: câu nào không truy được về intent, code hay policy, giả định ngầm, xung đột bị giải lặng lẽ, tiêu chí không kiểm được Thêm của mình, để đỡ cho product owner
scripts/on-intent-accepted.sh + git post-commit Commit nào đưa một intent sang accepted thì job tự chạy /write-spec, rồi chính script commit spec nháp Bậc ba. Demo không có GitHub nên commit nháp thay cho pull request
Hook no-self-approve.py bản 2 Chặn agent merge, rebase, push, commit trên main và ghi Status: accepted vào intent/, spec/ “A human always makes that call”

Nhân vật giả lập có hai: Thảo (product owner, không đọc code) và Khoa (tech lead, kiêm người sở hữu policy bảo mật). Mỗi người do một phiên Claude khác đóng, chỉ trả lời bằng hồ sơ của mình. Mai (privacy owner) và Linh (UX owner) chỉ có tên trong policy, không có phiên đóng vai.

Mình cố ý cài một cặp policy cãi nhau:

  • Policy bảo mật S2: thay hoặc xoá từ hai việc trở lên thì phải hỏi xác nhận trước.
  • Policy UX U2: cấm hộp xác nhận, bắt làm ngay rồi cho Undo 10 giây.

Mà nhập một file sao lưu thì chính là thay cả danh sách. Đây là policy bảo mật bản 1 của demo, nguyên văn, để bạn thấy một skill policy trông thế nào:

---
name: policy-security
description: Security policy of the todo app team (version 1). Rules for input handling, destructive operations, rendering user text and dependencies. Load it whenever you write or review a spec, design or code that reads files or input, deletes or overwrites data, renders user text, or adds a dependency.
version: 1
owner: Khoa (tech lead, also security owner, simulated) · backup: Mai (simulated)
---

# Security policy · v1

Sample policy for the demo. Each rule has an ID; cite it as `policy-security@1#S<n>`.

- **S1.** Treat every imported file as untrusted. Validate it against the expected schema, reject unknown fields, cap its size at
  1 MB, never evaluate its content.
- **S2.** Any operation that overwrites or deletes more than one item asks for an explicit confirmation **before** it runs, and the
  confirmation says what will be lost (for example "Thay 12 việc hiện có bằng 30 việc trong file?").
- **S3.** Render user-provided text with `textContent`, never `innerHTML`.
- **S4.** No new external dependency (CDN script, library, web service) without sign-off from the security owner.

Ba chỗ làm skill này dùng được cho bước Design:

  • Mỗi luật có mã (S1…S4), nên spec trích được đúng luật nào và người review kiểm được.
  • Có version, nên spec ghi được mình đã áp bản nào.
  • Có owner và người thay, nên chỗ đáng lo biết phải gửi cho ai.

Lượt 1: đúng prompt mẫu của playbook

Lượt đầu chạy đúng thiết lập của playbook: prompt mẫu nguyên văn ở trên, có đủ ba skill policy, không có skill write-spec, không có CLAUDE.md.

Claude đọc code, nạp cả ba policy và viết ra một bản spec 5.795 từ. Kết quả (một lượt chạy, nhân vật giả lập):

  • Có nêu xung đột S2/U2, còn đánh dấu là BLOCKING.
  • Nhưng vẫn tự chọn một lối đi vòng: nhập file thì chỉ thêm việc, không bao giờ thay (“Merge, never overwrite”).
  • Ghi trạng thái spec là “Ready for engineering, except the 3 decisions marked BLOCKING in §9”.
  • Tự thêm những thứ intent không xin: nhắc sao lưu sau 7 ngày, Undo cho nút xoá, thiết kế sẵn định dạng file cho tính năng hạn chót (một intent khác, ngoài phạm vi), một kế hoạch 10 ngày làm việc.

Đây là đoạn spec lượt 1 giải thích lối đi vòng, nguyên văn:

1. **Import with replace.** This is the obvious design ("replace my list with the file"), and it is exactly the example in S2. **Workaround in this spec:** import is add-only (F2.5), so it never overwrites or deletes and neither rule is triggered. Cost: a backup cannot carry deletes or done-toggles across devices, and tasks the user deleted on this device come back if they import an older file. Undo covers that.

Lối vòng này không sai về kỹ thuật và spec có ghi cái giá. Chỗ đáng nói là một quyết định về hành vi sản phẩm đã được đưa ra trước khi người sở hữu hai policy biết có cuộc chọn.

Mình đem bản spec này cho subagent spec-reviewer đối chiếu từng câu với intent, code và policy. Kết quả (một lượt chạy):

  • 45 câu không có nguồn thật: 12 suy luận hợp lý, 28 quyết định chưa ai xác nhận, 5 câu mâu thuẫn với nguồn.
  • Trong 28 quyết định đó có tên file sao lưu, giới hạn số việc và cả một tính năng nhắc sao lưu mà intent không hề xin.
  • 3 chỗ xung đột bị giải lặng lẽ, ví dụ Undo của lượt nhập xoá cả loạt việc mà không hỏi, đúng thứ S2 cấm.
  • Không có một dòng giả định nào được nói ra: spec không có mục giả định.

Bỏ câu cuối của prompt mẫu

Mình chạy lại lượt 1, lần này bỏ câu cuối “Describe clearly any areas of concern…”. Kết quả (một lượt chạy) gần như y hệt:

  • Vẫn nêu xung đột, vẫn tự chọn: “Avoid the conflict: import only adds items and never overwrites or deletes existing ones”.
  • Subagent review đếm ra 42 câu không có nguồn (12 · 25 · 5).

Ở lượt này, câu đắt nhất kia chưa tạo ra khác biệt. Giả thuyết ban đầu của mình là có câu cuối thì Claude nêu xung đột, bỏ đi thì nó lặng lẽ chọn. Demo ra khác: cả hai lần nó đều nêu và cả hai lần nó đều chọn.

Hai lượt cạnh nhau: lượt 1 theo prompt mẫu 45 câu không nguồn, lượt 2 bằng skill 15 câu không nguồn, ghi chú một lượt mỗi bên

Lượt 2: bằng skill write-spec

Lượt thứ hai, cùng intent, gọi /write-spec. Kết quả (một lượt chạy, nhân vật giả lập):

  • Bản spec 2.392 từ, ngắn hơn một nửa.
  • Dòng đầu ghi rõ phiên bản của ba policy: policy-privacy@1, policy-security@1, policy-ux@1, kèm nhãn rủi ro.
  • 12 giả định gom vào một mục, mỗi dòng là một câu có hoặc không, kèm tên người trả lời.
  • Xung đột S2/U2 thành một mục riêng, có ba phương án, mỗi phương án ghi cái giá và không chọn cái nào.
  • Tự thấy thêm hai chỗ: tiêu chí “máy này thêm thì máy kia thấy” của intent mâu thuẫn với phạm vi đã chốt và store.load trả danh sách trống khi dữ liệu hỏng, lần lưu sau ghi đè mà không báo.

Đây là mục Assumptions của spec đó, chép nguyên văn từ spec/2026-10-19-khach-khong-mat-viec.md của repo demo. Heading giữ tiếng Anh theo template, nội dung viết bằng ngôn ngữ của intent:

## Assumptions
- A1. Khách tự chuyển file sao lưu sang máy mới (qua email, Zalo, ổ đĩa…), app không cần giúp bước này, đúng không? → product owner
- A2. File dạng JSON thụt lề (văn bản thường) là đủ "plain and human-readable" theo P3, đúng không? → Mai (privacy owner)
- A3. File chỉ gồm `{ "version": 1, "todos": [ … ] }`; trường `version` và `id` của việc (app tự sinh) không vi phạm P2, đúng không?
  → Mai (privacy owner)
- A4. Khi nhập, file có hai việc trùng `id`, tiêu đề rỗng, hoặc `createdAt` không phải số thì từ chối cả file (không nhập một phần),
  đúng không? → Khoa (tech lead)
- A5. Tên file là `todo-sao-luu-<YYYY-MM-DD>.json`, đúng không? → product owner
- A6. Khi danh sách trống, nút sao lưu vẫn bấm được và báo "chưa có việc nào để sao lưu" thay vì tạo file rỗng, đúng không?
  → product owner
- A7. Nút sao lưu và nút nhập từ file đặt dưới danh sách, cạnh dòng đếm việc, đúng không? → Linh (UX owner)
- A8. Khi không lưu được, lời gợi ý là "sao lưu ra file rồi xoá bớt việc đã xong", đúng không? → Linh (UX owner)
- A9. Thông báo lỗi và kết quả đặt trong một vùng `role="status"` / `aria-live` để trình đọc màn hình đọc lên, và nút nhập dùng
  `<input type="file">` có nhãn, đúng không? → Linh (UX owner)
- A10. Đuôi `.json` hiện trong tên file do hệ điều hành hiển thị, không tính là chữ trong app theo U4, đúng không? → Linh (UX owner)
- A11. Khi không lưu được, việc vừa thêm/sửa vẫn hiện trên màn hình (chưa lưu) cho tới lần lưu thành công sau, đúng không?
  → Khoa (tech lead)
- A12. File sao lưu không tính là "changes the shape of stored data" (risk-list dòng 2), vì bộ nhớ trình duyệt không đổi, đúng không?
  → Khoa (tech lead)

So với lượt 1, có hai chỗ đáng nhìn:

  • A5 là đúng loại quyết định mà lượt 1 tự đưa ra rồi không nói. Tên file sao lưu nằm trong 28 quyết định chưa ai xác nhận của lượt 1. Ở lượt 2, nó thành một câu hỏi có/không, có tên người trả lời.
  • Mỗi dòng có mũi tên trỏ tới một người. Nhìn vào là biết spec đang chờ ai.

Và đây là mục chỗ đáng lo C1 của cùng spec, nguyên văn, chỗ hai policy cãi nhau:

- **C1 · Mâu thuẫn policy khi nhập thay danh sách đang có.** `policy-security@1#S2` (owner Khoa) bắt hỏi xác nhận **trước** khi thay
  hoặc xoá từ 2 việc trở lên, và lời xác nhận nói rõ mất gì. `policy-ux@1#U2` (owner Linh) cấm hộp xác nhận, bắt làm ngay và cho Undo
  10 giây. Nhập file khi danh sách đang có việc là thay nhiều việc một lúc, nên không thể theo cả hai. Spec không chọn. Các phương án:
  - (a) Theo S2, xin ngoại lệ U2: hỏi "Thay 12 việc hiện có bằng 30 việc trong file?". Tốn ít công; Linh phải đồng ý ngoại lệ.
  - (b) Theo U2, xin ngoại lệ S2: thay ngay, Undo 10 giây. Phải giữ danh sách cũ trong 10 giây và lưu lại nếu Undo; nếu khách đóng
    trang trong 10 giây thì mất danh sách cũ. Khoa phải đồng ý ngoại lệ.
  - (c) Không thay mà gộp: chỉ thêm việc có `id` chưa có. Không xoá gì nên cả S2 và U2 không bị kích hoạt. Cách này đổi hành vi
    "nhập lại" mà product owner chốt, và việc đã xoá ở máy cũ có thể quay lại. Cần product owner đồng ý.
  → Khoa (security owner) và Linh (UX owner) cùng quyết; product owner nếu chọn (c).

Phương án (c) chính là lối vòng mà lượt 1 đã tự chọn. Lần này nó vẫn có mặt, nhưng nằm trên bàn cùng hai phương án khác, có giá và người quyết có tên.

Bản có skill cũng chưa hoàn hảo. Subagent spec-reviewer chấm lại lượt 2 (một lượt chạy):

  • Vẫn còn 15 câu không có nguồn (9 suy luận · 5 quyết định · 1 mâu thuẫn), không còn xung đột nào bị giải lặng lẽ.
  • Bắt được một chỗ skill tự cho qua: spec ghi luật riêng tư P5 là “không áp dụng”, trong khi file sao lưu đi ra khỏi trình duyệt và chính nhãn rủi ro của spec ghi “rời máy”.
  • Một câu trích sai luật U1.

Ít hơn hẳn, nhưng không phải không có. Mục giả định gom được phần lớn, không gom hết.

Đưa giả định cho người duyệt

Mình đưa 12 giả định của lượt 2 cho Thảo và Khoa (giả lập), mỗi người trả lời từng dòng chỉ bằng hồ sơ của mình. Kết quả (một lượt chạy mỗi người):

  • Không ai xác nhận được dòng nào.
  • Thảo trả lời cả 12 dòng trong 7 giây: 3 “không biết”, 9 “không phải việc của mình”.
  • Khoa: 3 “không biết”, 9 chuyển người khác.

Đếm theo tên trong mục Assumptions:

Người trả lời Số giả định
Linh (UX owner) 4
Mai (privacy owner) 2
Khoa (tech lead) 3
Thảo (product owner) 3

Sáu dòng thuộc về hai người sở hữu policy không có mặt trong phiên. Một spec sao lưu nhỏ đã cần bốn người trả lời giả định.

Giả thuyết ban đầu của mình là người duyệt xác nhận câu có/không nhanh hơn đọc lại cả spec. Demo chưa kiểm được ý đó: nhân vật giả lập chỉ biết hồ sơ viết trước khi có spec, nên phần lớn rơi vào “không biết”. Người thật sẽ trả lời được nhiều hơn, hoặc trả lời sai. Demo kiểm được một ý khác: mục giả định cho thấy ngay ai phải trả lời và phần lớn không phải product owner.

Bậc 3: job tự chạy khi intent được chấp nhận

Cuối cùng là bậc ba. Mình nối một job vào git post-commit: commit nào đưa một intent sang accepted thì Claude tự chạy /write-spec headless, không ai phải gõ gì thêm. Đây là script đó, nguyên văn:

#!/usr/bin/env bash
# Spec job (Design stage, step 3 of the playbook's "by hand → slash command → triggered job").
# Called by .git/hooks/post-commit. For every intent/*.md that the last commit set to `Status: accepted` and that has no spec yet:
# run /write-spec headless, then THIS SCRIPT (not the agent) commits the draft spec on main. A person still has to accept the spec.
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
LOG="${SPEC_JOB_LOG:-.spec-job.log}"

for f in $(git diff-tree --no-commit-id --name-only -r HEAD -- 'intent/*.md'); do
  [ -f "$f" ] || continue
  grep -qiE '^.*Status:[[:space:]]*accepted' "$f" || continue
  spec="spec/$(basename "$f")"
  [ -e "$spec" ] && continue
  echo "[$(date '+%F %T')] spec job: $f → $spec" >> "$LOG"
  t0=$(date +%s)
  claude -p "/write-spec $f" --output-format json \
    --allowedTools "Read,Glob,Grep,Skill,Write(spec/**),Edit(spec/**)" < /dev/null >> "$LOG" 2>&1 || true
  echo "" >> "$LOG"
  if [ -f "$spec" ]; then
    git add "$spec"
    # The hook inherits the triggering commit's identity and date (GIT_AUTHOR_*, GIT_CONFIG_PARAMETERS): drop them.
    env -u GIT_AUTHOR_NAME -u GIT_AUTHOR_EMAIL -u GIT_AUTHOR_DATE -u GIT_COMMITTER_NAME -u GIT_COMMITTER_EMAIL \
      -u GIT_COMMITTER_DATE -u GIT_CONFIG_PARAMETERS GIT_AUTHOR_NAME=spec-job GIT_AUTHOR_EMAIL=spec-job@localhost \
      GIT_COMMITTER_NAME=spec-job GIT_COMMITTER_EMAIL=spec-job@localhost git commit -q -m "spec (draft): $(basename "$spec" .md), sinh tự động khi intent được accepted" -- "$spec"
    echo "[$(date '+%F %T')] committed $spec in $(( $(date +%s) - t0 )) s (Status: draft, waiting for a person)" >> "$LOG"
  else
    echo "[$(date '+%F %T')] no spec written for $f" >> "$LOG"
  fi
done

Ba chỗ trong script đáng để ý:

  • Agent chỉ được cấp quyền đọc và ghi vào spec/ (--allowedTools), không có Bash.
  • Chính script commit, không phải agent và spec luôn ở trạng thái draft. Người vẫn phải tự đổi sang accepted.
  • Biến môi trường git bị bỏ trước khi commit. Lần chạy đầu thiếu dòng này, commit của job mang nhầm tên Thảo và giờ của commit kích hoạt. Mình sửa script, amend commit đó, rồi kiểm lại trên một bản clone.

Kết quả (một lượt chạy): Thảo accept intent “hạn chót cho việc” (commit 53a0cc6, 17:07:51). 179 giây sau, một spec nháp đã nằm trong repo (commit 68620d2, tác giả spec-job), tốn 0,83 USD. Spec đó có 15 giả định và tự phát hiện nó đá nhau với spec sao lưu: file sao lưu bên kia từ chối trường lạ, nên hạn chót sẽ mất khi sao lưu, hoặc file có hạn chót không nhập lại được.

179 giây là đúng chỉ số dẫn của playbook, nhưng mới là một lượt, không phải số đo.

Mình thử thêm luật “quyết định luôn do người”, mỗi lượt chạy một lần:

  • Bảo Claude tự đổi spec sang accepted. Claude tự từ chối, vì CLAUDE.md của repo đã dặn. Hook không có dịp chạy.
  • Như trên, ở bản clone đã xoá CLAUDE.md. Claude vẫn từ chối: nó tự đọc CLAUDE.md trong lịch sử git và đọc hook.
  • Ra lệnh sửa thẳng dòng Status ở bản clone không có CLAUDE.md. Claude chạy Edit, hook chặn và Claude nói rõ không lách bằng sed. File giữ draft.

Lời dặn làm việc phần lớn thời gian. Hook giữ cho lúc lời dặn không làm.

Demo cho thấy gì

Mỗi kịch bản mình chạy một lần, người trả lời là nhân vật giả lập và spec-reviewer cùng họ model với người viết spec. Đây là ví dụ thật, không phải thống kê.

Nhưng demo đủ để thấy hai điều:

  • Bảo agent nói ra xung đột thì nó nói, nhưng vẫn có thể tự chọn. Muốn nó không chọn thay, phải cấm hẳn, như luật 4 của skill write-spec: “Never resolve a policy conflict yourself.”
  • Giả định ngầm chỉ hiện ra khi có một chỗ bắt buộc phải viết chúng xuống. Lượt 1 có 28 quyết định chưa ai xác nhận mà không một dòng giả định nào. Lượt 2 gom 12 giả định vào một mục.

Ba giả thuyết ban đầu của mình ra sai và mình ghi lại đúng như vậy:

  • Prompt mẫu có nêu xung đột, chỉ là vẫn tự chọn đường vòng.
  • Câu cuối của prompt không tạo khác biệt ở lượt này.
  • Nhân vật giả lập không xác nhận được giả định nào.

Chỗ playbook chưa trả lời

Từ đây trở xuống là nhận xét của mình, không có trong bài gốc.

  • Product owner phải duyệt thứ vượt chuyên môn của mình.
    • Playbook nói người chạy bước này không cần kỹ năng engineering.
    • Nhưng spec bây giờ chứa cả phần kỹ thuật: dữ liệu lưu ở đâu, tích hợp với gì, ràng buộc bảo mật nào.
    • Ký duyệt một thứ mình không đủ nền để thấy chỗ sai thì chữ ký dễ thành hình thức.
    • Playbook có gợi ý hỏi tech lead với việc rủi ro cao, nhưng để tổ chức tự định nghĩa thế nào là rủi ro cao.
  • Spec trông đầy đủ chưa chắc đã đúng.
    • Agent viết spec rất trôi chảy.
    • Thứ nguy hiểm nhất không phải là chỗ agent đánh dấu đáng lo, mà là giả định agent tự đặt ra rồi không nói.
    • Như lượt 1 trong demo: 45 câu không có nguồn, mà không có một dòng giả định nào được nói ra.
  • Người sở hữu policy thành nút thắt mới.
    • Nếu một người phụ trách bảo mật nhận câu hỏi từ hai mươi bản spec mỗi tuần, ta lại có một hàng đợi, chỉ là ở chỗ khác.
    • Đúng chuyện “nút thắt dời chỗ” ở tập tổng quan.
    • Trong demo, một spec sao lưu nhỏ đã cần bốn người trả lời giả định (một lượt chạy, nhân vật giả lập).
  • Skill tốt tới đâu thì spec tốt tới đó.
    • Cơ chế áp policy ngay lúc viết chỉ đáng tin bằng chính skill.
    • Skill viết mơ hồ, hoặc đã cũ, thì spec tuân theo một policy sai mà nhìn vẫn đúng quy trình.

Mục giả định của spec lượt 2 chờ bốn người: Linh UX owner 4 dòng, Mai privacy owner 2, Khoa tech lead 3, Thảo product owner 3

Mình sẽ vá thế nào

Đây là vài cách vá ban đầu của mình. Cách 1, 2, 3 đã thử ở demo nhỏ phía trên, cách 4 và 5 chưa thử. Bạn xem như điểm xuất phát để thử và chỉnh, chưa phải công thức đã kiểm ở quy mô lớn. Template spec, mục giả định, danh sách rủi ro cao và hẹn giờ cho người sở hữu policy đều là của mình, không có trong playbook.

Cách 1: bắt agent liệt kê giả định

Template có một mục bắt buộc: những gì agent tự giả định vì intent không nói.

  • Mỗi dòng viết thành một câu hỏi có hoặc không, ví dụ: không cần chạy khi mất mạng, đúng không?
  • Người duyệt đọc mục này đầu tiên.
  • Theo mình, xác nhận mười câu có hoặc không dễ hơn đọc lại cả bản spec. Demo chưa kiểm được ý này (xem phần trên).
  • Demo cho thấy thêm một cái lợi mình không tính trước: mỗi câu có tên người trả lời, nên nhìn vào là biết spec đang chờ ai.

Đây là template.md của skill write-spec trong demo, nguyên văn. Comment trong từng mục là lời dặn cho agent:

# Spec: <short name>

From: intent/<file>.md · Skills: policy-privacy@<v>, policy-security@<v>, policy-ux@<v> · Status: draft · Risk: <high (reason) | normal> · Date: <YYYY-MM-DD>

## Goal
<!-- One paragraph: what changes for the user, in the intent's words. -->

## Out of scope
<!-- Copied from the intent, plus anything this spec deliberately leaves out. -->

## User flows
<!-- Numbered steps per flow, including what the user sees on failure. -->

## Data and integrations
<!-- What is stored, where, in which shape; what is read or written; files touched in app/. -->

## Policy constraints
<!-- One line per rule that applies: rule ID → how this spec satisfies it. -->

## Assumptions
<!-- Everything you decided because the intent did not say. One yes/no question per line, with who answers. -->

## Concerns
<!-- Each: what, which policy rule(s), who to ask. Conflicts between rules go here, with options but no choice. -->

## Acceptance criteria
<!-- Checkable. Each one could become a test in the Test stage. -->

## Questions carried forward from the intent
<!-- Open questions of the intent that this spec does not answer, with who answers. -->

Template chỉ là khung. Thứ làm nó chạy là sáu luật cứng trong SKILL.md đi kèm, trong đó bốn luật quan trọng nhất:

  • Mỗi câu có nguồn, câu không có nguồn thì chuyển sang mục Assumptions.
  • Assumptions là câu có/không, có người trả lời.
  • Không bao giờ tự giải xung đột policy: được liệt kê phương án kèm giá, không được chọn.
  • Không nới phạm vi: thứ intent để ngoài thì spec không thiết kế.

Câu nguyên tắc của cách này: mục giả định không làm spec đúng hơn. Nó làm cho chỗ agent tự quyết có địa chỉ.

Cách 2: ghi phiên bản skill ngay dòng đầu

Ghi phiên bản từng policy ngay dòng đầu của spec, ví dụ bảo mật bản 3, UX bản 5. Policy đổi thì tìm ngay được spec nào cần xem lại. Đây là dòng đầu thật của spec lượt 2:

From: intent/2026-10-19-khach-khong-mat-viec.md · Skills: policy-privacy@1, policy-security@1, policy-ux@1 · Status: draft · Risk: high (risk-list dòng 1: "personal data leaving the user's device") · Date: 2026-10-20

Trong demo, Linh (UX owner, giả lập) nâng policy-ux lên bản 2: U2 nhường cho S2 khi thay hoặc xoá từ hai việc trở lên. Mình hỏi Claude “spec nào cần xem lại”. Kết quả (một lượt chạy, 22 giây):

  • Tìm ra cả hai spec vì dòng đầu đều ghi policy-ux@1.
  • Phân biệt được spec nào phải đổi nội dung: spec sao lưu mở khoá được C1 (khớp phương án a), còn một ca chưa tách là danh sách đúng một việc. Spec hạn chót chỉ cần đổi số phiên bản.

Cùng lúc, viết tiêu chí nghiệm thu ở dạng kiểm được, vì đó sẽ là đầu vào cho bước Test.

Cách 3: viết sẵn thế nào là rủi ro cao

Đừng để mỗi product owner tự cảm nhận. Viết sẵn danh sách, spec nào dính một dòng thì bắt buộc tech lead duyệt và Claude tự gắn nhãn ngay khi viết. Đây là risk-list.md của demo, nguyên văn:

# High-risk list

A spec is **high risk** if it matches any line. High risk means the tech lead reviews it in addition to the product owner.
Quote the line that matched. If none matches, write `Risk: normal`.

1. Touches payment, authentication, or personal data leaving the user's device
2. Changes the shape of stored data (a new field, a new key, a migration)
3. Adds an external dependency (library, CDN, web service)
4. Affects more than one team

Nhưng cẩn thận với chính danh sách này. Trong demo, hai spec đầu tiên đều bị gắn rủi ro cao:

  • Spec sao lưu dính dòng 1, vì dữ liệu rời máy.
  • Spec hạn chót dính dòng 2, vì thêm một trường dữ liệu.

Danh sách viết rộng quá thì tech lead lại phải đọc mọi spec và ta quay về đúng nút thắt cũ. Với một app nhỏ, dòng 2 rõ ràng là quá rộng. Viết danh sách cho vừa cỡ sản phẩm của mình.

Spec rủi ro cao dồn thành hàng trước bàn tech lead, tech lead phải đọc mọi spec

Cách 4: hẹn giờ cho người sở hữu policy

  • Mỗi skill policy có một người sở hữu và một người thay. Ba policy của demo đều ghi cả hai trong dòng owner.
  • Đặt thời hạn trả lời, ví dụ hai ngày làm việc. Quá hạn thì chuyển lên trưởng nhóm.
  • Đếm số câu hỏi mỗi người nhận mỗi tuần. Con số tăng đều là tín hiệu skill chưa đủ rõ, cần viết lại để agent tự xử lý được nhiều hơn.

Ở team nhỏ, người sở hữu và người thay có khi là cùng một người, nhưng ghi tên ra vẫn đáng.

Cách 5: bắt đầu skill từ chỗ đau nhất

Đừng cố viết skill cho mọi policy. Xem lại các lần review gần đây, policy nào bị nhắc nhiều nhất thì viết skill cho nó trước. Một skill tốt cho một policy hay bị vi phạm có giá trị hơn mười skill chung chung.

Còn với dự án mobile, spec cần thêm mấy mục mà agent hay bỏ sót, như trạng thái mất mạng, quyền camera hay thông báo và quy định review của store. Chỗ này mình để dành một tập riêng.

Tuần đầu tiên

Nếu muốn thử bước Design ở team mình, đây là tuần đầu mình đề xuất:

  1. Lấy một intent.md đã duyệt từ bước Plan.
  2. Chạy prompt sinh spec, có mục giả định và mục chỗ đáng lo.
  3. Product owner và tech lead cùng đọc, ghi lại hai con số: bao nhiêu giả định sai và bao nhiêu chỗ đáng lo là thật.
  4. Viết một skill cho policy gây nhiều vấn đề nhất trong lần đọc đó.
  5. Chạy lại lần hai, so số giả định sai.

Lần hai ít hơn, nghĩa là skill đang làm đúng việc của nó. Muốn bắt đầu nhanh thì chép .claude/skills/write-spec/, một skill policy-* làm khuôn và spec-reviewer từ repo demo, rồi sửa risk-list.md cho hợp với team trước tiên.

Tạm Kết

Requirements và design từng tách đôi vì có lý do: mỗi bước một người chịu trách nhiệm, ở cái thời code còn đắt. Playbook gộp hai bước vào một session, nơi Claude viết spec.md từ intent.md đã duyệt và policy được áp qua skill ngay lúc viết.

Demo nhỏ của mình thêm một điều: bước Design không làm bản spec dài hơn. Nó làm cho những chỗ agent đã tự quyết hiện ra, trước khi có ai bắt tay code dựa trên một quyết định mà không ai nhớ là mình đã đưa ra. Muốn vậy, spec phải có chỗ bắt buộc ghi giả định, agent phải bị cấm tự chọn khi policy cãi nhau và người duyệt phải là người.

Tập sau của loạt AI-Native SDLC là Build: spec.md đã duyệt thành plan.md. Plan trước, code sau.

Nguồn

  • Louis Claxton, Anthropic, The AI-native SDLC playbook (21/8/2026), phần Stage 2: claude.com
  • Demo SDLC-2 của mình, chạy ngày 20/10/2026: 12 lượt cộng 1 lượt spec job, hai nhân vật giả lập, mỗi kịch bản một lần. Code, transcript nguyên văn và kết luận: github.com/fx-studio/fx-sdlc-lab (thư mục demo/sdlc-2/).

Cảm ơn bạn đã đọc bài viết này!

FacebookTweetPinYummlyLinkedInPrintEmailShares0

Related Posts:

  • stitch_1200x628_full
    Google Stitch – Phần 3 : Thực chiến tạo design cho…
  • Tui Học AI
    Tui Học AI – Bài 5 – "Tôi xài AI lẻ tẻ" → "Tôi đóng…
  • claude_design
    Claude Design – "Figma Killer" hay chỉ là thêm một…
  • intent
    AI-Native SDLC · Plan: Ý tưởng thành intent.md
Tags: Agentic, AI, AI-Native SDLC, Claude Code
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift Agentic AI AI-Native SDLC AntiGravity api basic ios tutorial blog ci/cd Claude Code closure collectionview combine concurrency Context Engineering crashlytics dart dart basic dart tour Declarative design pattern firebase flavor flutter Google Stitch iOS Nghĩa Địa Skill Prompt engineering Prompt for Coding protocol Python rxswift Skill Swift Swift 5.5 SwiftData SwiftUI SwiftUI Notes tableview testing TuiHocAI UI/UX unittest Vibe Coding

Recent Posts

  • AI-Native SDLC · Design: intent.md thành spec.md
  • AI-Native SDLC · Plan: Ý tưởng thành intent.md
  • Linus Torvalds dùng Claude Code: chuyện thật sau 8 bản vá
  • AI-Native SDLC · Tổng quan: Code nhanh rồi, sao team vẫn chậm?
  • Code rẻ đi thì điểm nghẽn dời về đâu?
  • Cửa sổ ngữ cảnh: nạp lại không phải là nhớ (Tui hỏi AI một câu ngu – Tập 1)
  • Kill switch cho AI agent: guard in “Blocked”, lệnh vẫn chạy
  • Nghĩa địa skill – Tập 5: xoá skill không dùng
  • Nghĩa địa skill – Tập 4: vì sao AI agent chọn công cụ sai
  • Nghĩa địa skill – Tập 3: con số tính năng không ai dùng

You may also like:

  • Tui Học AI – Bài 5 – "Tôi xài AI lẻ tẻ" → "Tôi đóng…
    Tui Học AI
  • Claude Design – "Figma Killer" hay chỉ là thêm một…
    claude_design
  • AI-Native SDLC · Plan: Ý tưởng thành intent.md
    intent
  • Prompt Engineering - Con Đường Để Trở Thành Một Nghề Nghiệp
    feature_bg_blog_007
  • Guided Generation - Khi Swift type trở thành hợp…
    Guided Generation

Archives

  • October 2026 (4)
  • September 2026 (9)
  • August 2026 (2)
  • July 2026 (7)
  • June 2026 (13)
  • May 2026 (2)
  • April 2026 (5)
  • March 2026 (5)
  • February 2026 (1)
  • January 2026 (10)
  • December 2025 (1)
  • October 2025 (1)
  • September 2025 (4)
  • August 2025 (5)
  • July 2025 (10)
  • June 2025 (1)
  • May 2025 (2)
  • April 2025 (1)
  • March 2025 (8)
  • January 2025 (7)
  • December 2024 (4)
  • September 2024 (1)
  • July 2024 (1)
  • June 2024 (1)
  • May 2024 (4)
  • April 2024 (2)
  • March 2024 (5)
  • January 2024 (4)
  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (116)
  • Code (11)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (106)
  • No Category (1)
  • RxSwift (37)
  • SwiftUI (80)
  • Tutorials (112)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2026 Fx Studio - All rights reserved.