ห้าม rm — ย้ายเข้า .archive แทน: กฎบรรทัดเดียวที่ทำให้ AI agent ลบพลาดแล้วกู้ได้
agent ที่รันเองลบไฟล์จริงได้ ผมเลยไม่ให้มันลบ ให้ย้ายเข้าโฟลเดอร์ .archive ตามวันที่แทน ผลจริงใน repo ที่ใช้สร้าง Terminal: ไฟล์ในถังพักรวมกว่า 1.3 แสนไฟล์ แต่ลบจริงถาวรที่ต้องลงบันทึกมีแค่ 4 ครั้ง — พร้อมขั้นตอนเต็มและ hook ตัวอย่าง
โดย วรัญชัย ยิ่งคำนึง (Boom) · เผยแพร่ครั้งแรก · ตรวจทานล่าสุด
ผมเคยเห็น agent ตีความ path ผิดแล้วสั่งลบโฟลเดอร์ที่ไม่ควรลบ วันนั้นมันอยู่ในกล่องทดลอง ของจริงไม่หาย แต่คำถามที่ค้างในหัวคือ ถ้าวันหนึ่งมันเกิดกับ index ที่ลูกค้า Boom Leverage Terminal ใช้อยู่ล่ะ
คำตอบไม่ใช่ "ทำให้ agent ไม่พลาด" — ไม่มีใครทำได้ คำตอบคือ ทำให้ความผิดพลาดกู้คืนได้ บทความนี้คือกฎที่ผมใช้จริง ตัวเลขจริง และข้อจำกัดของมัน
ทำไมต้องโฟกัสที่ "กู้กลับได้" มากกว่า "อย่าให้พลาด"?
เวลาประเมินระบบอัตโนมัติ ผมไล่ทุกการกระทำลงสองถัง: ถังที่ กด undo ได้ กับถังที่ กดไม่ได้ ของในถังแรกปล่อยให้ระบบทำเองได้ ของในถังที่สองต้องมีด่าน
rm อยู่ถังที่สองชัดเจน ลบแล้วเงียบหาย ไม่มีร่องรอยว่าใครลบอะไรเมื่อไหร่ แต่ถ้าเปลี่ยน rm เป็น mv ไปไว้ในโฟลเดอร์พักตามวันที่ การกระทำเดียวกันย้ายมาอยู่ถังแรกทันที:
rm | mv → .archive/YYYY-MM-DD/ | |
|---|---|---|
| พลาดแล้วกู้ได้ไหม | ไม่ได้ (หรือยากมาก) | ได้ในไม่กี่วินาที |
| มีร่องรอยไหม | ไม่มี | มี — โฟลเดอร์ตามวันที่คือบันทึกในตัว |
| ต้องไว้ใจ agent แค่ไหน | ต้องไว้ใจ 100% | ไม่ต้อง |
| ต้นทุน | ศูนย์ | พื้นที่ดิสก์ |
ต้นทุนเดียวคือพื้นที่ดิสก์ ซึ่งถูกกว่าการเสียงานหนึ่งวันมาก
กฎจริงเขียนไว้ว่าอะไร?

ใน File Deletion Protocol ของ CLAUDE.md เขียนไว้สั้นๆ ว่า:
ห้าม
rm—mv→.archive/YYYY-MM-DD/(mirror โครงสร้าง path เดิม)
"mirror โครงสร้าง path เดิม" สำคัญกว่าที่คิด ไฟล์ src/lib/foo.ts ที่ถูกย้ายจะไปอยู่ที่ .archive/2026-09-24/src/lib/foo.ts — เวลากู้คืน ไม่ต้องเดาว่ามันเคยอยู่ที่ไหน
แล้วถังพักจะเต็มไหม? ลบถาวรได้เมื่อไหร่?
ได้ แต่ต้องผ่านเงื่อนไขครบทุกข้อ กฎชั้นนี้เรียกว่า Stage 3 และลบถาวรได้เมื่อ:

