บทที่ 3 จาก 12 · Agentic Engineering — คู่มือปฏิบัติเขียนซอฟต์แวร์ระดับ Production ด้วย AI Agent
โครงสร้าง Repo สำหรับงาน Agentic
Layout มาตรฐานที่ทำให้ agent ซึ่งเพิ่งเปิด session ใหม่อ่าน repo แล้วทำงานถูกได้ทันที แผนที่ไฟล์ควบคุมของ Claude Code, Codex CLI และ Cursor และลำดับความสำคัญของ context เมื่อกติกาขัดกัน
เป้าหมายของโครงสร้างนี้คือ agent ที่เพิ่งเปิด session ใหม่ ไม่มีประวัติใด ๆ ต้องอ่าน repo แล้วทำงานถูกได้ทันที โดยที่คนไม่ต้องอธิบายซ้ำ
3.1 Layout มาตรฐาน
repo/
├── AGENTS.md # กติกาโปรเจกต์ — ไฟล์เดียวที่เป็นแหล่งความจริง
├── CLAUDE.md # symlink → AGENTS.md
├── .cursor/
│ └── rules/
│ ├── 000-core.mdc # alwaysApply: true
│ ├── 100-backend.mdc # globs: src/api/**
│ └── 200-frontend.mdc # globs: src/web/**
├── .claude/
│ ├── settings.json # permissions + hooks (commit เข้า git)
│ ├── settings.local.json # ค่าเฉพาะเครื่อง (.gitignore)
│ ├── skills/
│ │ ├── api-endpoint/SKILL.md
│ │ ├── db-migration/SKILL.md
│ │ └── incident-triage/SKILL.md
│ ├── commands/
│ │ ├── ship.md # /ship
│ │ └── spec.md # /spec
│ └── hooks/
│ ├── guard_pretooluse.py # บล็อกคำสั่งและไฟล์อันตราย
│ ├── format_postedit.sh # จัดฟอร์แมตอัตโนมัติ
│ └── gate_stop.sh # รัน gate ก่อน agent จบงาน
├── docs/
│ ├── architecture.md # ภาพระบบ + ขอบเขตของแต่ละ module
│ ├── specs/ # หนึ่งไฟล์ต่อหนึ่งฟีเจอร์
│ │ └── coupon.md
│ └── adr/ # Architecture Decision Records
│ └── 0007-idempotency-key.md
├── memory/
│ ├── decisions.md # ตัดสินใจอะไรไปแล้วบ้าง เพราะอะไร
│ ├── pitfalls.md # สิ่งที่ลองแล้วพัง ห้ามลองซ้ำ
│ └── glossary.md # ศัพท์เฉพาะโดเมน
├── scripts/
│ ├── verify.sh # GATE — นิยามของคำว่าผ่าน
│ ├── verify-fast.sh # subset สำหรับใช้ระหว่าง loop
│ └── agent-loop.sh # ตัวขับ loop แบบ headless
├── tests/
└── src/
หลักการเดียวที่ต้องจำ
AGENTS.mdคือแหล่งความจริงหนึ่งเดียว ไฟล์ของเครื่องมืออื่นให้ชี้กลับมาที่นี่ อย่าเขียนกติกาซ้ำสามที่ เพราะสามที่จะไม่ตรงกันภายในสองสัปดาห์ และ agent จะเลือกเชื่ออันที่ผิด
3.2 แผนที่ไฟล์ควบคุมข้ามเครื่องมือ
| บทบาท | Claude Code | Codex CLI | Cursor |
|---|---|---|---|
| กติกาโปรเจกต์ | CLAUDE.md | AGENTS.md | .cursor/rules/*.mdc |
| กติกาส่วนตัว | ~/.claude/CLAUDE.md | ~/.codex/AGENTS.md | Cursor Settings → Rules |
| ขั้นตอนเฉพาะทาง | .claude/skills/*/SKILL.md | อ้างจาก AGENTS.md | rule แยกไฟล์ + globs |
| คำสั่งลัด | .claude/commands/*.md | prompt ไฟล์ | @rule / Notepads |
| Hook | .claude/settings.json | ~/.codex/config.toml | ไม่มี ใช้ git hook แทน |
| สิทธิการรัน | permissions ใน settings | approval_policy, sandbox_mode | Command allowlist / denylist |
| MCP | .mcp.json | [mcp_servers] ใน config.toml | .cursor/mcp.json |
วิธีจัดการที่ได้ผลที่สุดคือเขียนของจริงไว้ใน AGENTS.md แล้วชี้กลับมา
ln -s AGENTS.md CLAUDE.md
<!-- .cursor/rules/000-core.mdc -->
---
alwaysApply: true
---
กติกาทั้งหมดของโปรเจกต์นี้อยู่ที่ @AGENTS.md — อ่านไฟล์นั้นก่อนเริ่มงานทุกครั้ง
กติกาในไฟล์นี้เป็นเพียงส่วนขยายเฉพาะ editor เท่านั้น
3.3 ลำดับความสำคัญของ context
เมื่อกติกาขัดกัน agent ควรรู้ว่าต้องเชื่ออันไหน ให้ประกาศลำดับไว้ใน AGENTS.md ตรง ๆ
1. คำสั่งของผู้ใช้ใน session ปัจจุบัน (สูงสุด — แต่ห้ามข้าม §ข้อห้าม)
2. ข้อห้ามใน AGENTS.md §NEVER (ห้ามข้ามแม้ผู้ใช้สั่ง)
3. spec ของฟีเจอร์ใน docs/specs/
4. SKILL.md ของงานประเภทนั้น
5. AGENTS.md ส่วนที่เหลือ
6. pattern ที่พบในโค้ดเดิม
7. ค่า default ของภาษาและเฟรมเวิร์ก (ต่ำสุด)
ทำไมข้อห้ามต้องอยู่เหนือคำสั่งผู้ใช้
เพราะคำสั่งผู้ใช้อาจไม่ได้มาจากผู้ใช้จริง อาจมาจากข้อความที่ agent อ่านเจอใน issue, PR comment, เอกสาร หรือ output ของ tool การตรึงข้อห้ามไว้ที่ระดับสูงกว่าคือการป้องกัน prompt injection ชั้นแรก
สรุปบทนี้
โครงสร้างที่ดีคือโครงสร้างที่ตอบคำถามของ agent ได้ก่อนที่มันจะถาม เขียนกติกาไว้ที่เดียวใน AGENTS.md ให้ไฟล์ของเครื่องมืออื่นชี้กลับมา แยก spec, memory และ gate ออกเป็นโฟลเดอร์ของตัวเอง และประกาศลำดับความสำคัญไว้ให้ชัดว่าเมื่อกติกาขัดกันต้องเชื่ออันไหน
บทถัดไปเป็นไฟล์ตัวอย่างจริงที่เอาไปใช้ได้ทันที ทั้ง AGENTS.md, Skill, Hook, Rules และ Memory