ใช้การอ้างอิง @file, allowed-tools, subagent และเครื่องมือ MCP เพื่ออัปเกรด slash command จากทางลัดเป็นคลัง workflow ของทีม
สองบทความแรกพูดถึงว่า slash command คืออะไร (ไฟล์ Markdown ไฟล์หนึ่ง) และวิธีใช้ prefix ! เพื่อฉีด output ของ shell เข้าไปใน context บทความนี้ไปไกลกว่านั้น: วิธีทำให้คำสั่งเดียวประสานความสามารถที่แข็งแกร่งที่สุดของ Claude Code — การอ้างอิงไฟล์, subagent, เครื่องมือ MCP — พร้อมคุมสิทธิ์ไว้ให้ได้
พอมาถึงชั้นนี้ command ก็ไม่ใช่แค่ "ทางลัดของ prompt" อีกต่อไป แต่กลายเป็น workflow ขนาดเล็กที่ใช้ซ้ำได้
@file: การฉีดเนื้อหาแบบคงที่ที่เหมาะกว่า !cat!cat file.md สามารถยัดเนื้อหาของไฟล์เข้า context ได้ก็จริง แต่มันวิ่งผ่าน shell จึงมีข้อเสียอยู่หลายข้อ: ทุกครั้งที่เรียกต้องเปิด subprocess; ถ้า path ไฟล์มีช่องว่างหรืออักขระพิเศษก็ต้อง escape เพิ่ม; และ Claude Code จะไม่มอง path นั้นว่าเป็น "ไฟล์หนึ่งไฟล์" มันจะเป็นแค่ข้อความก้อนหนึ่งเท่านั้น
การอ้างอิง @ เป็นของ native:
---
description: รีวิวการเปลี่ยนแปลงตามมาตรฐานโปรเจกต์
---
อ้างอิงมาตรฐานต่อไปนี้:
@.claude/context/coding-standards.md
@.claude/context/security-checklist.md
ตอนนี้รีวิวการเปลี่ยนแปลงใน git diff และชี้ทุกจุดที่ละเมิดมาตรฐาน
!`git diff HEAD`
@path เป็นการบอก Claude Code ว่า "ให้แนบไฟล์นี้เข้ากับบทสนทนาเสมือนเป็น attachment" ความต่างอยู่ที่:
| สถานการณ์ | ใช้ !cat |
ใช้ @ |
|---|---|---|
Path มาจาก argument ($ARGUMENTS) |
✅ ใช้ได้แค่ !cat |
❌ @ ไม่รองรับการขยายตัวแปร |
| มาตรฐาน/เทมเพลตโปรเจกต์ที่คงที่ | ⚠️ ใช้ได้แต่หนัก | ✅ Native ประหยัดการเรียก shell |
| เนื้อหาไดนามิก (diff, log, ผลเทสต์) | ✅ ต้อง ! |
❌ ใช้ไม่ได้ |
กฎทั่วไป: ไฟล์คงที่ใช้ @, output ไดนามิกใช้ !, path ที่เป็นพารามิเตอร์ใช้ !cat $ARGUMENTS
allowed-tools: ตีเส้นขอบเขตสิทธิ์ให้ commandโดยดีฟอลต์ ตอนรัน command โมเดลจะใช้ได้ทุกเครื่องมือใน session นี่บางทีก็ไม่ใช่สิ่งที่คุณอยากได้ — เช่น /review เป็นงานรีวิวแบบ read-only คุณไม่อยากให้มัน "เผลอมือ" ไปแก้โค้ดแม้สักบรรทัด
ใส่ allowed-tools ใน frontmatter ตอน command กำลังทำงาน จะอนุญาตเฉพาะเครื่องมือที่อยู่ในรายชื่อเท่านั้น:
---
description: รีวิวโค้ดแบบอ่านอย่างเดียว
allowed-tools: Read, Grep, Glob, Bash(git diff:*), Bash(git log:*)
---
รีวิวความต่างระหว่างบรานช์ปัจจุบันกับ master อ่านอย่างเดียว ห้ามแก้
!`git diff master...HEAD`
จุดสำคัญ:
Bash(git diff:*) เป็นการให้สิทธิ์แบบละเอียด — อนุญาตเฉพาะคำสั่ง bash ที่ขึ้นต้นด้วย git diff, git push จะโดนบล็อกRead / Grep / Glob ระบุชัดเจนว่าให้เฉพาะเครื่องมือ read-onlyEdit / Write ไว้ ดังนั้นถึงโมเดลจะอยากแก้โค้ดก็เรียกไม่ได้ในทางเดียวกัน command สิทธิ์สูงอย่าง /deploy ก็ให้สิทธิ์ย้อนทางได้:
---
description: Deploy บรานช์ปัจจุบัน
allowed-tools: Bash(kamal deploy:*), Bash(git push:*), Read
---
การเขียนตายตัวว่า "command นี้ทำอะไรได้บ้าง" เชื่อถือได้กว่าการพึ่งให้คนมานั่งรีวิว prompt bash แต่ละครั้งเป็นไหนๆ
งานบางประเภททำให้ context ของบทสนทนาหลักระเบิด — ไล่อ่านไฟล์หลายสิบไฟล์เพื่อหา call site ทุกจุดของฟังก์ชัน, รันสถิติ codebase, ดึง log ก้อนใหญ่มาวิเคราะห์ ถ้าทำตรงๆ ในบทสนทนาหลัก output หลายพันบรรทัดจะค้างอยู่ใน context แล้วบทสนทนาช่วงต่อไปก็จะช้าลงและโง่ลง
วิธีที่ถูกคือโยนงานแบบนี้ให้ subagent: subagent รันใน context ของตัวเอง พอรันเสร็จก็แค่หอบข้อสรุปกลับมาที่บทสนทนาหลัก ใน command แค่สั่งให้ชัดเจนเท่านั้น:
---
description: สำรวจทุกการใช้งานของสัญลักษณ์อย่างลึก
allowed-tools: Task
---
ใช้ Explore subagent สำรวจทุกการใช้งานของสัญลักษณ์ต่อไปนี้อย่างลึก: $ARGUMENTS
ให้ subagent ครอบคลุม:
- call site ทุกจุด (รวมไฟล์เทสต์)
- สถานการณ์ทางธุรกิจที่ครอบคลุม
- มีการ implement ทางเลือกที่เทียบเท่ากันหรือไม่
หลัง subagent กลับมา ให้ฉันเฉพาะสรุปความยาว ≤300 คำ อย่าแปะโค้ดดิบๆ
ทริก /trace SomeClass#some_method แล้ว Claude Code จะเปิด Explore subagent กวาด codebase แบบขนาน บทสนทนาหลักรับแค่ข้อสรุปที่กลั่นแล้ว ไม่มี output จาก grep ไม่มี snippet ของไฟล์ context ก็สะอาด
การเล่นที่สูงขึ้นไปอีก:
---
description: สำรวจทางเลือกสามแบบแบบขนาน
allowed-tools: Task
---
เปิด 3 subagent พร้อมกัน สำรวจเส้นทางการ implement สามแบบต่อไปนี้:
1. ใช้ ActiveJob + Sidekiq ที่มีอยู่แล้ว
2. ใช้ Solid Queue
3. สร้าง queue น้ำหนักเบาขึ้นเอง
แต่ละ agent ตอบ: ปริมาณงาน, ความเสี่ยง, ระดับการแทรกซึมเข้าโค้ดเดิม หลังได้ข้อสรุปทั้งสามฝั่งกลับมา เดี๋ยวฉันจะเอามาเทียบเอง
สาม subagent รันขนานกัน บทสนทนาหลักรอผลแค่รอบเดียว นี่คือ leverage ที่ใหญ่ที่สุดตัวหนึ่งที่ command ให้ได้ — แปลงงานวิจัยที่ "ต้องใช้ token เยอะมากกว่าจะได้ข้อสรุป" ให้กลายเป็น workflow แบบแตะครั้งเดียว
ถ้า session เชื่อมต่อกับ MCP server (Linear, GitHub, Sentry, proxy ฐานข้อมูลที่สร้างเอง ฯลฯ) command ก็สั่งโมเดลเรียกเครื่องมือเหล่านี้ได้ตรงๆ:
---
description: สร้าง todo การ implement จาก Linear issue
allowed-tools: mcp__linear__*, Read, Grep
---
อ่านรายละเอียดและคอมเมนต์ทั้งหมดของ Linear issue $ARGUMENTS
เอามาผสมกับสถานะปัจจุบันของ codebase (ใช้ Grep/Read หาไฟล์ที่เกี่ยวข้องเอง) แล้วเรียงเป็น todo การ implement:
- ต้องแก้ไฟล์ไหนบ้าง
- แต่ละขั้นแยก commit หรือรวมกัน
- มีจุดคลุมเครือที่ต้องเคลียร์กับ PM ก่อนไหม
อย่าเพิ่งเขียนโค้ด ออกแค่แผน
mcp__linear__* ให้สิทธิ์เครื่องมือ Linear MCP ทั้งหมด โมเดลจะดึงรายละเอียด issue, คอมเมนต์, สถานะได้ ทั้ง command นี้จึงกลายเป็นจุดเริ่ม workflow "จาก ticket สู่แผนการ implement"
จุดสำคัญ: เวลาเขียนชื่อเครื่องมือ MCP ใน allowed-tools ต้องใช้ prefix เต็มของมัน (mcp__<server>__<tool>) ไม่อย่างนั้นสิทธิ์จะไม่มีผล
ความเข้าใจผิดที่เจอบ่อยมาก: เขียน /test ในไฟล์ของ /review แล้วคิดว่าจะไปทริก test command ไม่ไปทริก slash command จะถูกขยายแค่ครั้งเดียวในชั้น input ระดับบนสุดของผู้ใช้เท่านั้น; /xxx ที่อยู่ใน command เป็นแค่ข้อความธรรมดา โมเดลจะอ่านมันได้ แต่ Claude Code ไม่ไปรันให้
ถ้าอยากคอมโพสหลาย command วิธีที่ถูกมีหลายแบบ:
วิธี A: แยก logic ที่ใช้ร่วมเป็นไฟล์ context แต่ละ command ก็ใช้ @ หรือ !cat อ้างอิง
@.claude/context/review-checklist.md
@.claude/context/security-checklist.md
วิธี B: ใน command เขียนตรงๆ ว่า "ทำเหมือน /review" + ทวนคำสั่งสำคัญซ้ำ
ไม่สง่างามแต่ใช้ได้ แค่ prompt ชัดเจนพอ โมเดลก็จะทำตามแนวทางเดิม
วิธี C: ให้ command หนึ่งใช้เครื่องมือ Task เปิด subagent แล้วใน prompt ของ subagent ก็เรียกใช้ชุดไฟล์ context ชุดเดียวกันอีกที
การประสาน workflow จริงๆ ใช้เส้นทางนี้ทั้งหมด command แม่ทำหน้าที่จัดคิวและสรุป ส่วน subagent ทำหน้าที่รันขั้นตอนจริง
Anti-pattern ที่ต้องเลี่ยง: เขียน command ยาวเป็นร้อยบรรทัด พยายามให้คำสั่งเดียวทำทุกอย่างจบ พอ granularity ระเบิดแล้วต้นทุนการดูแลจะพุ่ง และงบ token ต่อรอบก็จะถูก command ตัวเดียวกินเกลี้ยง
เขียนมาถึงตรงนี้ กลไกการฉีด "ความสามารถภายนอก" เข้ากับ command ใน Claude Code ก็ครบแล้ว เลือกใช้งานยังไง:
| ความต้องการ | กลไกที่ควรเลือก |
|---|---|
| มาตรฐาน/เทมเพลต/เอกสาร context ที่คงที่ | การอ้างอิง @file |
| สถานะ real-time (diff, log, ผลเทสต์, query DB) | การฉีด !shell |
| เนื้อหาไฟล์ที่เป็นพารามิเตอร์ | !cat $ARGUMENTS |
| งานวิจัยกิน context, ค้นหาข้ามไฟล์ | subagent ผ่าน Task |
| ระบบภายนอก (issue tracker, monitoring, ข้อมูล production) | เครื่องมือ MCP + allowed-tools |
| Workflow หลายขั้นแบบต่อเนื่อง/ขนาน | command แม่เรียก subagent |
ขอบเขตสิทธิ์ประกาศชัดเจนผ่าน allowed-tools โดยเฉพาะ command ที่ใช้ร่วมกันในทีม — เขียนล็อกไว้ว่ามันทำอะไรได้ เชื่อถือได้กว่าพึ่งการอนุมัติด้วยมือทุกครั้ง
เอาทุกอย่างมารวมกัน ดู command "สำรวจเส้นทางการ implement จาก Linear ticket" กัน:
---
description: สร้างแผนการ implement จาก Linear ticket
allowed-tools: mcp__linear__*, Task, Read, Grep, Glob, Bash(git log:*)
---
## Context
@.claude/context/architecture.md
@.claude/context/coding-standards.md
## สถานะ codebase ปัจจุบัน
!`git log --oneline -10`
## ภารกิจ
ดึงรายละเอียด, คอมเมนต์, และ ticket ที่เกี่ยวข้องของ Linear ticket $ARGUMENTS
จากนั้นเปิด subagent สองตัวรันขนานกัน:
1. ตัวแรก: ไปหาใน codebase ว่ามี implementation ที่เกี่ยวข้องอะไรอยู่แล้วบ้าง มีโมดูลที่ใช้ซ้ำได้ไหม
2. ตัวที่สอง: ประเมินความเสี่ยง — การเปลี่ยนแปลงครั้งนี้จะไปแตะเส้นทางโค้ดที่ traffic สูงตัวไหน มีช่องโหว่ test coverage ตรงไหน
หลังทั้งสอง agent กลับมา ออกผลลัพธ์:
- ขั้นตอนการ implement (เรียงตามลำดับ dependency)
- รายการความเสี่ยง
- ระดับ granularity ของ commit ที่แนะนำ
ยังไม่ต้องเขียนโค้ด
ทริก /plan ENG-4213 คำสั่งเดียวรันจบหมด: ดึง ticket → สำรวจ codebase แบบขนาน → ประเมินความเสี่ยง → สรุปแผน ผู้ใช้มีหน้าที่แค่อ่านข้อสรุปแล้วตัดสินใจว่าจะลงมือ
นี่คือเส้นโค้งที่ครบถ้วนของ slash command สามบทแรก: นิยาม prompt ที่ใช้ซ้ำได้ (intro) → ฉีด context แบบไดนามิก (context) → ประสานเครื่องมือและ subagent (บทนี้) พอมาถึงชั้นนี้ .claude/commands/ ก็ไม่ใช่ทางลัดอีกต่อไปแล้ว แต่เป็นคลัง workflow ขนาดเล็กของทีม