teach-me-ai / sources / SP-6
⟵ กลับหน้าแทร็กเสริม
SP-6 · Superpowers

เขียน Skill ของตัวเอง

⏱️ ~22 นาที 🎯 เขียน SKILL.md ที่ trigger ถูกจังหวะและกระชับ 📦 ต้นทาง: skills/writing-skills

บทก่อนหน้าคุณเห็น 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 ตรง กับสิ่งที่กำลังทำอยู่เท่านั้น
--- frontmatter (YAML) --- name kebab-case ไม่มีวงเล็บ description ★ ตัวตัดสิน trigger "Use when..." + อาการ/สถานการณ์เจาะจง ถูกสแกนทุกครั้ง แม้ไม่ได้ใช้ skill นี้ ▼ ตรงเงื่อนไข → โหลดต่อ # Body (Markdown) — โหลดเมื่อ match เท่านั้น Overview หลักการ When to Use ขอบเขต Quick Ref ตาราง/checklist Common Mistakes พลาดตรงไหนบ่อย
description ถูกสแกนตลอดเวลา (ต้องกระชับ+เจาะจง) ส่วน body ถูกอ่านเต็มก็ต่อเมื่อ 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")

1. เจอปัญหา 🧩 เช่น DTO ไม่มี validation decorator 2. สแกน desc. 🔍 ของ skill ทุกตัว (เบา ไม่กิน context) 3. ตรงไหม? 🤔 description ตรง เงื่อนไขหรือเปล่า 4. โหลด body 📖 อ่านขั้นตอน เต็มแล้วทำตาม
description ผิด → agent วนอยู่แค่ขั้น 3 (ไม่โหลด หรือโหลดผิดตัว) ไม่ว่า body จะเขียนดีแค่ไหนก็ไม่ถูกใช้

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:

  1. เขียน name (kebab-case, เป็น gerund ก็ได้ เช่น checking-..., reviewing-...) และ description ที่ขึ้นต้นด้วย "Use when..." บอกอาการ/สถานการณ์ล้วนๆ ห้ามสรุปขั้นตอนการทำงาน
  2. เช็คตัวเอง: description นี้ กว้างไปจนโหลดมั่ว หรือ แคบไปจนไม่มีวันตรง ไหม? ถ้าไม่แน่ใจ ลองอ่านออกเสียงแล้วถามว่า "สถานการณ์ไหนบ้างที่เข้าเงื่อนไขนี้"
  3. ร่าง body สั้นๆ 3 หัวข้อพอ: Overview (1-2 ประโยค), Quick Reference (ตาราง/checklist), Common Mistakes (พลาดตรงไหนบ่อย) — ยังไม่ต้องยาว ขอแค่โครงถูก
  4. ตอบคำถามคิดต่อ: skill นี้ควรวางที่ EN/dot-claude/skills/ (พกพา) หรือ .claude/skills/ ของโปรเจกต์นั้น (เฉพาะที่)? เพราะอะไร?

เขียนคำตอบในแชท แล้วพิมพ์ /quiz SP-6 เพื่อทดสอบความเข้าใจ