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

ทำงานหลาย agent ขนาน + แยกพื้นที่ด้วย worktree

⏱️ ~20 นาที 🎯 เข้าใจ subagent-driven dev, การกระจายงานขนาน และการแยก workspace 📦 ต้นทาง: skills/subagent-driven-development · dispatching-parallel-agents · using-git-worktrees

จนถึงตอนนี้เราคุยกันเรื่อง "agent เดียวทำงานเดียว" — วน core loop, ใช้ skill, ทำ TDD/debug ให้ครบก่อนค่อยส่งต่อ แต่พองานใหญ่ขึ้น (เช่น implement plan ที่มีหลาย task หรือต้องรีวิวโค้ดหลายมุมพร้อมกัน) การนั่งไล่ทำทีละอย่างในเซสชันเดียวจะช้าและ context บวมเร็ว บทนี้จะพาไปดู 3 สกิลที่ทำงานคู่กันเพื่อแก้ปัญหานี้: subagent-driven-development (แตกงานให้ subagent ทำทีละ task พร้อมรีวิว), dispatching-parallel-agents (ตัดสินใจว่าเมื่อไรควรยิงงานขนานได้จริง) และ using-git-worktrees (แยกพื้นที่ทำงานไม่ให้ agent ชนกัน) — สามอย่างนี้คือฐานของการทำงานแบบ "หัวหน้าทีมสั่งงานลูกทีม" ที่เอาไปใช้กับงาน dev จริงได้ทันที

Subagent-Driven Development — orchestrator แตกงานให้ subagent

ไอเดียหลักตามสเปกใน skills/subagent-driven-development/SKILL.md คือ: เมื่อมี implementation plan ที่ task ส่วนใหญ่ independent กัน (ไม่ต้องพึ่งผลลัพธ์ของกันและกันมาก) และอยากอยู่ใน session เดิม (ไม่ย้ายไป session คู่ขนานแบบ executing-plans) ให้ agent หลัก (ทำหน้าที่เป็น orchestrator) ยิง subagent ใหม่เอี่ยมทีละ task ไม่ใช่ทำเองทั้งหมด

เหตุผลตามต้นฉบับ: "You delegate tasks to specialized agents with isolated context... They should never inherit your session's context or history — you construct exactly what they need. This also preserves your own context for coordination work." พูดง่าย ๆ คือ subagent แต่ละตัวเห็นแค่สิ่งที่ orchestrator ป้อนให้ (task brief) เท่านั้น ไม่เห็นประวัติสนทนาทั้งเซสชัน — ทำให้ subagent โฟกัสงานตัวเองได้เต็มที่ และ context ของ orchestrator เองก็ไม่บวมจากรายละเอียดที่ subagent คุยกับตัวเอง

Orchestrator อ่าน plan · สร้าง todos PER TASK (ทำซ้ำจนครบทุก task) Implementer subagent ใหม่ TDD → commit → self-review Task Reviewer อ่าน diff (review-package) spec ✅/❌ + quality ผ่านไหม? spec + quality ❌ ไม่ผ่าน → dispatch fix subagent → รีวิวใหม่ ✅ ผ่าน มาร์ก task เสร็จ → task ถัดไป Final whole-branch review (ทั้ง branch)
Orchestrator ไม่เขียนโค้ดเอง — แค่แตก task, ยิง implementer subagent ทีละตัว, ตรวจผ่าน task reviewer, วนแก้จนผ่านค่อยไป task ถัดไป แล้วปิดท้ายด้วยรีวิวทั้ง branch

จุดที่ต้องเน้น: subagent ไม่ได้อ่าน plan ทั้งไฟล์ — orchestrator จะสกัด "task brief" เฉพาะ task นั้นให้ (สคริปต์ task-brief ในสกิลจริง) แล้วส่งไฟล์ path ให้ subagent อ่านเอง เพื่อไม่ให้ prompt ยาวจนบวม context ของ orchestrator เอง เช่นเดียวกับตอนรีวิว — reviewer จะได้รับ "diff package" เป็นไฟล์ ไม่ใช่ paste diff ทั้งดุ้นเข้า prompt

Implementer รายงานสถานะ 4 แบบ — orchestrator ต้องรู้ว่าจะจัดการยังไง

