- หน้าแรก
- Documentation
- ส่วนขยาย
- ไปป์ไลน์การจับคู่ Rulebook
ไปป์ไลน์การจับคู่ Rulebook
เอกสารนี้อธิบายว่า coding-agent ค้นพบกฎจากรูปแบบคอนฟิกที่รองรับได้อย่างไร ทำให้กฎเหล่านั้นเป็นรูปแบบ Rule เดียวกัน แก้ไขข้อขัดแย้งด้านลำดับความสำคัญ และแบ่งผลลัพธ์ออกเป็น:
- กฎ Rulebook (ให้โมเดลใช้ได้ผ่าน system prompt + URL
rule://) - กฎ TTSR (กฎการหยุดสตรีมแบบ time-travel)
เอกสารนี้สะท้อนการใช้งานในปัจจุบัน รวมถึง semantics บางส่วนและ metadata ที่ถูกแยกวิเคราะห์แต่ไม่ได้บังคับใช้
ไฟล์การใช้งาน
หัวข้อที่มีชื่อว่า “ไฟล์การใช้งาน”../src/capability/rule.ts../src/capability/index.ts../src/discovery/index.ts../src/discovery/helpers.ts../src/discovery/builtin.ts../src/discovery/cursor.ts../src/discovery/windsurf.ts../src/discovery/cline.ts../src/sdk.ts../src/system-prompt.ts../src/internal-urls/rule-protocol.ts../src/utils/frontmatter.ts
1. รูปร่างกฎตามรูปแบบมาตรฐาน
หัวข้อที่มีชื่อว่า “1. รูปร่างกฎตามรูปแบบมาตรฐาน”ผู้ให้บริการทั้งหมดทำให้ไฟล์ต้นทางอยู่ในรูปแบบ Rule:
interface Rule { name: string; path: string; content: string; globs?: string[]; alwaysApply?: boolean; description?: string; ttsrTrigger?: string; _source: SourceMeta;}เอกลักษณ์ของความสามารถคือ rule.name (ruleCapability.key = rule => rule.name)
ผลลัพธ์: ลำดับความสำคัญและการขจัดข้อมูลซ้ำซ้อนเป็นแบบอิงตามชื่อเท่านั้น ไฟล์ที่ต่างกันสองไฟล์ที่มี name เหมือนกันจะถือว่าเป็นกฎเชิงตรรกะเดียวกัน
2. แหล่งที่มาของการค้นพบและการทำให้เป็นรูปแบบมาตรฐาน
หัวข้อที่มีชื่อว่า “2. แหล่งที่มาของการค้นพบและการทำให้เป็นรูปแบบมาตรฐาน”src/discovery/index.ts ลงทะเบียนผู้ให้บริการโดยอัตโนมัติ สำหรับ rules ผู้ให้บริการในปัจจุบันได้แก่:
native(ลำดับความสำคัญ100)cursor(ลำดับความสำคัญ50)windsurf(ลำดับความสำคัญ50)cline(ลำดับความสำคัญ40)
ผู้ให้บริการ Native (builtin.ts)
หัวข้อที่มีชื่อว่า “ผู้ให้บริการ Native (builtin.ts)”โหลดกฎ .xcsh จาก:
- โปรเจกต์:
<cwd>/.xcsh/rules/*.{md,mdc} - ผู้ใช้:
~/.xcsh/agent/rules/*.{md,mdc}
การทำให้เป็นรูปแบบมาตรฐาน:
name= ชื่อไฟล์โดยไม่มีนามสกุล.md/.mdc- frontmatter ถูกแยกวิเคราะห์ผ่าน
parseFrontmatter content= เนื้อหา (frontmatter ถูกตัดออก)globs,alwaysApply,description,ttsr_triggerถูก map โดยตรง
ข้อควรระวังสำคัญ: globs ถูก cast เป็น string[] | undefined โดยไม่มีการกรองสมาชิกในผู้ให้บริการนี้
ผู้ให้บริการ Cursor (cursor.ts)
หัวข้อที่มีชื่อว่า “ผู้ให้บริการ Cursor (cursor.ts)”โหลดจาก:
- ผู้ใช้:
~/.cursor/rules/*.{mdc,md} - โปรเจกต์:
<cwd>/.cursor/rules/*.{mdc,md}
การทำให้เป็นรูปแบบมาตรฐาน (transformMDCRule):
description: เก็บไว้เฉพาะเมื่อเป็น string เท่านั้นalwaysApply: เก็บเฉพาะค่าtrueเท่านั้น (falseจะกลายเป็นundefined)globs: รับ array (เฉพาะสมาชิกที่เป็น string) หรือ string เดี่ยวttsr_trigger: เฉพาะ string เท่านั้นnameจากชื่อไฟล์โดยไม่มีนามสกุล
ผู้ให้บริการ Windsurf (windsurf.ts)
หัวข้อที่มีชื่อว่า “ผู้ให้บริการ Windsurf (windsurf.ts)”โหลดจาก:
- ผู้ใช้:
~/.codeium/windsurf/memories/global_rules.md(ชื่อกฎคงที่global_rules) - โปรเจกต์:
<cwd>/.windsurf/rules/*.md
การทำให้เป็นรูปแบบมาตรฐาน:
globs: array ของ string หรือ string เดี่ยวalwaysApply,descriptionถูก cast จาก frontmatterttsr_trigger: เฉพาะ string เท่านั้นnameจากชื่อไฟล์สำหรับกฎในโปรเจกต์
ผู้ให้บริการ Cline (cline.ts)
หัวข้อที่มีชื่อว่า “ผู้ให้บริการ Cline (cline.ts)”ค้นหาขึ้นไปจาก cwd เพื่อหา .clinerules ที่ใกล้ที่สุด:
- หากเป็นไดเรกทอรี: โหลด
*.mdที่อยู่ข้างใน - หากเป็นไฟล์: โหลดไฟล์เดียวเป็นกฎที่ชื่อว่า
clinerules
การทำให้เป็นรูปแบบมาตรฐาน:
globs: array ของ string หรือ string เดี่ยวalwaysApply: เฉพาะเมื่อเป็น boolean เท่านั้นdescription: เฉพาะ string เท่านั้นttsr_trigger: เฉพาะ string เท่านั้น
3. พฤติกรรมการแยกวิเคราะห์ Frontmatter และความคลุมเครือ
หัวข้อที่มีชื่อว่า “3. พฤติกรรมการแยกวิเคราะห์ Frontmatter และความคลุมเครือ”ผู้ให้บริการทั้งหมดใช้ parseFrontmatter (utils/frontmatter.ts) ด้วย semantics เหล่านี้:
- Frontmatter จะถูกแยกวิเคราะห์เฉพาะเมื่อเนื้อหาเริ่มต้นด้วย
---และมีการปิด\n--- - เนื้อหาจะถูกตัดช่องว่างหลังจากแยก frontmatter ออก
- หาก YAML แยกวิเคราะห์ล้มเหลว:
- จะบันทึกคำเตือน
- parser จะ fallback ไปใช้การแยกวิเคราะห์แบบ
key: valueบรรทัดต่อบรรทัด (^(\w+):\s*(.*)$)
ผลที่ตามมาของความคลุมเครือ:
- Fallback parser ไม่รองรับ array, nested object, กฎการ quoting หรือ key ที่มีขีดกลาง
- ค่า fallback จะกลายเป็น string (ตัวอย่างเช่น
alwaysApply: trueจะกลายเป็น string"true") ดังนั้นผู้ให้บริการที่ต้องการประเภท boolean/string อาจสูญเสีย metadata ttsr_triggerใช้งานได้ใน fallback (key ที่ใช้ underscore); key เช่นthinking-levelจะไม่ทำงาน- ไฟล์ที่ไม่มี frontmatter ที่ถูกต้องจะยังคงโหลดเป็นกฎโดยมี metadata ว่างเปล่าและเนื้อหาครบถ้วน
4. ลำดับความสำคัญของผู้ให้บริการและการขจัดข้อมูลซ้ำซ้อน
หัวข้อที่มีชื่อว่า “4. ลำดับความสำคัญของผู้ให้บริการและการขจัดข้อมูลซ้ำซ้อน”loadCapability("rules") (capability/index.ts) รวมผลลัพธ์จากผู้ให้บริการ จากนั้นขจัดข้อมูลซ้ำซ้อนด้วย rule.name
โมเดลลำดับความสำคัญ
หัวข้อที่มีชื่อว่า “โมเดลลำดับความสำคัญ”- ผู้ให้บริการถูกเรียงลำดับตาม priority จากมากไปน้อย
- ลำดับความสำคัญเท่ากันจะรักษาลำดับการลงทะเบียน (
cursorก่อนwindsurfจากdiscovery/index.ts) - การขจัดข้อมูลซ้ำซ้อนแบบ first-wins: ชื่อกฎที่พบก่อนจะถูกเก็บไว้; รายการที่มีชื่อเดียวกันในภายหลังจะถูกทำเครื่องหมาย
_shadowedในallและถูกแยกออกจากitems
ลำดับผู้ให้บริการกฎที่มีผลในปัจจุบันคือ:
native(100)cursor(50)windsurf(50)cline(40)
ข้อควรระวังเกี่ยวกับการเรียงลำดับภายในผู้ให้บริการ
หัวข้อที่มีชื่อว่า “ข้อควรระวังเกี่ยวกับการเรียงลำดับภายในผู้ให้บริการ”ภายในผู้ให้บริการ ลำดับรายการมาจากผลลัพธ์การ glob ของ loadFilesFromDir บวกกับลำดับการ push ที่ชัดเจน ซึ่งเพียงพอสำหรับการใช้งานปกติแต่ไม่ได้ระบุการเรียงลำดับไว้ชัดเจนในโค้ด
ความแตกต่างของลำดับแหล่งที่มาที่สังเกตได้:
nativeเพิ่มไดเรกทอรีคอนฟิกของโปรเจกต์ก่อน จากนั้นจึงเพิ่มของผู้ใช้cursorเพิ่มผลลัพธ์ของผู้ใช้ก่อน จากนั้นจึงเพิ่มของโปรเจกต์windsurfเพิ่มglobal_rulesของผู้ใช้ก่อน จากนั้นจึงเพิ่มกฎของโปรเจกต์clineโหลดเฉพาะแหล่ง.clinerulesที่ใกล้ที่สุดเท่านั้น
5. การแบ่งออกเป็น bucket Rulebook, Always-Apply และ TTSR
หัวข้อที่มีชื่อว่า “5. การแบ่งออกเป็น bucket Rulebook, Always-Apply และ TTSR”หลังจากค้นพบกฎใน createAgentSession (sdk.ts):
- กฎที่ค้นพบทั้งหมดจะถูกสแกน
- กฎที่มี
condition(frontmatter key;ttsr_trigger/ttsrTriggerถูกรับเป็นค่า fallback) จะถูกลงทะเบียนเข้าสู่TtsrManager - รายการ
rulebookRulesแยกต่างหากจะถูกสร้างขึ้นด้วย predicate นี้:
!registeredTtsrRuleNames.has(rule.name) && !rule.alwaysApply && !!rule.description- รายการ
alwaysApplyRulesจะถูกสร้างขึ้น:
!registeredTtsrRuleNames.has(rule.name) && rule.alwaysApply === trueพฤติกรรมของ Bucket
หัวข้อที่มีชื่อว่า “พฤติกรรมของ Bucket”- TTSR bucket: กฎใดก็ตามที่มี
condition(ไม่จำเป็นต้องมี description) มีลำดับความสำคัญเหนือ bucket อื่น - Always-apply bucket:
alwaysApply === true, ไม่ใช่ TTSR เนื้อหาทั้งหมดถูก inject เข้าสู่ system prompt สามารถ resolve ผ่านrule://ได้ - Rulebook bucket: ต้องมี description, ต้องไม่ใช่ TTSR, ต้องไม่มี
alwaysApplyถูกระบุไว้ใน system prompt ด้วยชื่อ+description; เนื้อหาถูกอ่านตามต้องการผ่านrule:// - กฎที่มีทั้ง
conditionและalwaysApplyจะไปอยู่ใน TTSR เท่านั้น (TTSR มีลำดับความสำคัญสูงกว่า) - กฎที่มีทั้ง
alwaysApplyและdescriptionจะไปอยู่ใน always-apply เท่านั้น (ไม่ใช่ rulebook)
6. วิธีที่ metadata ส่งผลต่อพื้นผิว runtime
หัวข้อที่มีชื่อว่า “6. วิธีที่ metadata ส่งผลต่อพื้นผิว runtime”description
หัวข้อที่มีชื่อว่า “description”- จำเป็นสำหรับการรวมไว้ใน rulebook
- แสดงผลใน block
<rules>ของ system prompt - หาก description หายไป กฎจะไม่สามารถใช้งานผ่าน
rule://และไม่ถูกระบุไว้ใน system prompt rules
- ถูกส่งต่อไปบน
Rule - แสดงผลเป็นรายการ
<glob>...</glob>ใน block rules ของ system prompt - แสดงในสถานะ UI ของกฎ (รายการโหมด
extensions) - ไม่ได้บังคับใช้สำหรับการจับคู่อัตโนมัติในไปป์ไลน์นี้ ไม่มี runtime glob matcher ที่เลือกกฎตาม file/tool target ในปัจจุบัน
alwaysApply
หัวข้อที่มีชื่อว่า “alwaysApply”- ถูกแยกวิเคราะห์และเก็บรักษาโดยผู้ให้บริการ
- ใช้ในการแสดงผล UI (ป้ายกำกับ trigger
"always"ใน extensions state manager) - ใช้เป็นเงื่อนไขการแยกออกจาก
rulebookRules - เนื้อหากฎทั้งหมดจะถูก inject เข้าสู่ system prompt โดยอัตโนมัติ (ก่อนส่วน rulebook rules)
- กฎยังสามารถระบุที่อยู่ได้ผ่าน
rule://<name>เพื่ออ่านซ้ำ
ttsr_trigger
หัวข้อที่มีชื่อว่า “ttsr_trigger”- ถูก map ไปยัง
rule.ttsrTrigger - หากมีอยู่ กฎจะถูกส่งต่อไปยัง TTSR manager ไม่ใช่ rulebook
7. เส้นทางการรวมอยู่ใน System Prompt
หัวข้อที่มีชื่อว่า “7. เส้นทางการรวมอยู่ใน System Prompt”buildSystemPromptInternal รับทั้ง rules (rulebook) และ alwaysApplyRules
กฎ Always-apply จะถูกแสดงผลก่อน โดย inject เนื้อหาดิบของกฎเข้าสู่ prompt โดยตรง
กฎ Rulebook จะถูกแสดงผลในส่วน # Rules พร้อมด้วย:
Read rule://<name> when working in matching domainname,descriptionและรายการ<glob>ที่ไม่บังคับของแต่ละกฎ
นี่เป็นแนวทางแบบ advisory/contextual: ข้อความ prompt ขอให้โมเดลอ่านกฎที่ใช้งานได้ แต่โค้ดไม่ได้บังคับการใช้งานได้ของ glob
8. พฤติกรรม URL ภายใน rule://
หัวข้อที่มีชื่อว่า “8. พฤติกรรม URL ภายใน rule://”RuleProtocolHandler ถูกลงทะเบียนด้วย:
new RuleProtocolHandler({ getRules: () => [...rulebookRules, ...alwaysApplyRules] })ผลที่ตามมา:
rule://<name>resolve กับทั้ง rulebookRules และ alwaysApplyRules- กฎที่อยู่ใน TTSR เท่านั้น และกฎที่ไม่มี description และไม่มี
alwaysApplyไม่สามารถระบุที่อยู่ผ่านrule://ได้ - การ resolution เป็นการจับคู่ชื่อแบบตรงทั้งหมด
- ชื่อที่ไม่รู้จักจะ return error พร้อมระบุชื่อกฎที่มีอยู่
- เนื้อหาที่ return คือ
rule.contentดิบ (frontmatter ถูกตัดออก) ประเภทเนื้อหาtext/markdown
9. Semantics บางส่วน / ที่ไม่ได้บังคับใช้ที่ทราบ
หัวข้อที่มีชื่อว่า “9. Semantics บางส่วน / ที่ไม่ได้บังคับใช้ที่ทราบ”- คำอธิบายของผู้ให้บริการกล่าวถึงไฟล์ legacy (
.cursorrules,.windsurfrules) แต่เส้นทางโค้ด loader ในปัจจุบันไม่ได้อ่านไฟล์เหล่านั้นจริง - metadata
globsถูกนำเสนอไปยัง prompt/UI แต่ไม่ได้บังคับใช้โดย logic การเลือกกฎ - การเลือกกฎสำหรับ
rule://รวม rulebook และ always-apply rules แต่ไม่รวมกฎที่อยู่ใน TTSR เท่านั้น - คำเตือนการค้นพบ (
loadCapability("rules").warnings) ถูกสร้างขึ้นแต่createAgentSessionในปัจจุบันไม่ได้ surface/บันทึกคำเตือนเหล่านั้นในเส้นทางนี้