| name | wayfinder |
| description | วางแผนงานก้อนใหญ่ — ใหญ่เกินกว่าหนึ่ง agent session จะรับไหว — เป็นแผนที่ร่วมของ ticket สำหรับการ investigate บน issue tracker ของคุณ แล้วไล่ resolve ทีละใบจนกว่าเส้นทางไปยังจุดหมายจะชัด |
| disable-model-invocation | true |
ไอเดียหลวม ๆ ก้อนหนึ่งเพิ่งมาถึง — ใหญ่เกินกว่าหนึ่ง agent session และถูกหมอกปกคลุม: เส้นทางจากตรงนี้ไปยัง จุดหมาย (destination) ยังมองไม่เห็น Wayfinding คือการหาเส้นทางนั้น ไม่ใช่การพุ่งเข้าใส่จุดหมาย skill นี้จะวาดเส้นทางเป็น แผนที่ร่วม (shared map) บน issue tracker ของ repo แล้วไล่ทำ ticket ของมันทีละใบจนกว่าเส้นทางจะชัด
จุดหมายของแต่ละ effort ไม่เหมือนกัน และการตั้งชื่อจุดหมายคือก้าวแรกของการวาดแผนที่ — มันกำหนดรูปร่างของทุก ticket จุดหมายอาจเป็น spec ที่จะส่งต่อไป iterate กันต่อ เป็นการตัดสินใจที่ต้องล็อกก่อนเริ่มวางแผน หรือเป็นการเปลี่ยนแปลงที่ลงมือทำในที่เลย เช่นการ migrate data structure ตัวแผนที่ไม่ผูกกับ domain ไหน — งาน engineering เนื้อหาคอร์ส หรืออะไรก็ตามที่เข้ารูปแบบนี้
วางแผน อย่าเพิ่งลงมือทำ
Wayfinder คือการวางแผนโดย default: แต่ละ ticket ปิดการตัดสินใจหนึ่งเรื่อง และแผนที่จะเสร็จเมื่อเส้นทางชัด — ไม่เหลืออะไรให้ตัดสินใจก่อนที่ใครสักคนจะไปลงมือทำของจริง แรงดึงที่อยากลงมือทำงานเลยมักเป็นสัญญาณว่าคุณมาถึงขอบแผนที่แล้ว และถึงเวลา hand off แต่ละ effort สามารถ override เรื่องนี้ได้ใน Notes ของมัน — ดึง execution เข้ามาอยู่ในแผนที่ด้วย — แต่ถ้าไม่ได้ระบุไว้ ให้ผลิตการตัดสินใจ ไม่ใช่ deliverable
เรียกด้วยชื่อ
ทุกแผนที่และทุก ticket เป็น issue จึงมี ชื่อ — คือ title ของมัน ในทุกอย่างที่มนุษย์อ่าน — คำบรรยายระหว่างทำงาน, Decisions-so-far ของแผนที่ — ให้เรียกมันด้วยชื่อนั้น อย่าเรียกด้วย id เปล่า ๆ ตัวเลข หรือ slug กำแพงข้อความแบบ #42, #43, #44 อ่านไม่รู้เรื่อง แต่ชื่ออ่านปราดเดียวก็เข้าใจ id กับ URL ไม่ได้หายไปไหน — ชื่อห่อลิงก์ของมันไว้ — แต่พวกมันอยู่ข้างในชื่อ ไม่ใช่มาแทนที่ชื่อ
แผนที่
แผนที่คือ issue เดียวบน issue tracker ของ repo นี้ ติด label wayfinder:map — เป็น artifact หลักของงานนี้ ticket ของมันคือ child issue ของแผนที่
แผนที่เป็น index ไม่ใช่ที่เก็บข้อมูล มัน list การตัดสินใจที่ทำไปแล้วและชี้ไปยัง ticket ที่เก็บรายละเอียด; การตัดสินใจหนึ่งเรื่องอยู่ในที่เดียวเท่านั้น — ticket ของมัน — แผนที่จึงไม่เล่าซ้ำ แค่สรุปใจความแล้วใส่ลิงก์
ส่วนที่ว่าแผนที่ child ticket การ block และ query หา frontier อยู่ตรงไหนจริง ๆ นั้นขึ้นกับ tracker แต่ละตัว issue tracker ควรถูกส่งมอบให้คุณมาแล้ว — ถ้ายัง ให้รัน /setup-matt-pocock-skills ดูวิธีที่ repo นี้ ใช้ได้จาก section "Wayfinding operations" ในเอกสารของ tracker ถ้าไม่มี tracker ให้มา ให้ใช้ tracker แบบ local markdown เป็น default
เนื้อหาของแผนที่
ทั้งแผนที่ในความละเอียดต่ำ โหลดครั้งเดียวต่อ session ticket ที่ยังเปิดอยู่จะไม่ถูก list ไว้ — พวกมันคือ child issue ที่เปิดอยู่ หาเจอได้ด้วย query
## Destination
<what reaching the end of this map looks like — the spec, decision, or change this effort is finding its way to. One or two lines; every session orients to it before choosing a ticket.>
## Notes
<domain; skills every session should consult; standing preferences for this effort>
## Decisions so far
<!-- the index — one line per closed ticket: enough to judge relevance, then zoom the link for the detail the ticket holds -->
- [<closed ticket title>](link) — <one-line gist of the answer>
## Not yet specified
<!-- see "Fog of war": in-scope fog you can't ticket yet; graduates as the frontier advances -->
## Out of scope
<!-- see "Out of scope": work ruled beyond the destination; closed, never graduates -->
Tickets
แต่ละ ticket เป็น child issue ของแผนที่; issue id ของ tracker คือ identity ของมัน เนื้อหาของ ticket คือคำถาม ขนาดพอดีกับ agent session ขนาด 100K token หนึ่ง session:
## Question
<the decision or investigation this ticket resolves>
แต่ละ ticket ติด label wayfinder:<type> — หนึ่งใน research, prototype, grilling, task (ดู ประเภทของ ticket)
session จะ claim ticket ด้วยการ assign ให้ dev ที่ขับเคลื่อนแผนที่ ก่อน เริ่มงานใด ๆ เพื่อให้ session อื่นที่รันพร้อมกัน skip มันไป assignee นั่นแหละ_คือ_ตัว claim: ticket ที่เปิดอยู่และไม่มี assignee คือยังไม่ถูก claim
การ block ใช้ dependency relationship แบบ native ของ tracker — สำคัญมาก เพราะมัน render frontier ให้_เห็นด้วยตา_ใน UI ของ tracker เอง มนุษย์จึงเห็นว่าอะไรหยิบทำได้โดยไม่ต้องเปิดแผนที่ เฉพาะ tracker ที่ไม่มี native blocking เท่านั้นที่ fallback ไปใช้ convention ในเนื้อหา issue ticket จะ unblocked เมื่อทุก ticket ที่ block มันถูกปิดหมดแล้ว; frontier คือ child ที่เปิดอยู่ ไม่ถูก block และยังไม่ถูก claim — ขอบเขตของสิ่งที่รู้แล้ว
คำตอบไม่ใช่ส่วนหนึ่งของเนื้อหา ticket — มันถูกบันทึกตอน resolve (ดู ไล่ทำตามแผนที่) asset ที่สร้างขึ้นระหว่าง resolve ticket ให้ลิงก์จาก issue ไม่ใช่แปะเนื้อหาลงไปตรง ๆ
ประเภทของ ticket
ทุก ticket เป็นได้อย่างใดอย่างหนึ่ง: HITL — human in the loop, ทำร่วมกับมนุษย์ที่พูดแทนตัวเองได้ — หรือ AFK ที่ agent ขับเคลื่อนคนเดียว ticket แบบ HITL จะ resolve ได้ก็ต่อเมื่อมีการแลกเปลี่ยนสด ๆ นั้นเท่านั้น; agent ห้ามสวมบทตอบแทนฝั่งมนุษย์เด็ดขาด (agent ที่ grill แล้วตอบคำถามตัวเองคือละเมิดข้อนี้แล้ว)
- Research (AFK): อ่านเอกสาร, third-party API หรือ resource ในเครื่องอย่าง knowledge base สร้างสรุปเป็น markdown ลิงก์ไว้เป็น asset ใช้เมื่อต้องการความรู้ที่อยู่นอก working directory ปัจจุบัน
- Prototype (HITL): ยกระดับความคมชัดของการถกเถียงด้วยการทำ artifact ที่ถูก หยาบ แต่จับต้องได้ ให้คนได้ลองตอบสนอง — outline, ร่างคร่าว ๆ, stub หรือโค้ด UI/logic ผ่าน /prototype skill ลิงก์ prototype ไว้เป็น asset ใช้เมื่อคำถามหลักคือ "ควรหน้าตาเป็นยังไง" หรือ "ควรทำงานยังไง"
- Grilling (HITL): คุยกันผ่าน skill /grilling และ /domain-modeling ทีละคำถาม เป็นเคส default
- Task (HITL หรือ AFK): งาน manual ที่ต้องเกิดขึ้นก่อนจะตัดสินใจอะไรได้ — ไม่มีอะไรให้ตัดสินใจ prototype หรือ research แต่การถกเถียงถูก block จนกว่างานนี้จะเสร็จ เช่น สมัครใช้ service เพื่อให้ประเมิน API ของมันได้, จัดเตรียม access, ย้ายข้อมูลเพื่อให้เห็นรูปร่างของมัน นี่คือประเภทเดียวที่ลงมือทำแทนที่จะตัดสินใจ — และมันมีที่ยืนเพราะไป unblock การตัดสินใจ ไม่ใช่เพราะ deliver จุดหมาย ถ้า agent ทำเองคนเดียวได้ก็ทำเลย (AFK); ไม่งั้นก็ส่ง checklist ที่แม่นยำให้มนุษย์ (HITL) ถือว่า resolve เมื่องานเสร็จ; คำตอบบันทึกว่าทำอะไรไปและ fact ที่ตามมา (ที่เก็บ credentials, URL ใหม่, จำนวน row) ซึ่ง ticket ใบต่อ ๆ ไปต้องพึ่ง
Fog of war
แผนที่_ตั้งใจ_ให้ไม่สมบูรณ์: อย่าวาดสิ่งที่ยังมองไม่เห็น พ้นจาก ticket ที่ active อยู่ออกไปคือ fog of war (หมอกสงคราม — พื้นที่ที่ยังมองไม่ชัด) — ภาพราง ๆ ของการตัดสินใจและการ investigate ที่พอบอกได้ว่ากำลังจะมา แต่ยังปักหมุดไม่ได้ เพราะมันแขวนอยู่กับคำถามที่ยังเปิดอยู่ การ resolve ticket หนึ่งใบจะเคลียร์หมอกที่อยู่ข้างหน้ามัน เลื่อนขั้นสิ่งที่ตอนนี้ระบุได้แล้วให้กลายเป็น ticket ใหม่ — ทีละใบ จนเส้นทางไปจุดหมายชัดและไม่เหลือ ticket
section Not yet specified ของแผนที่คือที่จดภาพราง ๆ นั้น: คำถามที่คาดว่าจะมี พื้นที่ที่ต้องกลับมาดูทีหลัง มันคือ frontier ที่ยังไม่ถูกค้นพบ ซึ่งมุ่ง_ไปหา_จุดหมาย — ทุกอย่างตรงนี้อยู่ใน scope แค่ยังไม่คมพอจะตั้งเป็น ticket จะเขียนหลวมหรือละเอียดแค่ไหนก็ได้ตามที่มองเห็น; มันทำหน้าที่เป็นป้ายบอกทางให้ collaborator ที่มาอ่านรู้ด้วยว่า effort นี้กำลังมุ่งไปทางไหน
หมอกหรือ ticket? เกณฑ์ตัดสินคือคุณตั้งคำถามได้อย่างแม่นยำตอนนี้หรือยัง — _ไม่ใช่_ว่าคุณตอบมันได้ตอนนี้หรือเปล่า
- เป็น ticket เมื่อ คำถามคมแล้ว — ต่อให้มันถูก block และยังลงมือทำไม่ได้ก็ตาม
- เป็น Not yet specified เมื่อ ยังเรียบเรียงให้คมขนาดนั้นไม่ได้ อย่าหั่นหมอกล่วงหน้าเป็นชิ้นขนาด ticket: มันหยาบกว่า ticket และหมอกก้อนหนึ่งอาจเลื่อนขั้นเป็นหลาย ticket หรือไม่เป็นเลยสักใบก็ได้ เมื่อ frontier ไปถึงมัน
Not yet specified ไม่รวมสิ่งที่ตัดสินใจไปแล้ว (Decisions so far) สิ่งที่เป็น ticket อยู่แล้ว และสิ่งที่อยู่นอก scope (section ถัดไป)
Out of scope
หมอกก่อตัว_มุ่งไปหา_จุดหมายเท่านั้น จุดหมายเป็นตัวกำหนด scope งานที่เลยจุดหมายออกไปจึงเป็น out of scope — มันไม่ใช่หมอก และไม่ควรอยู่ใน Not yet specified มันได้ section ของตัวเองบนแผนที่ชื่อ Out of scope: งานที่คุณตั้งใจตัดออกจาก effort นี้ สิ่งที่พามันมาลงตรงนี้คือ scope ไม่ใช่ความคมของคำถาม
งานที่ out of scope ไม่มีวันเลื่อนขั้น — frontier หยุดที่จุดหมาย — มันจะกลับมาก็ต่อเมื่อจุดหมายถูกวาดใหม่ และถึงตอนนั้นก็กลับมาเป็น effort ใหม่ ไม่ใช่ทำต่อจากของเดิม
การตัดอะไรออกนอก scope เป็นการกำหนดขอบเขต ไม่ใช่ก้าวหนึ่งบนเส้นทาง เมื่อ ticket ที่มีอยู่แล้วกลายเป็นว่าอยู่เลยจุดหมาย — หลุด scope เข้ามาตั้งแต่ตอนวาดแผนที่ หรือถูกเปิดเผยโดย resolution — ให้ปิดมัน (ticket ที่ปิดแล้วหลุดจาก frontier แบบไม่มีข้อกังขา) แล้วทิ้งไว้หนึ่งบรรทัดใน section Out of scope: ใจความสั้น ๆ บวกเหตุผลว่าทำไมถึง out of scope พร้อมลิงก์ไปยัง ticket ที่ปิด มันไม่เข้า Decisions so far ซึ่งบันทึกเฉพาะเส้นทางที่เดินจริง — เส้นแบ่ง scope ไม่ใช่ก้าวหนึ่งบนเส้นทางนั้น
การเรียกใช้
มีสองโหมด ไม่ว่าโหมดไหน ห้าม resolve เกินหนึ่ง ticket ต่อ session
วาดแผนที่
ผู้ใช้เรียกใช้พร้อมไอเดียหลวม ๆ
- ตั้งชื่อจุดหมาย รัน session
/grilling และ /domain-modeling เพื่อปักหมุดว่าแผนที่นี้กำลังหาทางไปที่ไหน — spec การตัดสินใจ หรือการเปลี่ยนแปลง จุดหมายเป็นตัวกำหนด scope จึงต้องเคลียร์ให้จบก่อน
- สำรวจ frontier grill อีกรอบ คราวนี้แบบ breadth-first: กระจายให้ทั่วทั้งพื้นที่แทนที่จะเจาะลึก thread ใดหนึ่ง เพื่อให้เห็นการตัดสินใจที่ยังเปิดอยู่และก้าวแรก ๆ ที่ทำได้เลยตอนนี้ ถ้ารอบนี้ไม่เจอหมอกเลย — เส้นทางไปจุดหมายชัดอยู่แล้ว ทั้งงานเล็กพอสำหรับ session เดียว — ก็ไม่จำเป็นต้องมีแผนที่ หยุดแล้วถามผู้ใช้ว่าอยากไปต่อยังไง
- สร้างแผนที่ (label
wayfinder:map): กรอก Destination กับ Notes, ปล่อย Decisions-so-far ว่างไว้, สเก็ตช์หมอกลงใน Not yet specified
- สร้าง ticket ที่ระบุได้ตอนนี้ เป็น child issue ของแผนที่ — แล้วค่อยโยงเส้น blocking ในรอบที่สอง (issue ต้องมี id ก่อนถึงจะอ้างถึงกันได้) การโยงเส้นจะแยกพวกมันออกเป็น frontier กับพวกที่ถูก block; อะไรที่ยังระบุไม่ได้ให้คงอยู่ในหมอก — section Not yet specified
- หยุด — การวาดแผนที่คืองานของหนึ่ง session; อย่าเลยไป resolve ticket ต่อ
ไล่ทำตามแผนที่
ผู้ใช้เรียกใช้พร้อมแผนที่ (URL หรือหมายเลข) จะระบุ ticket มาด้วยหรือไม่ก็ได้ — ถ้าไม่ระบุ คุณเป็นคนเลือกการตัดสินใจถัดไป ไม่ใช่ผู้ใช้
- โหลด แผนที่ — มุมมองความละเอียดต่ำ ไม่ต้องโหลดเนื้อหาของทุก ticket
- เลือก ticket ถ้าผู้ใช้ระบุมา ใช้ใบนั้น ไม่งั้นหยิบ ticket แรกใน frontier ตามลำดับ claim มัน: assign ให้ตัวเองก่อนเริ่มงานใด ๆ
- resolve มัน — zoom เท่าที่จำเป็น: ดึงเนื้อหาเต็มของ ticket ที่เกี่ยวข้องหรือปิดไปแล้วเมื่อต้องใช้; เรียกใช้ skill ที่ block
## Notes ระบุไว้ ถ้าไม่แน่ใจ ใช้ /grilling และ /domain-modeling
- บันทึกผลการ resolve: โพสต์คำตอบเป็น resolution comment, ปิด issue แล้ว เพิ่ม context pointer ต่อท้าย Decisions-so-far ของแผนที่
- เพิ่ม ticket ที่เพิ่งโผล่ขึ้นมาใหม่ (สร้างก่อนแล้วค่อยโยงเส้น); เลื่อนขั้นหมอกที่คำตอบทำให้ระบุได้แล้ว โดยลบหมอกก้อนที่เลื่อนขั้นออกจาก Not yet specified ให้มันเหลืออยู่แค่ในรูป ticket ใหม่เท่านั้น ถ้าคำตอบเผยว่า ticket ใบไหน — ใบนี้หรือใบอื่น — อยู่เลยจุดหมายไป ให้ตัดมันออกนอก scope แทนที่จะ resolve บนเส้นทาง ถ้าการตัดสินใจนี้ทำให้ส่วนอื่นของแผนที่ใช้ไม่ได้ ให้ update หรือลบ ticket เหล่านั้น
ผู้ใช้อาจรัน ticket ที่ unblocked หลายใบขนานกัน ดังนั้นให้เผื่อใจว่ามี session อื่นกำลังแก้ tracker อยู่พร้อมกัน