สถานะความหมายorchestrator ทำอะไรต่อ
DONE ทำเสร็จ ทดสอบผ่าน commit แล้ว สร้าง review package แล้วส่งให้ task reviewer
DONE_WITH_CONCERNS ทำเสร็จ แต่มีข้อกังวล อ่านข้อกังวลก่อน — ถ้าเรื่อง correctness/scope ต้องแก้ก่อนรีวิว
NEEDS_CONTEXT ขาดข้อมูลที่จำเป็น ให้ context เพิ่ม แล้ว dispatch ใหม่
BLOCKED ทำต่อไม่ได้ วิเคราะห์ว่าเป็น context ไม่พอ / งานยากเกิน model / plan ผิด แล้วจัดการตามนั้น
💡

เลือก model ตามความยากของ task: งานกลไกล้วน ๆ (แก้ 1-2 ไฟล์ ที่ spec ชัดเจน) ใช้โมเดลถูก/เร็ว งานที่ต้อง integrate หลายไฟล์หรือ debug ใช้โมเดลมาตรฐาน ส่วนงานออกแบบสถาปัตยกรรม รวมถึง final whole-branch review ให้ใช้โมเดลที่แรงที่สุดที่มี — ตามต้นฉบับ: "Always specify the model explicitly when dispatching a subagent" ห้ามปล่อยให้ subagent สืบทอด model ของ session หลักไปเฉย ๆ เพราะมักแพงเกินความจำเป็น

Dispatching Parallel Agents — เมื่อไรควรกระจายงานขนาน

สกิลนี้ตอบคำถามที่ subagent-driven-development ไม่ได้ตอบตรง ๆ: "แล้วเมื่อไรที่ยิง subagent หลายตัว พร้อมกัน ได้จริง (ไม่ใช่ทีละตัวเรียงคิว)?" เงื่อนไขตามสเปกคือ ต้องมีปัญหา/งาน 2 อย่างขึ้นไป ที่:

  • Independent — แต่ละงานเข้าใจและแก้ได้โดยไม่ต้องรู้บริบทของงานอื่น
  • ไม่มี shared state — ไม่แก้ไฟล์เดียวกัน ไม่ใช้ resource เดียวกัน
  • ไม่มีลำดับก่อนหลัง — แก้ปัญหา A ไม่ทำให้ปัญหา B หายหรือเปลี่ยนไป

ถ้าเข้าเงื่อนไขครบ → ยิง dispatch หลายตัวในคำตอบเดียวกัน (ต้นฉบับ: "Multiple dispatch calls in one response = parallel execution. One per response = sequential.") ถ้าปัญหาเกี่ยวโยงกัน (แก้ตัวหนึ่งอาจแก้อีกตัวไปด้วย) หรือมี shared state → ใช้ agent เดียวสืบทั้งหมด หรือยิงแบบ sequential แทน

SEQUENTIAL — งาน dependent / มี shared state Agent A Agent B Agent C รอ A เสร็จก่อน ค่อยเริ่ม B → รอ B เสร็จก่อน ค่อยเริ่ม C PARALLEL — งาน independent ไม่มี shared state Agent A Agent B Agent C A, B, C เริ่มพร้อมกันในคำตอบเดียว → เสร็จเร็วกว่าเรียงคิว
Sequential เหมาะกับงานที่เกี่ยวโยงกัน ส่วน parallel ใช้ได้เมื่อไม่มีอะไรทับซ้อนกันเลย

ตัวอย่างจากต้นฉบับ (สถานการณ์จริง): มี test fail 6 เคสกระจายอยู่ 3 ไฟล์ที่ไม่เกี่ยวกัน (agent-tool-abort.test.ts, batch-completion-behavior.test.ts, tool-approval-race-conditions.test.ts) — แต่ละไฟล์เป็นปัญหาคนละ root cause จึงยิง subagent 3 ตัวพร้อมกัน ตัวละไฟล์ แต่ละตัวได้ scope ชัดเจน + constraint ("ห้ามแก้ไฟล์อื่น") + บอกชัดว่าให้ return อะไรกลับมา (สรุป root cause + สิ่งที่แก้) ผลคือ 3 ปัญหาแก้เสร็จพร้อมกัน ไม่มี conflict แล้วค่อยรัน full test suite รวมเพื่อ verify ทีเดียว

using-git-worktrees — แยกพื้นที่ทำงานไม่ให้ชนกัน

