เขียน Skill ของตัวเอง
บทก่อนหน้าคุณเห็น skill สำเร็จรูป มาแล้วหลายตัว (code-review, tdd, brainstorming)
บทนี้คุณจะได้รู้ว่าเบื้องหลัง skill พวกนั้นเขียนยังไง และเขียนของตัวเองได้
เป้าหมายคือจบบทนี้แล้วคุณร่าง SKILL.md ได้ 1 ไฟล์ที่
trigger
(ตัวกระตุ้น — จังหวะที่ Claude ตัดสินใจโหลด) ถูกจังหวะจริง ไม่ใช่แค่เขียนสวยแต่ไม่มีใครเรียกใช้
1. กายวิภาคของ SKILL.md — สองส่วนที่ทำงานคนละจังหวะ
skill คือโฟลเดอร์ 1 อัน มีไฟล์ SKILL.md เป็นไฟล์หลัก (required) และอาจมีไฟล์เสริม
(reference/script/template) แนบอยู่ด้วยถ้าจำเป็น แต่ตัว SKILL.md เองแบ่งเป็น 2 ส่วนที่
ถูกใช้งานคนละเวลา:
-
Frontmatter (YAML) — ส่วนหัวใน
---มี 2 ช่องบังคับคือnameและdescriptionยาวรวมกันไม่เกิน 1024 ตัวอักษร ส่วนนี้ ถูกสแกนตลอดเวลา ทุก skill ในระบบ ไม่ว่าจะใช้หรือไม่ก็ตาม - Body (เนื้อ Markdown) — Overview, When to Use, Quick Reference, Common Mistakes ฯลฯ ส่วนนี้ โหลดเข้ามาเฉพาะตอนที่ description ตรง กับสิ่งที่กำลังทำอยู่เท่านั้น
ผลตามมาที่สำคัญมาก: description คือส่วนที่แพงที่สุดต่อคุณภาพของ skill
เพราะมันถูกอ่านทุกครั้งไม่ว่าจะได้ใช้จริงหรือไม่ ส่วน body เขียนยาวแค่ไหนก็ไม่กระทบ skill อื่น
เพราะมันโหลดเฉพาะตอนถูกเรียกเท่านั้น
2. เขียน description ให้ trigger ถูกจังหวะ
กติกาจากไฟล์ต้นทาง writing-skills/SKILL.md ชัดเจนมาก: description ต้อง
ขึ้นต้นด้วย "Use when..." เขียนบุคคลที่สาม (third person) และบอก
"เมื่อไหร่ควรใช้" เท่านั้น — ห้ามสรุปว่า skill ทำอะไรหรือมีขั้นตอนยังไง
ทำไมห้ามสรุป workflow ใน description: ไฟล์ต้นทางเล่าเคสจริงว่า skill ตัวหนึ่งเขียน description ว่า "code review between tasks" ผลคือ agent ทำ review แค่ครั้งเดียว ทั้งที่เนื้อ skill (flowchart) บอกชัดว่าต้อง review 2 รอบ (compliance แล้วค่อย quality) พอเปลี่ยน description เหลือแค่ "Use when executing implementation plans with independent tasks" (ไม่มีสรุป workflow) agent ถึงจะอ่าน flowchart จริงแล้วทำ 2 รอบตามที่ควร — description ที่สรุป workflow กลายเป็น "ทางลัด" ที่ agent เลือกเดินแทนการอ่าน body จริง
| ตัวอย่าง description | |
|---|---|
| ❌ สรุป workflow | Use when executing plans - dispatches subagent per task with code review between tasks |
| ❌ กว้างเกินไป | For async testing — ไม่บอกว่า "เมื่อไหร่" เลย |
| ❌ บุคคลที่หนึ่ง | I can help you with async tests when they're flaky |
| ✅ ระบุ trigger เจาะจง | Use when tests have race conditions, timing dependencies, or pass/fail inconsistently |
| ✅ เจาะจงเทคโนโลยี (เมื่อ skill เฉพาะทางจริง) | Use when using React Router and handling authentication redirects |
สังเกตแพตเทิร์น: description ที่ดีอธิบาย "อาการ/ปัญหา" (symptom) ไม่ใช่ "รายละเอียดเฉพาะภาษา" เช่น พูดว่า "race condition" ไม่ใช่ "setTimeout" — เว้นแต่ตัว skill เองผูกกับเทคโนโลยีนั้นจริงๆ ก็ให้ระบุชัดไปเลย (เช่น "React Router")
3. เขียนให้กระชับ คาดเดาได้ ทดสอบได้
ไฟล์ต้นทางให้เป้าจำนวนคำไว้ชัดเจน เพราะ skill ที่โหลดบ่อยกินบริบท (context) ของทุกงาน:
| ประเภท skill | เป้าความยาว |
|---|---|
| โหลดทุก session (getting-started) | < 150 คำ/skill |
| ถูกเรียกบ่อย | < 200 คำ รวม |
| skill ทั่วไป | < 500 คำ (ยังต้องกระชับ) |
- ตัวอย่างเดียวที่ดี ดีกว่าหลายตัวอย่างกลางๆ — อย่าเขียนโค้ดตัวอย่างซ้ำหลายภาษา
-
ไฟล์เสริมแยกเฉพาะที่จำเป็นจริง — reference หนักๆ (100+ บรรทัด) หรือ tool/script
ที่ reuse ได้ ค่อยแยกไฟล์ ส่วน concept/pattern สั้นๆ เก็บไว้ใน
SKILL.mdเอง -
อ้างอิง skill อื่นด้วยชื่อ ไม่ force-load — เขียน
**REQUIRED BACKGROUND:** ใช้ superpowers:test-driven-developmentอย่าใช้@skills/...เพราะ@จะโหลดไฟล์ทันทีทั้งไฟล์ (กิน context ก่อนเวลาที่ต้องใช้จริง)
เขียน skill คือ TDD ของงานเอกสาร: หลักการต้นทางบอกว่า "ถ้าคุณไม่เคยเห็น agent ทำผิดตอนไม่มี skill คุณไม่รู้หรอกว่า skill สอนถูกจุดไหม" วิธีทดสอบคร่าวๆ: (1) RED — ลองสั่งงานแบบไม่มี skill ดูว่า agent พลาดตรงไหน (2) GREEN — เขียน skill แก้เฉพาะจุดที่พลาดจริง ไม่ใส่ของที่ยังไม่เจอปัญหา (3) REFACTOR — เจอช่องโหว่ใหม่ ก็เติมกฎปิดช่องนั้นแล้วทดสอบซ้ำ
4. ตัวอย่าง: ร่าง skill ตรวจ convention ของ NestJS module
สมมติทีมของคุณเจอปัญหาซ้ำๆ: PR เพิ่ม endpoint ใหม่แต่ลืมใส่ class-validator
decorator ใน DTO หรือยัด business logic ไว้ใน controller แทนที่จะส่งต่อให้ service
— นี่คือ pattern ที่ "เจอซ้ำข้ามโปรเจกต์" เข้าเกณฑ์ควรทำเป็น skill (ไม่ใช่ one-off)
---
name: reviewing-nestjs-modules
description: Use when creating or reviewing a NestJS module — checks DTO
validation decorators, controller/service separation, and provider registration
---
# Reviewing NestJS Modules
## Overview
NestJS module ที่ดี: controller บาง, service มี business logic, DTO validate ครบ
## When to Use
- เพิ่ม endpoint ใหม่ หรือรีวิว PR ที่แก้ controller/DTO
- controller มี logic เกิน routing + delegate (เช่น query DB ตรงๆ)
- DTO ไม่มี @IsString() / @IsNotEmpty() ฯลฯ กำกับ field
## Quick Reference
| จุดตรวจ | ต้องเป็น |
|---|---|
| DTO field | มี decorator จาก class-validator ครบทุก field ที่รับจาก client |
| Controller | เรียก service เท่านั้น ไม่ query DB / ไม่มี business rule |
| Module | ประกาศ provider ใน providers ก่อน inject ใน constructor |
## Common Mistakes
- ลืม @ValidateNested() เมื่อ DTO ซ้อน DTO อีกที
- Service ไม่ throw NotFoundException แต่ return null เงียบๆ
ถ้าเป็นฝั่ง Go แนวเดียวกัน ตั้งชื่อ reviewing-go-error-wrapping description
จะเป็น "Use when writing or reviewing Go functions that return errors — checks that
errors are wrapped with %w and context, not swallowed or returned bare"
— โครงเดียวกันเป๊ะ แค่ Quick Reference/Common Mistakes เปลี่ยนไปตามภาษา
5. เขียนเสร็จแล้ว วางไฟล์ไว้ที่ไหน
ในโปรเจกต์นี้มี 2 เส้นทาง ขึ้นกับว่า skill ที่คุณเขียน "ใช้ได้ข้ามโปรเจกต์" หรือ "เฉพาะโปรเจกต์นี้":
-
Skill พกพา (ใช้ได้ข้ามโปรเจกต์) — เขียนไว้ที่
EN/dot-claude/skills/<ชื่อ>/SKILL.md(ภาษาอังกฤษ ตามกติกาในCLAUDE.md) แล้วก๊อปคู่แปลไทยไว้ที่TH/dot-claude/skills/<ชื่อ>/SKILL.md— มีเทมเพลตเปล่าให้เริ่มจากตรงนี้ได้เลยที่EN/dot-claude/skills/example-skill/SKILL.md -
Skill เฉพาะโปรเจกต์นั้นๆ — วางไว้ใน runtime skills directory ของโปรเจกต์เอง
คือ
.claude/skills/<ชื่อ>/SKILL.mdที่ root ของโปรเจกต์นั้น (ไม่ต้องพกมาที่นี่)
กติกาการเลือกเหมือนกับ agent ใน SP ก่อนๆ: ถามตัวเองว่า "เพื่อนที่ทำโปรเจกต์อื่น (คนละ tech stack ก็ได้) ได้ประโยชน์จาก skill นี้ไหม" ถ้าใช่ → พกพา ถ้าเป็น convention เฉพาะทีม/โปรเจกต์ → เก็บไว้ที่โปรเจกต์นั้นพอ
6. กับดักที่พบบ่อยที่สุด: description กว้างไป vs แคบไป
กว้างไป เช่น Use when working with code — โมเดลจะโหลด skill นี้
แทบทุกครั้งที่ทำงาน แม้ไม่เกี่ยวจริง context เปลืองไปฟรีๆ และเสี่ยง skill ตัวอื่นแย่งกันโหลดจนสับสน
แคบไป เช่น Use when reviewing DTO validation in file src/user/create-user.dto.ts
— ระบุเฉพาะเจาะจงจนใช้ได้แค่ไฟล์เดียว ทั้งที่ปัญหาเดียวกันเกิดกับ DTO ไฟล์อื่นได้เหมือนกัน
สุดท้าย skill ไม่ถูกเรียกตอนที่ควรจะเรียก
จุดพอดี: อธิบาย "อาการ/สถานการณ์" ให้ครอบคลุมทุกที่ที่ปัญหานี้เกิดได้ แต่ยังเจาะจง
พอที่ไม่ทับซ้อนกับ skill อื่น — เหมือนตั้งชื่อ error message ที่ทั้งเจาะจงและ reuse ได้
เลือกงานซ้ำๆ ที่คุณเจอบ่อยในงาน NestJS/Go/MongoDB/PostgreSQL แล้วลองเขียน frontmatter:
-
เขียน
name(kebab-case, เป็น gerund ก็ได้ เช่นchecking-...,reviewing-...) และdescriptionที่ขึ้นต้นด้วย "Use when..." บอกอาการ/สถานการณ์ล้วนๆ ห้ามสรุปขั้นตอนการทำงาน - เช็คตัวเอง: description นี้ กว้างไปจนโหลดมั่ว หรือ แคบไปจนไม่มีวันตรง ไหม? ถ้าไม่แน่ใจ ลองอ่านออกเสียงแล้วถามว่า "สถานการณ์ไหนบ้างที่เข้าเงื่อนไขนี้"
- ร่าง body สั้นๆ 3 หัวข้อพอ: Overview (1-2 ประโยค), Quick Reference (ตาราง/checklist), Common Mistakes (พลาดตรงไหนบ่อย) — ยังไม่ต้องยาว ขอแค่โครงถูก
-
ตอบคำถามคิดต่อ: skill นี้ควรวางที่
EN/dot-claude/skills/(พกพา) หรือ.claude/skills/ของโปรเจกต์นั้น (เฉพาะที่)? เพราะอะไร?
เขียนคำตอบในแชท แล้วพิมพ์ /quiz SP-6 เพื่อทดสอบความเข้าใจ