- อยู่ใน
.archive/**แล้ว (เคยถูกตัดสินแล้วว่าเอาออกได้) หรือเป็นไฟล์ทดชั่วคราวชัดเจน - mtime ≥ 1 เดือน — และห้ามใช้ atime เพราะการ grep หรือ linter อ่านไฟล์โดยไม่อัปเดต atime ทำให้ตัดสินผิด
- ไม่มีการอ้างถึงเลย — สแกนชื่อไฟล์ ชื่อไม่มีนามสกุล และรูปแบบ slug ทั้ง repo เจอแม้แต่ที่เดียว = เก็บไว้ (กันไฟล์ที่ถูกอ่านปีละครั้งแต่สำคัญมาก)
- ลงบันทึกทุกครั้ง ใน
_rm_log.jsonlพร้อมเหตุผล
ส่วนการ archive อัตโนมัติของไฟล์ที่ไม่ได้ใช้ 30 วัน มีช่วงกัก 7 วันก่อน ถ้ามีการเข้าถึงในช่วงนั้นระบบย้ายกลับที่เดิมเอง
ผลจริงเป็นยังไง?

| ที่ | ไฟล์ใน .archive |
|---|---|
| โฟลเดอร์ home | 97,833 |
| repo กฎ + wiki (27 โฟลเดอร์วันที่ ตั้งแต่ 28 ส.ค. ถึง 26 ก.ย. 2026) | 20,967 |
| data pipeline ของ Terminal | 15,145 |
| รวม | 133,945 |
เทียบกับการลบถาวรที่ลงบันทึกใน repo กฎ/wiki ทั้งหมด 4 ครั้ง หนึ่งในนั้นคือไฟล์ index ขนาดราว 3.6 GB ที่เขียนไม่ครบเพราะเครื่องค้างกลาง build — ของที่พิสูจน์แล้วว่าเสียและสร้างใหม่ได้ ไม่ใช่ของที่ "น่าจะไม่ได้ใช้"
ตัวเลขนี้บอกว่ากฎทำงาน: การลบแทบทั้งหมดถูกเปลี่ยนเป็นการย้าย และการลบจริงที่เหลือเป็นเคสที่มีเหตุผลเขียนไว้ทุกครั้ง
บังคับกฎนี้ด้วย hook ได้ไหม?
ได้ และถ้าคุณเพิ่งเริ่ม ผมแนะนำให้ทำ ขอบอกตามจริงว่า ในระบบของผม กฎนี้บังคับด้วย CLAUDE.md + บันทึก + การตรวจรายสัปดาห์ ยังไม่ได้ใช้ hook ที่บล็อก rm ทุกครั้ง เพราะมีงาน build ที่ต้องลบ output ชั่วคราว (เช่น __pycache__) ได้ตามปกติ
ถ้าจะใช้ hook นี่คือตัวอย่าง PreToolUse hook แบบสั้นที่บล็อก rm บน tool Bash (exit code 2 = บล็อก และข้อความ stderr ถูกส่งกลับให้ agent อ่าน ตาม เอกสาร hooks ของ Claude Code):
#!/usr/bin/env python3
# .claude/hooks/guard_rm.py — ลงทะเบียนเป็น PreToolUse (matcher: "Bash")
import json, re, sys
cmd = (json.load(sys.stdin).get("tool_input") or {}).get("command", "")
if re.search(r"(^|[;&|]\s*)(sudo\s+)?rm\s", cmd):
print("ห้าม rm — ใช้ mv ไปที่ .archive/$(date +%F)/<path เดิม> แทน", file=sys.stderr)
sys.exit(2)
sys.exit(0)
ข้อควรระวังถ้าใช้จริง: regex แบบนี้จับได้เฉพาะรูปแบบตรงๆ คำสั่งที่ซ่อน rm ไว้ใน script อื่นหรือใน find -delete จะหลุด — hook คือด่านที่ดี แต่ไม่ใช่ด่านเดียว ต้องมีบันทึกและการตรวจย้อนหลังคู่กันเสมอ ดูภาพรวมของด่านหลายชั้นได้ที่ ด่านอนุมัติ + hook
สรุป
กฎ "ห้าม rm ให้ย้ายแทน" ไม่ได้ทำให้ agent ฉลาดขึ้น มันทำให้ ราคาของความผิดพลาดต่ำลงจนแทบเป็นศูนย์ ซึ่งเป็นสิ่งที่คนสร้าง product การเงินควรต้องการมากกว่า agent ที่ไม่เคยพลาด เพราะอย่างหลังไม่มีอยู่จริง