พอเริ่มมีหลาย agent ทำงานพร้อมกันจริง (โดยเฉพาะถ้าแต่ละงานต้องแก้โค้ดจริง ไม่ใช่แค่รีวิว) ปัญหาที่ตามมาคือทุกคนแก้ไฟล์ในโฟลเดอร์เดียวกัน branch เดียวกัน — ชนกันแน่นอน using-git-worktrees แก้ตรงนี้ด้วยการให้แต่ละงาน (หรือแต่ละ session) มี worktree ของตัวเอง — เหมือน clone repo แยก แต่ประหยัดพื้นที่กว่าเพราะแชร์ .git object เดียวกัน

ลำดับที่สกิลนี้ทำจริง (สำคัญ อย่าข้าม step):

  1. Step 0 — เช็กก่อนว่าอยู่ในพื้นที่แยกอยู่แล้วหรือยัง เทียบ git rev-parse --git-dir กับ --git-common-dir ถ้าไม่เท่ากัน (และไม่ใช่ submodule) แปลว่าอยู่ใน worktree แยกอยู่แล้ว — ข้ามไป step 2 ทันที ห้ามสร้างซ้อนอีกชั้น
  2. Step 1 — สร้าง worktree ถ้ายังไม่มี ให้ลองใช้ native tool ของ harness ก่อน (เช่นเครื่องมือ EnterWorktree/คำสั่ง /worktree ถ้ามี) ถ้าไม่มีจริง ๆ ค่อย fallback มาใช้ git worktree add เอง — ลำดับการเลือกโฟลเดอร์คือ เช็ก preference ที่ผู้ใช้ระบุไว้ก่อน → เช็กว่ามี .worktrees/ หรือ worktrees/ อยู่แล้วไหม (ถ้ามีทั้งคู่ .worktrees/ ชนะ) → ถ้าไม่มีเลย default เป็น .worktrees/ ที่ root โปรเจกต์ พร้อมต้องตรวจสอบว่าโฟลเดอร์นี้ถูก .gitignore แล้ว ก่อนสร้างเสมอ (กัน worktree หลุดเข้าไปอยู่ใน commit)
  3. Step 2-3 — setup โปรเจกต์ + รัน test baseline เช่นถ้ามี go.mod รัน go mod download, ถ้ามี package.json รัน npm install แล้วต้องรัน test suite ให้ผ่าน ก่อนเริ่มงานจริง — ถ้า test แดงตั้งแต่ baseline ต้องรายงานและถามก่อน จะได้แยกได้ว่า bug ใหม่ที่ agent ทำ กับ bug เก่าที่มีอยู่แล้ว
# ตัวอย่าง fallback แบบ manual (เมื่อไม่มี native worktree tool)
git check-ignore -q .worktrees || # ต้องถูก ignore ก่อนเสมอ
  (echo ".worktrees/" >> .gitignore && git add .gitignore && git commit -m "chore: ignore worktrees")

git worktree add .worktrees/feature-security-review -b feature-security-review
cd .worktrees/feature-security-review

# NestJS: setup + baseline
npm install
npm test

ทำไมต้องแยก worktree แทนแค่แยก branch เฉย ๆ — เพราะการ checkout branch ในโฟลเดอร์เดียวกัน ทำให้ทำงานสองอย่างพร้อมกันไม่ได้ (checkout ทับกัน ไฟล์ที่แก้ค้างอยู่หาย) worktree ทำให้ แต่ละ branch มีโฟลเดอร์เป็นของตัวเอง agent หลายตัวจึงรันคู่ขนานจริงได้ โดยไม่ต้องกลัวไฟล์ที่ยังไม่ commit ของงานหนึ่งไปกระทบอีกงานหนึ่ง

ผูกกับงานจริง — รีวิว 3 มุมพร้อมกันบนโมดูล NestJS

ตัวอย่างที่ใช้ 3 สกิลนี้ร่วมกันแบบเป็นรูปธรรม: สมมติมีโมดูล UsersModule ใน NestJS ที่เพิ่ง merge ฟีเจอร์ใหม่เข้ามา แล้วอยากรีวิว 3 มุมพร้อมกัน — security, performance, และ type safety การรีวิวทั้ง 3 มุมนี้ independent กันจริง (อ่านโค้ดเดิม ไม่มีใครแก้ไฟล์ ไม่มี shared state) จึงเข้าเงื่อนไข dispatch แบบขนานได้เลย ไม่ต้องแยก worktree ด้วยซ้ำ (เพราะเป็น read-only review ไม่ได้แก้โค้ด)

