กฎคุม — นโยบายเดียวสำหรับทุกการกระทำที่เปลี่ยนแปลงสถานะ
เอเจนต์ใน Control Center ลบไฟล์ พุชแบรนช์ เผยแพร่ pull request และเรียก API ภายนอกได้ แต่ละอย่างเป็นความเสี่ยงต่าง แบบ กัน และเป็นเวลานานที่มีเพียงอย่างเดียว — คำสั่งเชลล์ — ที่มีนโยบาย กฎคุมมีอยู่เพื่อตอบคำถามข้อเดียวอย่างสม่ำเสมอ สำหรับทุกการกระทำที่เปลี่ยนแปลงสถานะซึ่งเอเจนต์ทำได้ ไม่ว่าตัวรันหรือเครื่องมือใด จะเป็นผู้เสนอ: สิ่งนี้ได้รับอนุญาต ต้องมีการอนุมัติ หรือถูกปฏิเสธ?
เอนจินเดียว ทุกจุดที่ต้องผ่าน
หัวข้อที่มีชื่อว่า “เอนจินเดียว ทุกจุดที่ต้องผ่าน”มีเอนจินนโยบายเพียงหนึ่งเดียวเท่านั้น มันถูกเรียกใช้ ณ ทุกจุดที่การกระทำอาจออกจาก ระบบ: ทะเบียนเครื่องมือของฮาร์เนสในตัว ประตูตัวจัดส่ง MCP ฝั่งเซิร์ฟเวอร์ และการ เปลี่ยนแปลงจาก repo-op กฎที่เขียนครั้งเดียวจึงใช้กับทั้งรันไทม์ในตัวและเอเจนต์ CLI ภายนอกเหมือนกัน — ไม่มีเส้นทางที่สองที่เงียบกว่าอ้อมมันไป นโยบายคำสั่งแบบใช้แต่ bash แบบเดิมยังทำงานอยู่: กฎหนึ่งข้อจับคู่กับคำนำหน้าคำสั่งแทนที่จะเป็นประเภทการ กระทำ และทั้งสองรูปแบบอยู่ร่วมกันในที่เก็บเดียวกัน
อย่างไรก็ตาม เอนจินนี้ไม่ใช่สิ่งทดแทนแซนด์บ็อกซ์ของ OS และแซนด์บ็อกซ์ก็ไม่ใช่
สิ่งทดแทนของมัน ทั้งสองตอบคำถามต่างกัน: กฎคุมตัดสินว่าการเรียกที่ Control Center
มองเห็นได้รับอนุญาตให้เกิดขึ้นเลยหรือไม่ ส่วนแซนด์บ็อกซ์จำกัดว่ากระบวนการที่เกิดขึ้น
จะเอื้อมไปถึงที่ใดได้บ้าง cc_server ใช้แซนด์บ็อกซ์ในโฮสต์ที่มีแบ็กเอนด์ — แต่
Windows ไม่มีเลย และ Linux ต้องมี bwrap และ socat บนโฮสต์
เหล่านั้น กฎคุมคือชั้นบังคับใช้ชั้นนอกสุด ไม่ใช่นโยบายที่วางทับบนพื้น จึงควรรู้ไว้
เมื่อคุณตัดสินใจว่าจะผ่อนปรนแค่ไหน
ActionClass: อนุกรมวิธานที่ปิดโดยเจตนา
หัวข้อที่มีชื่อว่า “ActionClass: อนุกรมวิธานที่ปิดโดยเจตนา”เครื่องมือที่เปลี่ยนแปลงสถานะทุกตัวประกาศว่าตนเป็นสมาชิกของ ActionClass ใด จากชุดปิดของคลาสผลกระทบสิบสามคลาส ห้าคลาสถามก่อนโดยค่าเริ่มต้น ที่เหลืออนุญาต และกฎคือสิ่งที่เปลี่ยนมัน
| คลาส | ค่าเริ่มต้นในตัว | ครอบคลุมอะไร |
|---|---|---|
fileDelete |
ถามก่อน | การลบไฟล์ (การเขียนแบบลบ, rm) |
gitPush |
ถามก่อน | การพุชไปยังรีโมตของ git |
prCreate |
ถามก่อน | การสร้าง pull request |
prPublish |
ถามก่อน | การเผยแพร่รีวิว, การรวม PR |
vendorSyncWrite |
ถามก่อน | การเขียนไปยังระบบตั๋วภายนอก (Linear, Jira, GitHub sync) |
fileWriteOutsideWorktree |
อนุญาต | การเขียนไฟล์นอก worktree ที่แยกออกมา |
gitCommit |
อนุญาต | การสร้างคอมมิตของ git |
networkEgress |
อนุญาต | การออกเครือข่าย (ดึงเว็บ, HTTP ตามอำเภอใจ) |
secretAccess |
อนุญาต | การอ่านความลับหรือข้อมูลรับรอง |
packageInstall |
อนุญาต | การติดตั้งแพ็กเกจ (npm, pip, pub, brew) |
processSpawn |
อนุญาต | การสปอว์นโพรเซส (เชลล์และทุกอย่างที่เรียกผ่านเชลล์) |
workspaceMutation |
อนุญาต | การเปลี่ยนโครงสร้างเวิร์กสเปซ (รีโป, สเปซ, เอเจนต์) |
enclosureControl |
อนุญาต | การควบคุมเอนโคลเจอร์ (ริก): บูต VM, ส่งอินพุตให้มัน |
แปดคลาสที่อนุญาตโดยค่าเริ่มต้นถูกเลือกบนสมมติฐานว่ามีพื้นแซนด์บ็อกซ์อยู่ใต้มัน
มันเป็นเช่นนั้นในโฮสต์ที่มีแบ็กเอนด์ และไม่เป็นเช่นนั้นบน Windows หรือบนเครื่อง Linux
ที่ขาด bwrap และ socat — ดังนั้นถ้าคุณต้องการให้ fileWriteOutsideWorktree
หรือ packageInstall ถูกกั้นที่นั่น นั่นคือกฎที่คุณต้องเขียนเอง
ชุดนี้ปิดโดยเจตนา เครื่องมือที่เปลี่ยนแปลงสถานะตัวใหม่ที่ประกาศคลาสไม่ได้จะ สอบไม่ผ่าน ratchet test อนุกรมวิธานจึงเติบโตได้ด้วยการตัดสินใจที่ชัดเจนและมี เหตุผลเท่านั้น — “การบานปลายของอนุกรมวิธานคือความตายของฟีเจอร์นี้” สิบสามคลาส เพียงพอที่จะแสดงนโยบายที่คนเขียนจริง (ไม่พุชโดยไม่ถาม, ไม่ลบนอก worktree, อนุญาตการอ่านเสมอ) และน้อยพอที่ UI การตั้งค่าจะยังเข้าใจได้
กฎและการตัดสินขอบเขต
หัวข้อที่มีชื่อว่า “กฎและการตัดสินขอบเขต”กฎหนึ่งข้อแมป (scope, ActionClass | command prefix) → allow | prompt | deny
ขอบเขตซ้อนกันจากจำเพาะที่สุดไปหาไม่จำเพาะที่สุด:
สเปซ > เอเจนต์ > เวิร์กสเปซ > พรีเซ็ตโหมด > ค่าเริ่มต้นในตัว
การตัดสินให้ ความจำเพาะก่อน: ขอบเขตแรกที่มีกฎตรงกันเป็นตัวตัดสิน และการ ตัดสินหยุดที่ตรงนั้น การเข้มงวดที่สุดใช้เป็นตัวตัดสินเฉพาะเมื่อเสมอกันเท่านั้น — ระหว่างกฎสองข้อที่จำเพาะเท่ากันในขอบเขตเดียวกัน และเมื่อรวมหลายคลาสที่การกระทำ เดียวประกาศไว้ ภายในขอบเขตหนึ่ง กฎคำสั่งจับคู่กับคำนำหน้าคำสั่งที่ยาวที่สุด อนุญาตไม่ชนะปฏิเสธที่ใดเลย
การตัดสินสองอย่างมีหลักประกันที่แน่นอน:
- คำถามที่ปิดเมื่อล้มเหลว
promptที่ไม่มีผู้อนุมัติเชื่อมต่ออยู่จะกลายเป็น ปฏิเสธ คำถามที่ไม่มีคำตอบไม่เคยเป็นคำตอบว่าใช่ - การรวมแบบเข้มงวดที่สุด การกระทำที่คร่อมหลายคลาสจะถูกรวมแบบเข้มงวดที่สุด เมื่อหลายคลาสถามก่อน การยืนยันครั้งเดียวจะแสดงรายการทั้งหมด
จงใจไม่มีตัวล็อกต่อเทิร์น ทุกการเรียกเครื่องมือตัดสินนโยบายใหม่ตั้งแต่ต้น การถามซ้ำสำหรับการกระทำเดิมจึงถูกจำกัดด้วย “จดจำการตัดสินนี้” ของผู้ปฏิบัติการเอง ไม่ใช่ด้วยสิ่งที่ผูกกับเทิร์น
กฎระดับอาร์กิวเมนต์
หัวข้อที่มีชื่อว่า “กฎระดับอาร์กิวเมนต์”กฎหนึ่งข้อจำกัด อาร์กิวเมนต์ ของการกระทำได้ ไม่ใช่แค่กริยาของมัน “พุชได้” กับ
“พุชไปยัง feature/* ได้” เป็นข้ออ้างที่ต่างกัน และมีเพียงข้อที่สองเท่านั้นที่
เป็นการควบคุม — ประตูความสามารถที่อนุญาตเฉพาะกริยาเป็นรูปทรงที่อยู่เบื้องหลัง
เหตุการณ์เอเจนต์ที่ถูกเปิดเผยส่วนใหญ่
ข้อจำกัดหนึ่งข้ออาจระบุ:
- พาธ — รูปแบบ glob (
repos/**,!**/.env) - ref — git ref พร้อมการปฏิเสธด้วย
!(['**', '!main']อ่านว่า “ทุกแบรนช์ ยกเว้น main”) - โฮสต์ — ปลายทางเครือข่าย พร้อมไวลด์การ์ดซับโดเมน (
*.internal) - คำสั่ง — คำนำหน้าคำสั่ง จับคู่ที่ขอบเขตคำ
- เพดาน —
maxCount/maxCentsทำให้ “ลบได้ถึง 50 ไฟล์” แสดงออกได้
คุณสมบัติสามอย่างเกิดจากการที่ไวยากรณ์ปิดและไม่มีลูป และทั้งสามคือประเด็น: ทุกกฎแสดงออกเป็นประโยคที่คุณอ่านกลับได้ ทุกการปฏิเสธระบุข้อจำกัดที่ตรงได้ และ นโยบายทั้งหมดแจกแจงได้ — คุณเห็นได้ว่าเอเจนต์ทำอะไรได้ ก่อน มันรัน
กฎสามข้อที่สำคัญ:
- กฎที่มีข้อจำกัดจำเพาะกว่า กฎที่ไม่มีข้อจำกัดในขอบเขตเดียวกัน “ปฏิเสธการ
พุชไป
main” จึงชนะ “อนุญาตการพุช” โดยไม่มีใครต้องคิดเรื่องลำดับ - กฎแบบ จำกัด (ปฏิเสธ / ถามก่อน) มีผลเมื่อคำขอแตะค่าใด ๆ ที่มันระบุ กฎแบบ ผ่อนปรน (อนุญาต) มีผลเฉพาะเมื่อคำขออยู่ ทั้งหมด ภายในมัน การอ่านทั้งสอง แบบเดียวกันจะเปิดทางให้เอเจนต์ฟอกพาธต้องห้ามโดยพาเส้นทางที่ไม่ผิดอะไรไปด้วย ข้าง ๆ
- กฎที่ระบุมิติที่คำขอไม่ได้กล่าวถึง จะไม่ถูกปรับใช้และไม่ถูกข้าม: มัน ยกระดับเป็นการขออนุมัติ การข้ามไปเงียบ ๆ จะทำให้กฎป้องกันแบรนช์ทุกข้อ ไร้ผลกับเครื่องมือที่ไม่รายงาน ref ของมัน การปฏิเสธเงียบ ๆ จะปฏิเสธทุกการพุช ที่ตัวสกัดอธิบายไม่ได้ เมื่อไม่มีผู้อนุมัติเชื่อมต่ออยู่ กฎปิดเมื่อล้มเหลวที่ มีอยู่จะเปลี่ยนการยกระดับนั้นเป็นการปฏิเสธ
กฎคำสั่งจับอะไรได้และจับอะไรไม่ได้
หัวข้อที่มีชื่อว่า “กฎคำสั่งจับอะไรได้และจับอะไรไม่ได้”กฎ commandPrefix จับคู่ที่ขอบเขตคำ: git push ครอบ git push origin main
และไม่ครอบ git pushx มัน ไม่ ปรับรูปเชลล์ git push (เว้นวรรคสองครั้ง),
cd sub && git push และ GIT_DIR=… git push เป็นสตริงที่ต่างกันทั้งหมด และ
ไม่มีอันใดตรงกับกฎเกี่ยวกับ git push
นั่นคือข้อจำกัดจริง และมันถูกระบุไว้แทนที่จะกลบเกลื่อน: กฎคำสั่งเป็นความสะดวก
ของผู้ปฏิบัติการในการจัดรูปพฤติกรรมปกติของเอเจนต์ ไม่ใช่ ขอบเขตต่อเอเจนต์ที่
เป็นปรปักษ์ ขอบเขตคือคลาสผลกระทบ (ซึ่งเครื่องมือประกาศและสะกดใหม่ไม่ได้) ตาข่าย
คำสั่งของโหมดที่อยู่ใต้ที่เก็บนโยบาย และแซนด์บ็อกซ์ของ OS ที่อยู่ใต้ทั้งสอง
กฎคำสั่งที่ตัดสินเป็น allow ไม่เคยทำให้สองอย่างนั้นหลวมขึ้น — ตาข่ายโหมดรัน
หลังจากนั้น และ deny ของมันเป็นที่สุด
การอนุมัติแบบต่อเนื่อง
หัวข้อที่มีชื่อว่า “การอนุมัติแบบต่อเนื่อง”การตอบคำถามด้วย “จดจำการตัดสินนี้” เขียนกฎนโยบายจริง: มีขอบเขต (สเปซ / เอเจนต์ /
เวิร์กสเปซ), มีข้อจำกัดที่อาร์กิวเมนต์ (การอนุมัติพุชไปยัง feature/login
ให้สิทธิ์ feature/** ไม่ใช่ main) และ เพิกถอนตัวเอง ตาม TTL ที่ระบุชัด
การตอบว่าใช่สำหรับสองสามชั่วโมงข้างหน้าไม่เหมือนกับการเขียนนโยบายถาวรของคุณใหม่
เงียบ ๆ และกฎที่มันเขียนจะลงในที่เก็บเดียวกันโดยมีแหล่งที่มาเป็น remembered
และวันหมดอายุ จึงเพิกถอนก่อนกำหนดได้
ระดับการบังคับใช้
หัวข้อที่มีชื่อว่า “ระดับการบังคับใช้”แต่ละกฎมีระดับหนึ่ง:
- advisory — อนุญาต แต่บันทึกว่ากฎตรง นี่คือเส้นทางการนำไปใช้: เปิดกฎเข้มใน โหมด advisory อ่านเส้นทางการตรวจสอบหนึ่งสัปดาห์เพื่อดูว่ามัน จะ บล็อกอะไร บ้าง แล้วเลื่อนขั้นมัน หากไม่มีระดับนี้ นโยบายเข้มจะไม่ถูกเปิดใช้เลย
- soft — ปฏิเสธ แต่ผู้ที่ถือสิทธิ์เขียนทับเขียนทับได้ พร้อมเหตุผลที่บันทึกไว้ การเขียนทับนั้นเองก็เป็นเหตุการณ์ที่ถูกตรวจสอบ
- hard (ค่าเริ่มต้น) — ปฏิเสธ ไม่มีสิ่งใดเขียนทับได้
ชั้นที่จัดการจากส่วนกลาง
หัวข้อที่มีชื่อว่า “ชั้นที่จัดการจากส่วนกลาง”ผู้ปฏิบัติการติดตั้งสามารถปักหมุดนโยบายที่ผู้ดูแลเวิร์กสเปซคนใดก็ทำให้หลวมขึ้น
ไม่ได้ กฎที่จัดการจากส่วนกลางอยู่ฝั่งเซิร์ฟเวอร์และถูกรวมแบบ เข้มงวดที่สุด
กับเชนของแต่ละเวิร์กสเปซ — ไม่ใช่ขอบเขตที่อยู่หัวเชน เพราะ allow ที่จัดการจาก
ส่วนกลางซึ่งอยู่หัวเชนจะเปิดให้การติดตั้งเขียนทับการปฏิเสธของเวิร์กสเปซ ซึ่ง
ตรงข้ามกับจุดประสงค์ของการบีบ กฎที่จัดการจากส่วนกลางจึงทำได้เพียงเข้มขึ้นเสมอ
การตั้ง CC_SERVER_MANAGED_POLICY ให้ชี้ไปที่ไฟล์ JSON มีอำนาจเหนือกฎที่จัดเก็บ
ไว้ทั้งหมด นี่คือสิ่งที่ทำให้ผู้ปฏิบัติการปักหมุดท่าทีที่ UI ผู้ดูแลใด ๆ พลิกไม่ได้
— คำตอบของคำถาม “ฉันหยุดนักพัฒนาของฉันจากการปิดการควบคุมความปลอดภัยได้ไหม?”
ปุ่มปรับความเป็นอิสระเป็นโปรไฟล์ ไม่ใช่ระบบคู่ขนาน
หัวข้อที่มีชื่อว่า “ปุ่มปรับความเป็นอิสระเป็นโปรไฟล์ ไม่ใช่ระบบคู่ขนาน”ปุ่มปรับความเป็นอิสระต่อสเปซเป็นโปรไฟล์ที่มีชื่อบนที่เก็บนโยบายเดียวกันนี้
ไม่ใช่กลไกที่สอง การตั้งค่าสามอย่างของมันถูกจัดเก็บและส่งเป็น proposeOnly,
actWithApproval และ actFreely (รูปแบบที่มีขีดกลางเป็นถ้อยคำของ UI เท่านั้น
และ autonomy.setForSpace ปฏิเสธอย่างอื่น) การปล่อยให้ไม่ได้ตั้งมีพฤติกรรม
เหมือน actWithApproval
แต่ละอย่างทำอะไรกับการตัดสินที่ได้:
proposeOnlyปฏิเสธเครื่องมือที่มีประตูกั้นทุกตัว เอเจนต์ยังคิดและตอบได้ แต่ลงมือไม่ได้ และข้อความของมันบอกเหตุผลactWithApproval(และเมื่อไม่ได้ตั้ง) คือประตูอนุมัติแบบปิดเมื่อล้มเหลวที่ อธิบายข้างต้นactFreelyอนุมัติล่วงหน้าทุกอย่างที่ไม่ได้ตัดสินเป็นdenyแบบ hard
ข้อสุดท้ายควรถูกระบุตรง ๆ มากกว่าทำให้เบาลง: ภายใต้ actFreely การตัดสินที่เป็น
prompt ไม่ ถูกยกระดับไปยังผู้อนุมัติ — มันถูกอนุญาตและไม่มีใครถูกถาม
มีเพียงกฎ deny ที่ชัดเจนเท่านั้นที่รอดจากปุ่มปรับ ดังนั้น actFreely เป็นการ
มอบความเป็นอิสระโดยเจตนา ไม่ใช่การตั้งค่าตามความสะดวก และกฎปิดเมื่อล้มเหลว
ปกป้องกรณีที่มันสำคัญพอดี (actWithApproval ซึ่งเป็นค่าเริ่มต้น)
การมอบหมายระหว่างเอเจนต์ถูกป้องกันที่จุดที่ต้องผ่าน delegate_task ด้วยการ์ด
ทั้งสี่: เพดานความลึก (ค่าเริ่มต้น 3), การตรวจจับวงจร, เพดานความเป็นอิสระ
(ผู้รับมอบหมายลงมือด้วยความเป็นอิสระมากกว่าผู้มอบหมายไม่ได้เลย — สิทธิ์พิเศษ
ไม่สามารถถูกฟอกด้วยการยกงานให้เอเจนต์ที่อิสระกว่า) และ กรอบงบประมาณ
(การมอบหมายตัดจากงบประมาณที่เหลือของผู้มอบหมายและสร้างเพิ่มไม่ได้) แต่ละอย่าง
ถูกปฏิเสธอย่างชัดเจน พร้อมเหตุผลของการ์ดที่ส่งกลับไปให้เอเจนต์ตามเดิม
เมทริกซ์ความซื่อสัตย์ของอะแดปเตอร์
หัวข้อที่มีชื่อว่า “เมทริกซ์ความซื่อสัตย์ของอะแดปเตอร์”ไม่ใช่ทุกรันไทม์ที่เปิดให้ Control Center สกัดทุกการกระทำ เอเจนต์ CLI ภายนอก รันเครื่องมือบางตัวแบบเนทีฟ ในโปรเซสเดียวกัน ซึ่งไม่มีประตูใดนั่งอยู่ได้ แทนที่ จะแกล้งทำเป็นอื่น แต่ละอะแดปเตอร์จึงมี เมทริกซ์ความซื่อสัตย์: ต่ออะแดปเตอร์ ว่า Control Center กรองพื้นผิวเครื่องมือ สกัดการเรียกเครื่องมือ สังเกตสัญญาการ จบงาน มองเห็นเครื่องมือเนทีฟของตัวรัน และว่าเครื่องมือในโปรเซสเดียวกันถูกครอบ ด้วยโปรไฟล์แซนด์บ็อกซ์หรือไม่
สองรายการควรค่าแก่การอ่านก่อนที่คุณจะเชื่อการตั้งค่าใด ๆ ฮาร์เนสในตัวประกาศว่า
เครื่องมือไฟล์ในโปรเซสของมัน ไม่ ถูกแซนด์บ็อกซ์ — พื้นผิวเครื่องมือและ
เอนจินนโยบายนี้คือขอบเขตระบบไฟล์เดียวที่มันมี Claude Code ประกาศว่าการเรียก
เครื่องมือของมันเอง สกัดไม่ได้ เพราะมันถูกเรียกด้วย
--dangerously-skip-permissions; Control Center เห็นการเรียก mcp__* ของมัน
และบรรทัดคำสั่ง Bash ผ่านฮุก ส่วนเครื่องมืออ่าน เขียน และแก้ไขของมันเองรันแบบ
ไม่ถูกเห็น
หน้าจอการตั้งค่าแสดงเมทริกซ์นี้ เพราะความล้มเหลวที่ไม่อาจให้อภัยได้อย่างเดียว สำหรับระบบกฎคุมคือการอ้างความครอบคลุมที่ไม่มีอยู่
ตรวจสอบนโยบายก่อนที่มันจะกัด
หัวข้อที่มีชื่อว่า “ตรวจสอบนโยบายก่อนที่มันจะกัด”กฎคุมอยู่ที่ การตั้งค่า → เวิร์กสเปซ → สิทธิ์ของเอเจนต์
(/workspaces/<id>/settings/workspace/permissions) หน้าจอมีเมทริกซ์นโยบายที่
ใช้เขียนกฎ เทมเพลตนโยบาย ตัวตรวจแบบสมมติ เส้นทางการตรวจสอบการอนุญาต และ
เมทริกซ์ความซื่อสัตย์ของอะแดปเตอร์
ตัวตรวจรับคลาสการกระทำ (หรือคำสั่ง) และขอบเขต แล้วแสดงว่ากฎใดตัดสินและเพราะ อะไร เพราะการตัดสินบริสุทธิ์และกำหนดได้แน่นอน — การกระทำเดิม ขอบเขตเดิม คำตอบ เดิม — คำตอบของตัวตรวจคือคำตอบที่เอเจนต์จะได้รับ
แนวคิดที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “แนวคิดที่เกี่ยวข้อง”- แซนด์บ็อกซ์และความปลอดภัย: อะไรที่จำกัดการรันของเอเจนต์จริง ๆ และพื้นของ OS ใต้เอนจินนี้เอื้อมไปไกลแค่ไหน
- การทำงานร่วมกันแบบหลายคน — ตัวตน สมาชิกภาพ และการแสดงตน: สเปซ ตัวตนหลัก และตำแหน่งของปุ่มปรับความเป็นอิสระ
- ตั้งค่ากฎคุม: การเขียนและทดสอบกฎในทางปฏิบัติ