AI Context Engineering untuk Monolith Multi-Module
Monolith multi-module sering dianggap lebih sederhana untuk AI agent dibanding microservices karena semuanya ada dalam satu repo — tidak ada masalah akses lintas repo, tidak perlu pointer file eksternal. Tapi anggapan ini keliru begitu monolith-nya sudah berisi belasan module dengan domain yang berbeda-beda: agent yang mengerjakan module payment tetap bisa kebanjiran context dari module catalog, shipping, atau notification kalau tidak ada strukturisasi yang jelas. Artikel ini membahas context engineering di dalam satu repo secara konkret, memakai studi kasus e-commerce monolith dengan beberapa module utama, lengkap dengan contoh isi AGENTS.md dan CLAUDE.md di tiap layer serta best practice menjaga context tetap relevan dan sinkron.
Studi Kasus: Struktur E-Commerce Monolith Multi-Module
Supaya pembahasan konkret, kita pakai satu contoh struktur yang representatif untuk aplikasi e-commerce monolith bergaya modular — pola yang umum dipakai baik di Go (modular monolith dengan package per domain), Java/Spring (multi-module Maven/Gradle), maupun Node/TypeScript (workspace-based monorepo internal).
ecommerce-monolith/
├── AGENTS.md
├── CLAUDE.md
├── docs/
│ └── architecture.md
├── modules/
│ ├── catalog/
│ │ ├── AGENTS.md
│ │ ├── CLAUDE.md
│ │ ├── domain/
│ │ ├── application/
│ │ └── infrastructure/
│ ├── cart/
│ │ ├── AGENTS.md
│ │ ├── CLAUDE.md
│ │ └── ...
│ ├── checkout/
│ │ ├── AGENTS.md
│ │ ├── CLAUDE.md
│ │ └── ...
│ ├── payment/
│ │ ├── AGENTS.md
│ │ ├── CLAUDE.md
│ │ ├── gateway/
│ │ │ └── AGENTS.md
│ │ └── ...
│ ├── inventory/
│ │ └── ...
│ ├── shipping/
│ │ └── ...
│ ├── user/
│ │ └── ...
│ └── notification/
│ └── ...
└── shared/
├── domain/
└── AGENTS.md
Tujuh module utama: catalog (produk), cart, checkout, payment, inventory, shipping, user, dan notification. Ada juga folder shared/ untuk domain model yang dipakai lintas module — ini sengaja jadi contoh kasus khusus karena sering jadi sumber ambiguitas context.
Kenapa Monolith Multi-Module Tetap Butuh Context Engineering
Tiga alasan struktur ini tetap butuh perhatian context yang sama seriusnya dengan multi-service, meski secara teknis semua kode ada dalam satu akses:
Context window tetap terbatas. Agent yang mengerjakan bug di payment/gateway/ tidak butuh tahu detail implementasi notification/email-templates/. Akses teknis penuh tidak menghilangkan kebutuhan filtering — token tetap mahal dan noise tetap menurunkan kualitas jawaban.
Domain knowledge tetap terpisah. Konvensi module payment (harus idempotent, harus audit trail, harus terhubung ke payment gateway eksternal) sangat berbeda dari konvensi module catalog (fokus ke search performance, caching produk). Menyatukan semua ini di satu file besar membuat agent harus menyaring sendiri mana yang relevan — pekerjaan yang seharusnya sudah diselesaikan oleh strukturisasi context file.
Module boundary sering dilanggar tanpa disadari. Salah satu masalah paling umum di monolith modular adalah agent (atau developer) tanpa sadar mengimpor langsung dari internal module lain, melanggar boundary yang seharusnya dijaga lewat interface publik. Context file yang menjelaskan boundary ini secara eksplisit mengurangi risiko itu.
flowchart TD
A[Agent kerja di modules/payment/] --> B{Baca context apa?}
B -- Tanpa strukturisasi --> C[Satu AGENTS.md raksasa berisi semua module]
C --> D[Noise tinggi, konvensi campur aduk, token boros]
B -- Dengan strukturisasi --> E[Root AGENTS.md: konvensi global]
E --> F[modules/payment/AGENTS.md: konvensi domain payment]
F --> G[Context relevan, ringkas, boundary jelas]Bagaimana Context Sebenarnya Bekerja di Berbagai AI Agent
Sebelum masuk ke pola tiga layer, penting digarisbawahi: struktur root/module/local yang dibahas di artikel ini adalah pola rekomendasi berdasarkan prinsip context engineering umum — bukan mekanisme universal yang berlaku sama persis di semua AI coding agent. Tiap tool punya cara berbeda menentukan file instruksi mana yang dibaca, kapan, dan bagaimana urutannya. Memahami perbedaan ini penting supaya pola yang kamu terapkan benar-benar cocok dengan tool yang dipakai tim.
Claude Code — Lazy-Load Berbasis Lokasi Folder
Dokumentasi resmi Claude Code menjelaskan bahwa file CLAUDE.md di root (beserta level enterprise dan user di atasnya) dimuat otomatis ke context begitu sesi dimulai. Untuk CLAUDE.md yang ada di subdirectory, mekanismenya berbeda — file itu baru ikut dimuat saat Claude membaca file dari direktori tersebut, bukan sekaligus di awal sesi. Kalau agent belum pernah menyentuh file di suatu folder, CLAUDE.md di folder itu juga belum ter-load ke context, dan instruksi di dalamnya bisa tampak seperti “diabaikan” padahal sebenarnya belum sempat dibaca. Ini yang membuat perintah /memory berguna untuk mengecek file instruksi mana saja yang sudah benar-benar masuk ke context pada suatu titik dalam sesi.
Referensi: docs.anthropic.com/en/docs/claude-code/memory dan code.claude.com/docs/en/memory.
OpenAI Codex CLI — Cascading AGENTS.md dari Global sampai Direktori Kerja
Codex CLI, yang menjadi salah satu pendorong awal format AGENTS.md sebagai standar terbuka, mendukung nested AGENTS.md secara native. Perbedaan pentingnya dengan Claude Code: Codex menyusun context-nya dari beberapa layer sekaligus — level global (~/.codex/AGENTS.md), level root repo, dan level direktori kerja saat ini — lalu menggabungkannya, dengan file yang lebih lokal memenangkan konflik terhadap yang lebih general. Repo Codex milik OpenAI sendiri dilaporkan memakai puluhan AGENTS.md terpisah tersebar di seluruh direktori proyek sebagai contoh nyata pola ini diterapkan dalam skala besar.
Referensi: spesifikasi resmi di agents.md, dan dokumentasi developer OpenAI soal custom instructions dengan AGENTS.md.
Cursor — Bukan Berbasis Lokasi Folder, tapi Glob Pattern dan Aktivasi Semantik
Cursor punya pendekatan yang paling berbeda dari dua tool di atas. Alih-alih mekanisme “file terdekat ke lokasi kerja menang” seperti Claude Code dan Codex, Cursor memakai direktori .cursor/rules/ berisi file .mdc dengan empat mode aktivasi yang didefinisikan lewat YAML frontmatter:
| Mode Aktivasi | Trigger |
|---|---|
| Always Apply | Selalu dimuat di setiap request, terlepas dari lokasi file |
| Auto Attached | Dimuat kalau file yang sedang disentuh cocok dengan pattern di field globs |
| Agent Requested | AI sendiri yang memutuskan apakah rule ini relevan, berdasarkan field description |
| Manual | Hanya dimuat kalau developer secara eksplisit mengetik @nama-rule di chat |
Field globs di Cursor tidak terikat pada lokasi folder tempat rule itu disimpan — sebuah rule di .cursor/rules/backend.mdc bisa saja diaktifkan berdasarkan pattern services/api/**, meski file .mdc-nya sendiri fisiknya ada di lokasi terpusat, bukan tersebar mengikuti struktur folder kode. Ini kebalikan dari pola nested AGENTS.md/CLAUDE.md yang mengandalkan lokasi fisik file sebagai penentu kapan dia dimuat.
Referensi: dokumentasi resmi Cursor soal Rules dan format frontmatter .mdc.
Implikasi untuk Pola Tiga Layer di Artikel Ini
Karena perbedaan ini, penerapan pola root/module/local yang dibahas di artikel ini perlu disesuaikan tergantung tool:
- Claude Code — pola nested
AGENTS.md+CLAUDE.mdjembatan (seperti dibahas di bagian sebelumnya) langsung relevan, karena mekanisme lazy-load berbasis lokasi folder memang cara kerja aslinya. - Codex CLI — nested
AGENTS.mdper module juga langsung didukung native, tanpa perlu file jembatan tambahan seperti di Claude Code. - Cursor — pola nested per-folder kurang pas diterapkan apa adanya. Yang lebih sesuai adalah menerjemahkan batas module jadi
globspattern di file.mdcterpusat, atau memakaiAGENTS.mdyang tetap dibaca Cursor sebagai source of truth lintas tool, sambil menambahkan.mdckhusus untuk kebutuhan aktivasi semantik yang memang jadi kekuatan Cursor.
- Detail mekanisme ini berubah cukup cepat mengikuti update tiap tool — kalau tim kamu serius menerapkan pola ini, cek ulang dokumentasi resmi tool yang dipakai sebelum implementasi final, jangan hanya mengandalkan artikel ini sebagai satu-satunya sumber.
- Kalau tim memakai lebih dari satu tool,
AGENTS.mdsebagai source of truth tetap masuk akal karena didukung secara luas — tapi mekanisme bagaimana dia dimuat ke context tetap berbeda-beda per tool, dan itu yang menentukan seberapa efektif strukturisasi nested-mu di masing-masing tool.
Layer Konteks: Root, Module, dan Local
Pola tiga layer ini jadi kerangka utama untuk seluruh contoh konkret di artikel ini.
| Layer | Lokasi | Isi | Frekuensi Berubah |
|---|---|---|---|
| Root | /AGENTS.md | Konvensi global, tech stack, cara run/test/build, arsitektur keseluruhan | Jarang |
| Module | /modules/<nama>/AGENTS.md | Konvensi domain spesifik, boundary module, invariant bisnis | Sedang |
| Local | /modules/<nama>/<sub-folder>/AGENTS.md | Detail sangat spesifik — misalnya integrasi payment gateway tertentu | Sering |
Prinsipnya: semakin dalam levelnya, semakin spesifik dan semakin sering berubah isinya. Root file harus stabil — kalau root sering diubah, itu tanda ada konten yang seharusnya dipindah ke level module.
Skenario Konkret: Agent Memperbaiki Bug Idempotency di Payment
Untuk melihat manfaat strukturisasi ini secara nyata, bayangkan task berikut: ada bug di mana refund kadang terpotong dua kali kalau webhook dari payment gateway datang duplikat. Agent ditugaskan memperbaikinya di modules/payment/gateway/.
Tanpa strukturisasi (satu AGENTS.md raksasa di root berisi semua module), agent harus memproses seluruh konvensi catalog, cart, shipping, user, dan notification sebelum sampai ke informasi yang relevan — meski task ini sama sekali tidak menyentuh module-module itu. Selain boros token, ada risiko lebih halus: agent bisa saja “meniru” pola dari module lain yang sebenarnya tidak cocok untuk konteks payment, misalnya menganggap semua module boleh update status langsung padahal payment punya aturan state machine yang ketat.
Dengan strukturisasi tiga layer, urutan context yang ter-load justru mengikuti kebutuhan task secara alami:
- Root
AGENTS.mdter-load di awal sesi — agent tahu aturan umum cross-module dan lokasi modulepayment. - Begitu agent mulai membaca file di
modules/payment/,modules/payment/AGENTS.mdikut ter-load — agent tahu invariant idempotency dan aturan state machine sebelum menyentuh kode. - Begitu agent masuk ke
modules/payment/gateway/, file lokal di situ ikut ter-load — agent langsung tahu bahwa webhook Midtrans memang bisa duplikat, dan validasi harus lewattransaction_id + status, bukan asumsi idempotency dari sisi provider.
Poin ketiga ini penting: tanpa file lokal itu, agent kemungkinan besar akan menghabiskan waktu menyimpulkan sendiri dari kode kenapa webhook bisa duplikat — atau lebih buruk, membuat asumsi salah dan menambah state check yang keliru. Gotcha spesifik seperti ini adalah jenis informasi yang paling bernilai ditulis eksplisit di context file lokal, karena sulit disimpulkan hanya dari membaca kode.
| Pendekatan | Context yang ter-load | Relevansi dengan task |
|---|---|---|
| Satu AGENTS.md raksasa | Semua 7 module + shared, sekaligus di awal | Rendah — sebagian besar tidak relevan |
| Tiga layer (root + module + local) | Root, lalu payment, lalu gateway — bertahap sesuai kebutuhan | Tinggi — setiap layer relevan dengan langkah task saat itu |
Tooling Pendukung untuk Repo Besar: Symbol Index dan Search
Context file terstruktur menyelesaikan masalah apa konvensi yang berlaku, tapi tidak menyelesaikan masalah di mana kode yang relevan berada ketika repo sudah sangat besar. Untuk monolith dengan puluhan ribu baris kode per module, agent yang harus membaca banyak file satu-satu untuk menemukan definisi function atau pemanggilnya akan boros context dengan cara yang berbeda — bukan dari context file, tapi dari eksplorasi kode itu sendiri.
Beberapa alat yang membantu di titik ini, saling melengkapi dengan context file:
- ripgrep/grep cepat — untuk mencari string atau pattern spesifik lintas module tanpa membuka tiap file satu-satu. Banyak agent coding modern sudah menggunakan ini secara otomatis lewat tool bawaan.
- ctags/tree-sitter symbol index — memungkinkan agent “lompat” ke definisi function/struct langsung, alih-alih membaca seluruh file untuk menemukan satu definisi.
- Codebase indexing/embedding search — beberapa tool (built-in di sebagian agent, atau eksternal seperti Sourcegraph) mengindeks seluruh repo secara semantik, sehingga query seperti “di mana logika retry payment gateway” bisa langsung mengarahkan ke file yang tepat tanpa agent harus menyusuri struktur folder secara manual.
Tooling ini tidak menggantikan context file — dia melengkapi. Context file menjawab “apa aturan dan gotcha di sini”, sementara symbol index/search menjawab “di mana kode yang relevan berada”. Untuk monolith seukuran studi kasus e-commerce ini (tujuh module, kemungkinan puluhan ribu baris tiap module), kombinasi keduanya jauh lebih efektif dibanding mengandalkan agent membaca seluruh direktori secara manual setiap kali mulai task baru.
Konkret: AGENTS.md Root untuk E-Commerce Monolith
Root AGENTS.md berisi hal yang relevan untuk semua module — bukan detail satu domain tertentu.
# AGENTS.md — ecommerce-monolith
## Stack
- Go 1.23, modular monolith (bukan clean architecture penuh — lihat docs/architecture.md)
- PostgreSQL per module (schema terpisah, bukan shared table lintas module)
- Setiap module wajib expose public API lewat package `application/`,
jangan pernah import langsung dari `domain/` atau `infrastructure/` module lain.
## Struktur Module
- catalog/ → manajemen produk, kategori, search
- cart/ → keranjang belanja, berlaku per-session
- checkout/ → orkestrasi proses order dari cart ke payment
- payment/ → integrasi payment gateway, state machine transaksi
- inventory/ → stok, reservasi, sinkronisasi dengan warehouse
- shipping/ → kalkulasi ongkir, tracking pengiriman
- user/ → autentikasi, profil, alamat
- notification/ → email, push notification, SMS
Tiap module punya AGENTS.md sendiri di modules/<nama>/ — BACA file itu
sebelum mengerjakan perubahan di module tersebut. Jangan asumsikan
konvensi satu module berlaku sama di module lain.
## Build & Test
- `make test-module MODULE=<nama>` untuk test satu module saja
- `make test-all` untuk seluruh monolith (lambat, hindari kecuali perlu)
- Semua migration lewat `make migrate MODULE=<nama>`, jangan edit skema manual
## Cross-Module Rule
- Komunikasi antar module HARUS lewat interface di application/, tidak
pernah lewat akses langsung ke database module lain.
- Domain model yang dipakai lintas module (Product, Order, User) ada
di shared/domain/ — lihat shared/AGENTS.md sebelum mengubahnya.
Perhatikan: root file ini tidak menjelaskan detail bisnis payment atau algoritma search catalog — itu urusan file di level module.
Konkret: AGENTS.md per Module
Contoh — modules/payment/AGENTS.md
# AGENTS.md — payment module
## Tanggung Jawab
Module ini menangani seluruh siklus transaksi pembayaran: charge,
refund, dan rekonsiliasi dengan payment gateway eksternal.
## Invariant yang TIDAK BOLEH Dilanggar
- Setiap operasi charge/refund HARUS idempotent — gunakan idempotency_key
yang sudah ada di tabel transactions, jangan buat mekanisme baru.
- State transaksi HANYA boleh berubah lewat state machine di
domain/transaction_state.go — jangan update status secara langsung.
- Setiap perubahan status wajib menulis audit log di audit_trail table
sebagai bagian dari transaksi database yang sama (bukan best-effort
terpisah).
## Dependency ke Module Lain
- Membaca data order dari checkout module lewat application/OrderReader
interface — TIDAK mengakses tabel orders milik checkout secara langsung.
- Mempublish event payment.completed dan payment.failed yang di-consume
oleh checkout dan notification module.
## Payment Gateway
Integrasi gateway eksternal ada di gateway/ sub-folder — lihat
gateway/AGENTS.md untuk detail spesifik provider yang dipakai.
## Test
- Gunakan mock gateway di testing/mock_gateway.go untuk unit test.
- Test idempotency WAJIB ada di setiap PR yang menyentuh charge/refund flow.
Contoh — modules/catalog/AGENTS.md
# AGENTS.md — catalog module
## Tanggung Jawab
Manajemen produk, kategori, atribut varian, dan search index.
## Konvensi Spesifik Module Ini
- Setiap perubahan skema produk WAJIB disertai reindex ke Elasticsearch
(lihat infrastructure/search_indexer.go) — perubahan yang tidak
memicu reindex akan membuat data search basi.
- Harga dan stok TIDAK disimpan di module ini — harga ada di pricing
service eksternal (lihat shared/AGENTS.md), stok ada di inventory module.
## Dependency ke Module Lain
- Membaca stok dari inventory module lewat application/StockReader,
jangan pernah query tabel inventory langsung.
## Performance
- Endpoint search punya SLA p99 < 200ms — perubahan apapun di query
path harus disertai benchmark sebelum merge.
Perhatikan perbedaan gaya isi antara payment dan catalog — masing-masing fokus ke invariant dan gotcha yang benar-benar spesifik ke domainnya, bukan mengulang konvensi umum yang sudah ada di root.
Contoh — modules/payment/gateway/AGENTS.md (Local, Paling Spesifik)
# AGENTS.md — payment gateway integration
## Provider
Integrasi saat ini ke Midtrans (bukan Stripe/Xendit — sudah pernah
dicoba migrasi, lihat docs/architecture.md#adr-012 untuk alasan batal).
## Gotcha Penting
- Webhook Midtrans bisa datang duplikat — validasi selalu lewat
transaction_id + status, jangan asumsikan webhook idempotent
dari sisi mereka.
- Sandbox Midtrans punya rate limit ketat (10 req/menit) — jangan
jalankan integration test tanpa mock kecuali benar-benar perlu.
## Kredensial
Kredensial ada di vault, bukan file config — lihat
infrastructure/README.md untuk cara akses lokal.
File local seperti ini idealnya hanya dibaca ketika agent benar-benar menyentuh integrasi gateway — bukan setiap kali kerja di module payment secara umum. Ini yang membuat pola nested (bukan satu file besar) penting.
CLAUDE.md Root dan Bridge ke Setiap Module
Karena Claude Code secara native melakukan lazy-load pada file bernama CLAUDE.md di subdirectory — bukan AGENTS.md — kamu perlu file jembatan di tiap level yang juga punya AGENTS.md, supaya mekanisme discovery otomatis itu ikut terpicu.
# CLAUDE.md — root
@AGENTS.md
# modules/payment/CLAUDE.md
@AGENTS.md
# modules/payment/gateway/CLAUDE.md
@AGENTS.md
Tiap CLAUDE.md cukup satu baris import. Ini menghindari duplikasi isi — AGENTS.md tetap jadi satu-satunya source of truth yang juga bisa dibaca tool lain (Cursor, Codex CLI, Windsurf), sementara CLAUDE.md cuma jadi trigger supaya Claude Code ikut men-discover file itu secara otomatis saat bekerja di folder tersebut.
Kalau kamu tidak ingin maintain file duplikat sama sekali, alternatifnya pakai symlink:
cd modules/payment && ln -s AGENTS.md CLAUDE.md
cd gateway && ln -s AGENTS.md CLAUDE.md
sequenceDiagram
participant Agent
participant CC as Claude Code
participant Root as /CLAUDE.md
participant Mod as modules/payment/CLAUDE.md
Agent->>CC: Mulai sesi di root
CC->>Root: Load @AGENTS.md root (startup)
Agent->>CC: Task: perbaiki bug di modules/payment/
CC->>Mod: Baca file di subtree ini
Mod-->>CC: Lazy-load modules/payment/CLAUDE.md -> @AGENTS.md
CC-->>Agent: Context gabungan: root + payment module
- Root
CLAUDE.md/AGENTS.mddi-load di awal sesi. File nested hanya di-load saat Claude membaca file di subtree itu — bukan otomatis semua sekaligus di awal.- Kalau setelah kerja di suatu folder instruksi nested-nya sepertinya belum terbaca, jalankan
/memoryuntuk cek file mana saja yang sudah ter-load.
Menentukan Batas Module: Kapan Perlu AGENTS.md Sendiri
Tidak semua sub-folder butuh AGENTS.md sendiri. Aturan praktis:
BUTUH AGENTS.md sendiri jika folder tersebut:
✓ Punya domain/business rule yang berbeda dari parent-nya
✓ Sering jadi tempat kerja agent secara terpisah dari folder lain
✓ Punya gotcha/invariant spesifik yang tidak berlaku di tempat lain
✓ Merupakan boundary kepemilikan tim (meski satu repo, tim beda)
TIDAK BUTUH jika:
✗ Isinya hanya kumpulan file generik (misalnya folder utils/ kecil)
✗ Konvensi di dalamnya sama persis dengan parent
✗ Jarang sekali disentuh, dan kalaupun disentuh cukup 1-2 baris tambahan
di file parent
Untuk studi kasus e-commerce di atas, payment/gateway/ layak punya file sendiri karena provider eksternal, gotcha webhook, dan rate limit sandbox adalah hal yang sangat spesifik dan berbahaya kalau diabaikan. Sebaliknya, folder seperti payment/testing/ yang isinya cuma helper mock tidak perlu file terpisah — cukup disebut satu baris di payment/AGENTS.md.
Pertanyaan yang lebih sulit biasanya muncul di folder yang berada di tengah-tengah — tidak jelas-jelas butuh, tidak jelas-jelas tidak butuh. Untuk kasus ambigu semacam ini, heuristik yang berguna adalah bertanya: “kalau developer baru ditugaskan khusus mengerjakan folder ini selama seminggu, informasi apa yang akan mereka tanyakan berulang kali di hari pertama?” Kalau jawabannya cukup banyak dan spesifik, itu sinyal folder tersebut layak punya context file sendiri. Kalau jawabannya “sama saja dengan yang sudah ada di parent”, cukup gabungkan ke file yang sudah ada.
Penting juga diingat bahwa keputusan ini bukan sekali jadi. Module yang awalnya kecil dan cukup dijelaskan satu baris di parent bisa berkembang jadi kompleks seiring waktu — misalnya inventory/reservation/ yang tadinya sederhana bisa jadi rumit begitu ditambah logika reservasi multi-warehouse. Review context file secara berkala (idealnya bersamaan dengan review arsitektur module) membantu menangkap momen ketika sebuah sub-folder sudah waktunya “naik kelas” menjadi context file tersendiri.
Directory-Purpose Lines vs Full File Tree
Kesalahan umum saat menulis context file untuk repo besar adalah mencoba mencantumkan seluruh file tree secara detail. Ini boros token dan cepat basi begitu ada file baru.
// ANTI-PATTERN — daftar file lengkap, gampang basi
modules/payment/
├── domain/
│ ├── transaction.go
│ ├── transaction_state.go
│ ├── refund.go
│ ├── charge.go
│ └── transaction_test.go
├── application/
│ ├── payment_service.go
│ ├── order_reader.go
│ └── ...
[30 baris lagi]
// BENAR — directory-purpose lines, stabil terhadap perubahan file individual
modules/payment/
domain/ → entity & state machine transaksi (lihat invariant di atas)
application/ → use case & interface ke module lain
infrastructure/ → implementasi gateway, repository DB
gateway/ → integrasi provider eksternal (AGENTS.md sendiri)
testing/ → mock & fixture untuk unit test
Directory-purpose lines menjelaskan fungsi tiap folder dalam satu baris, bukan isi lengkapnya. Kalau ada file baru ditambahkan di dalam domain/, tidak ada yang perlu diupdate di context file — fungsinya tetap sama.
Mengelola Shared Domain Model Lintas Module
Folder shared/domain/ adalah sumber ambiguitas paling umum di monolith modular — entity seperti Product atau Order dipakai banyak module, tapi siapa yang “memiliki” perubahan terhadapnya?
# shared/AGENTS.md
## Kepemilikan Entity
- Product: dimiliki catalog module. Module lain HANYA membaca lewat
shared/domain/product.go, tidak boleh menambah field tanpa approval
dari perubahan di catalog/AGENTS.md juga.
- Order: dimiliki checkout module.
- User: dimiliki user module.
## Aturan Perubahan
Setiap perubahan struct di folder ini WAJIB:
1. Update module AGENTS.md pemilik entity terkait
2. Cek seluruh module consumer (lihat komentar "// used by" di tiap
struct) untuk breaking change
3. Jalankan make test-all (bukan test-module) karena perubahan di
sini berdampak lintas module
Pola “kepemilikan eksplisit” ini penting supaya agent tidak asal mengubah shared entity dari module manapun tanpa menyadari dampaknya ke module lain — masalah yang sama seperti kontrak API di microservices, hanya sekarang objeknya struct dalam satu repo yang sama.
- Shared domain model yang tidak punya kepemilikan eksplisit adalah sumber breaking change paling umum di monolith modular — siapa saja bisa mengubahnya, tidak ada yang merasa bertanggung jawab memvalidasi dampak lintas module.
- Jangan taruh business logic di shared/domain/ — folder ini seharusnya cuma struct/interface, logic tetap tinggal di module pemiliknya.
Sinkronisasi Context File Saat Module Berubah
Sama seperti kontrak API di multi-service, context file di monolith juga bisa basi. Bedanya, karena semua dalam satu repo, mekanisme deteksinya bisa lebih ketat karena CI punya akses penuh ke seluruh perubahan.
CI Check untuk Deteksi Perubahan Tanpa Update Context
flowchart TD
A[PR mengubah modules/payment/domain/] --> B{AGENTS.md payment ikut berubah?}
B -- Ya --> C[Lanjut review normal]
B -- Tidak, tapi perubahan signifikan* --> D[CI warning: review apakah AGENTS.md perlu update]
D --> E[Reviewer putuskan: perlu update atau memang tidak relevan]*“Signifikan” di sini bisa didefinisikan lewat heuristik sederhana — misalnya perubahan pada file yang namanya mengandung state, invariant, atau interface publik di application/.
# contoh step CI sederhana (pseudo)
- name: Check context file freshness
run: |
if git diff --name-only origin/main | grep -q "modules/payment/application/"; then
if ! git diff --name-only origin/main | grep -q "modules/payment/AGENTS.md"; then
echo "::warning::modules/payment/application/ changed but AGENTS.md was not updated. Please review."
fi
fi
Ini sengaja berupa warning, bukan hard block — karena tidak semua perubahan di folder itu otomatis butuh update context file. Tapi warning ini cukup untuk memicu reviewer (manusia atau agent) mengecek secara sadar.
Instruksi ke Agent di Root AGENTS.md
## Menjaga Context File Tetap Akurat
Jika perubahanmu menambah/menghapus interface publik di application/,
mengubah invariant bisnis, atau menambah dependency baru ke module
lain, update AGENTS.md module terkait sebagai bagian dari task —
sebelum menandai pekerjaan selesai.
Kombinasi instruksi eksplisit (advisory) dan CI warning (safety net) memberi jaminan berlapis — mirip pola yang sama dipakai untuk sinkronisasi kontrak API di multi-service, hanya sekarang dieksekusi dalam satu repo yang sama.
Anti-Pattern yang Harus Dihindari
// ✗ Satu AGENTS.md raksasa di root berisi semua detail semua module
// -- setiap sesi agent membawa noise dari module yang tidak relevan
// ✓ Root untuk konvensi global saja, detail domain di file per-module
// ✗ Context file mendaftar seluruh file tree secara manual
// -- cepat basi begitu ada file baru/dihapus
// ✓ Directory-purpose lines yang stabil terhadap perubahan file individual
// ✗ Shared domain model tanpa kepemilikan eksplisit
// -- siapa saja ubah struct tanpa sadar dampak lintas module
// ✓ Setiap shared entity punya "dimiliki oleh module X" yang jelas
// ✗ CLAUDE.md berisi salinan penuh AGENTS.md (dua sumber kebenaran)
// -- gampang out of sync begitu salah satu diupdate
// ✓ CLAUDE.md cuma satu baris @AGENTS.md, atau symlink
Checklist Review Context File Monolith
STRUKTUR:
□ Root AGENTS.md hanya berisi konvensi global, bukan detail per-domain
□ Tiap module dengan domain rule berbeda punya AGENTS.md sendiri
□ Folder generik/kecil TIDAK punya AGENTS.md terpisah yang tidak perlu
□ CLAUDE.md di tiap level cuma import (@AGENTS.md) atau symlink
ISI:
□ Invariant bisnis dan gotcha spesifik ada di level module, bukan root
□ Directory-purpose lines dipakai, bukan full file tree manual
□ Shared domain model punya kepemilikan eksplisit per entity
□ Tidak ada duplikasi isi antara root dan module
SINKRONISASI:
□ Ada instruksi eksplisit ke agent soal update context saat task selesai
□ Ada CI check/warning untuk mendeteksi perubahan signifikan tanpa
update context file
□ Root file di-review berkala — apakah masih ringkas atau mulai
membengkak
Ringkasan
- Monolith multi-module tetap butuh context engineering — akses teknis penuh ke semua kode tidak menghilangkan masalah context window dan noise antar domain.
- Tiga layer: root (konvensi global, jarang berubah), module (domain rule spesifik), local (detail sangat spesifik seperti integrasi gateway eksternal).
- Root AGENTS.md untuk stack, struktur module secara umum, dan aturan cross-module — bukan detail bisnis satu domain.
- Module AGENTS.md untuk invariant, boundary, dan dependency spesifik domain itu — beda gaya isi antar module (payment fokus idempotency, catalog fokus performance).
- CLAUDE.md di tiap level cukup satu baris
@AGENTS.mdatau symlink — supaya mekanisme lazy-load native Claude Code ikut terpicu tanpa duplikasi source of truth.- Directory-purpose lines, bukan full file tree — jelaskan fungsi folder dalam satu baris, tahan terhadap perubahan file individual.
- Shared domain model wajib punya kepemilikan eksplisit per entity — sumber breaking change paling umum kalau diabaikan.
- Sinkronisasi butuh kombinasi instruksi eksplisit ke agent dan CI warning sebagai safety net, bukan mengandalkan salah satu saja.