// ยิงพร้อมกันในคำตอบเดียว — 3 dispatch = parallel
Subagent 1 (security): "รีวิว security ของ src/users/*.ts — เน้น input validation,
  guard/decorator, การจัดการ password/token ห้ามแก้โค้ด คืนเป็นลิสต์ finding พร้อม severity"

Subagent 2 (performance): "รีวิว performance ของ src/users/*.ts — เน้น N+1 query
  ใน UsersService, index ที่ควรมีใน UsersEntity, การ cache ที่ควรเพิ่ม"

Subagent 3 (types): "รีวิว type safety ของ src/users/*.ts — เน้น any ที่หลุดมา,
  DTO validation ตรงกับ entity ไหม, return type ของทุก public method ชัดเจนไหม"

แต่ถ้าโจทย์เปลี่ยนเป็น "ให้ 3 agent แก้บั๊ก ใน UsersService พร้อมกัน" — อันนี้เข้าเงื่อนไข parallel ไม่ได้แล้ว เพราะทั้ง 3 คนต้องแก้ไฟล์เดียวกัน (shared state) ถ้ายิงพร้อมกันจริงจะเกิด conflict ทันที ต้องแยก worktree ให้แต่ละคนก่อน หรือไม่ก็ทำแบบ sequential (แก้ทีละคนในโฟลเดอร์เดียวกัน) — นี่คือเหตุผลที่ subagent-driven-development เขียนไว้ ใน Red Flags ชัดเจนว่า "Never dispatch multiple implementation subagents in parallel (conflicts)" การ implement task ต้องทำทีละตัวเสมอ ต่างจากการรีวิว/สืบสวนที่ทำขนานได้

⚠️

Pitfall ที่พบบ่อยที่สุด: เห็นว่ามีหลาย task ในแผนงาน แล้วรีบยิง implementer subagent หลายตัวพร้อมกันเพื่อ "ให้เร็วขึ้น" ทั้งที่ task พวกนั้น dependent กัน (เช่น task 2 ต้องใช้ interface ที่ task 1 เพิ่งสร้าง) ผลคือโค้ดชนกัน หรือ task 2 เขียนโดยเดา interface ผิด ๆ เพราะ task 1 ยังไม่เสร็จ — ก่อนกระจายงานขนานทุกครั้ง ให้ถามตัวเองก่อนว่า "งานพวกนี้ไม่มีใครรอผลใครจริง ๆ ใช่ไหม" ถ้าไม่แน่ใจ ให้ถือว่า dependent แล้วทำ sequential ไว้ก่อน ปลอดภัยกว่าเสมอ

สรุปเทียบ 3 สกิลนี้แบบไว ๆ

สกิลตอบคำถามอะไรใช้เมื่อ
subagent-driven-development "จะ execute plan หลาย task ในเซสชันนี้ยังไง" มี plan, task ส่วนใหญ่ independent, อยู่ session เดิม
dispatching-parallel-agents "ยิง agent พร้อมกันได้ไหม" 2+ ปัญหา independent ไม่มี shared state ไม่มีลำดับก่อนหลัง
using-git-worktrees "แยกพื้นที่ทำงานยังไงไม่ให้ชนกัน" เริ่มงานใหม่ที่ต้อง isolate จาก workspace ปัจจุบัน โดยเฉพาะก่อน execute plan
🎯 แบบฝึกหัด
  1. สมมติคุณมี Go service ที่มี 3 endpoint พังพร้อมกันหลัง refactor: /users, /orders, /payments — เขียน prompt สำหรับ dispatch 3 subagent (ระบุ scope + constraint + expected output ของแต่ละตัว) แล้วบอกว่าทำไมกรณีนี้ถึง dispatch พร้อมกันได้
  2. ลองคิดสถานการณ์ 1 อย่างที่ "ดูเหมือน" กระจายงานขนานได้ แต่จริง ๆ แล้ว dependent กัน (เช่น เกี่ยวกับ migration ฐานข้อมูล PostgreSQL) อธิบายว่าอะไรทำให้มันไม่ independent และควรจัดการยังไงแทน
  3. ลองรัน git rev-parse --git-dir กับ --git-common-dir ในโปรเจกต์จริงของคุณตอนนี้ (ไม่ต้องสร้าง worktree จริงก็ได้) แล้วดูว่าค่าที่ได้เท่ากันไหม — ถ้าเท่ากันแปลว่าตอนนี้คุณอยู่ใน checkout ปกติ ไม่ใช่ worktree แยก