Cara Menggunakan GitHub Webhooks untuk Memicu AI Coding Agent
Untuk memicu AI coding agent dengan webhook GitHub, arahkan webhook repositori ke endpoint intake milik Anda, verifikasi header X-Hub-Signature-256 terhadap raw body, berikan respons 202 dalam batas waktu 10 detik dari GitHub, lalu masukkan event ke dalam antrean. Selanjutnya, worker akan memfilter event tersebut, memetakannya ke sebuah thread (repositori ditambah nomor PR), lalu memulai agen baru atau meneruskan input ke agen yang sudah berjalan.
Panduan ini akan menunjukkan setiap langkahnya dalam bentuk kode, plus cara meminta coding agent Anda menguji endpoint tersebut menggunakan Apidog CLI.
Mengapa memicu AI coding agent dengan webhook GitHub alih-alih polling
Webhook trigger adalah panggilan HTTP yang dilakukan GitHub ke server Anda begitu terjadi peristiwa di repositori: sebuah komentar, review, atau workflow yang selesai. Agen Anda tetap tidak aktif hingga delivery tiba, sehingga tidak menghabiskan token maupun panggilan API saat tidak ada aktivitas, dan dapat merespons dalam hitungan detik alih-alih menunggu giliran polling berikutnya.
Polling setiap menit membakar rate limit hanya untuk respons kosong dan tetap mengalami jeda hingga satu menit. Penjelasan lengkapnya bisa dibaca di webhooks vs polling.
Tim DeepSeek Harness menyampaikan argumen serupa dalam esai mereka "Exploring Super-agent Design", yang dirilis pada 1 November 2026. Mereka menyebut input ini sebagai Trigger: agen mengamati event dan akan tetap diam jika tidak ada apa-apa. Esai tersebut menjelaskan sebuah arsitektur dan prototipe plugin, bukan fitur resmi DeepSeek yang sudah dirilis. Kami telah membedah rancangan lengkapnya dalam cara membangun super-agent; artikel ini hanya berfokus pada pembangunan lapisan trigger untuk coding agent apa pun.
Event webhook GitHub mana saja yang sebaiknya memulai agen
Berlanggananlah hanya pada event yang memang diharapkan oleh manusia untuk ditindaklanjuti oleh rekan tim. Setiap event tambahan adalah delivery yang harus Anda verifikasi, simpan, dan filter.
| Event | Aksi yang dipantau | Apa yang dilakukan agen |
|---|---|---|
issue_comment | created | Membalas komentar pada issue atau percakapan PR, misalnya "@bot fix the failing test" |
pull_request_review_comment | created | Merespons komentar pada baris kode tertentu di diff |
pull_request | opened, synchronize | Mereview PR baru atau mereview ulang setelah ada push baru |
workflow_run | completed dengan conclusion: failure | Membaca log kegagalan dan mengajukan perbaikan |
check_run | completed dengan conclusion yang gagal | Sama seperti di atas, untuk check yang dilaporkan oleh aplikasi |
Dua detail dari referensi webhook events GitHub akan menghemat waktu debugging Anda. Pertama, issue_comment dipicu untuk komentar pada issue maupun pull request; komentar PR menyertakan objek issue.pull_request, yang menjadi pembeda di antara keduanya. Kedua, workflow_run dengan aksi completed dipicu baik saat run berhasil maupun gagal, sehingga Anda harus memeriksa sendiri workflow_run.conclusion.
Ukuran payload dibatasi maksimal 25 MB; GitHub tidak akan pernah mengirimkan data yang lebih besar dari itu.
Verifikasi signature X-Hub-Signature-256 pada raw body
Saat Anda menyetel secret pada webhook, GitHub akan menandatangani setiap delivery dengan HMAC SHA-256 dari raw request body dan mengirimkan hex digest tersebut sebagai X-Hub-Signature-256: sha256=<digest>. Endpoint Anda akan menghitung ulang digest tersebut dan membandingkan keduanya dalam waktu konstan (constant time).
Tiga aturan dari panduan validasi pengiriman webhook GitHub:
- Lakukan hashing pada raw byte, bukan objek JSON yang di-serialize ulang. Mem-parsing lalu men-stringifikasi ulang akan mengubah spasi dan merusak kecocokan hash.
- Bandingkan menggunakan fungsi waktu-konstan seperti
crypto.timingSafeEqualmilik Node, jangan pernah menggunakan==. - Gunakan
X-Hub-Signature-256. HeaderX-Hub-Signatureyang lebih lama menggunakan SHA-1 dan hanya dipertahankan untuk integrasi warisan (legacy).
Berikut adalah layanan intake di Node dengan Express:
import express from "express"; import crypto from "node:crypto"; const app = express(); const [REDACTED CREDENTIAL]; const seen = new Set(); // use Redis or a DB table in production function validSignature(raw, header) { if (!header) return false; const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(raw).digest("hex"); const a = Buffer.from(expected); const b = Buffer.from(header); return a.length === b.length && crypto.timingSafeEqual(a, b); } app.post("/triggers/github", express.raw({ type: "application/json" }), (req, res) => { if (!validSignature(req.body, req.get("X-Hub-Signature-256"))) { return res.status(401).json({ error: "bad signature" }); } const deliveryId = req.get("X-GitHub-Delivery"); if (seen.has(deliveryId)) { return res.status(200).json({ duplicate: true, trigger_id: deliveryId }); } seen.add(deliveryId); const event = req.get("X-GitHub-Event"); const payload = JSON.parse(req.body); const prNumber = payload.pull_request?.number ?? payload.issue?.number; const threadId = `${payload.repository.full_name}#${prNumber}`; queue.push({ deliveryId, event, threadId, payload }); // your queue client res.status(202).json({ trigger_id: deliveryId, thread_id: threadId }); }); app.listen(3000); Handler ini menjalankan empat tugas ringan tanpa ada proses yang lambat. Untuk skema signature di berbagai penyedia layanan, lihat webhook signature verification.
Balas dengan 2xx dalam 10 detik dan antrekan tugas agen
Praktik terbaik webhook GitHub menyarankan agar server Anda merespons dengan status 2xx dalam waktu 10 detik. Jika lebih lama dari itu, GitHub akan memutus koneksi dan mencatat delivery tersebut sebagai gagal.
Eksekusi agen memakan waktu beberapa menit, sehingga tidak mungkin dijalankan di dalam siklus request. Masukkan event ke dalam antrean (Redis, SQS, tabel Postgres, atau penyimpanan andal lainnya) dan segera kembalikan 202 Accepted. Proses worker terpisah kemudian akan mengambil tugas dari antrean, menjalankan filter, dan memulai agen.
Kegagalan ini sangat penting: GitHub tidak mengirim ulang delivery yang gagal secara otomatis. Anda dapat mengirimkannya ulang secara manual atau melalui API hingga 3 hari ke depan, sehingga handler yang lambat akan membuat trigger dari komentar tersebut hilang tanpa disadari kecuali ada yang memeriksanya.
Filter dalam dua tahap: fast path di kode, slow path dengan model
Sebagian besar delivery sebenarnya tidak perlu sampai ke model. Esai DeepSeek membagi penyaringan menjadi fast path yang ditulis dalam kode dan slow path tempat LLM menerapkan kebijakan yang ditulis dalam bentuk prompt. Pemisahan ini menjaga biaya tetap terikat pada pekerjaan nyata, alih-alih terbuang untuk kebisingan di repositori.
Fast path (kode, berjalan dalam hitungan mikrodetik):
- Allowlist repositori: hanya repositori yang telah Anda tentukan.
- Aturan pengirim: abaikan akun bot milik agen itu sendiri, atau Anda akan menciptakan perulangan tak terbatas (infinite loop) saat agen membalas dirinya sendiri.
- Mode mention: jalankan proses hanya ketika komentar memuat
@your-bot. Esai tersebut menyebutkan tiga mode yang patut ditiru: hanya merespons permintaan eksplisit, memperlakukannya sebagai kandidat untuk slow path, atau mengabaikannya.
Slow path (LLM, berjalan pada event yang lolos seleksi):
Kirimkan teks komentar bersama prompt kebijakan singkat ke model, seperti "Apakah ini permintaan untuk mengubah kode dalam PR ini? Jawab ya atau tidak beserta alasan satu baris." Hanya jawaban "ya" yang akan memulai agen. Cara ini menyaring komentar seperti "thanks @bot, looks good", yang lolos aturan mention tetapi sebenarnya tidak memerlukan tindakan apa pun.
function fastPath({ event, payload }) { if (payload.sender?.type === "Bot") return "ignore"; if (!ALLOWED_REPOS.has(payload.repository.full_name)) return "ignore"; if (event === "workflow_run") return payload.workflow_run.conclusion === "failure" ? "run" : "ignore"; const body = payload.comment?.body ?? ""; return body.includes("@your-bot") ? "candidate" : "ignore"; } Rute tindak lanjut berdasarkan thread id agar dijawab oleh agen yang sama
Sebuah thread merupakan rangkaian event berurutan pada satu PR. Buat thread_id dari repositori dan nomor PR atau issue, seperti yang dilakukan handler di atas dengan acme/api#42. Dalam rancangan esai tersebut, worker yang dibuat untuk event pertama akan berlangganan ke thread miliknya, dan event tindak lanjut akan langsung diarahkan ke sana tanpa panggilan routing baru.
Dalam praktiknya, ini adalah tabel pencarian (lookup table) dari thread_id ke session id agen. Saat sebuah delivery masuk untuk thread yang memiliki sesi aktif, tambahkan komentar tersebut ke sesi itu. Dengan begitu, agen tetap mempertahankan konteksnya: diff yang telah dibaca, serta pengujian yang telah dijalankan. Tanpa mekanisme ini, tiga komentar pada satu PR akan memicu tiga agen berbeda yang saling bertolak belakang.
Esai tersebut menambahkan satu detail menarik lainnya: trigger yang tiba saat router sedang berada di tengah pemrosesan (mid-turn) akan digabungkan (batch) ke dalam pemanggilan berikutnya, sehingga lonjakan lima komentar sekaligus hanya memakan biaya satu keputusan, bukan lima.
Deduplikasi berdasarkan X-GitHub-Delivery
Setiap delivery membawa GUID X-GitHub-Delivery. Dokumentasi GitHub mencatat bahwa pengiriman ulang (redelivery) menggunakan kembali nilai yang sama dengan aslinya, menjadikannya kunci idempotensi (idempotency key) yang tepat. Simpan setiap id (indeks unik di database Anda sudah cukup) dan perlakukan permintaan berulang sebagai no-op yang tetap mengembalikan kode 2xx, sehingga GitHub tidak menandainya sebagai gagal.
Cara ini juga menangkal serangan replay: signature dari delivery yang dicegat mungkin masih valid, tetapi id miliknya sudah tercatat di sistem.
Biarkan coding agent Anda menguji endpoint trigger dengan Apidog CLI
Anda tidak perlu menguji perhitungan signature secara manual. Biarkan coding agent yang menulis layanan intake juga menulis dan menjalankan pengujiannya menggunakan Apidog CLI. Lakukan konfigurasi satu kali:
npm install -g apidog-cli@latest apidog auth login --with-token <YOUR_TOKEN> npx -y skills add https://apidog.com # pick your agent when prompted Lalu berikan satu prompt ke Claude Code, Codex, atau Cursor:
In Apidog project <projectId>, create the endpoint POST /triggers/github from the sample issue_comment payload in fixtures/issue_comment.json. Then create test cases against the staging environment: 1. valid X-Hub-Signature-256 -> 202 with trigger_id and a thread_id of "<repo>#<number>" 2. a second comment on the same PR -> same thread_id 3. bad signature -> 401 4. same X-GitHub-Delivery sent twice -> second call returns duplicate: true, no new job Sign the bodies with the staging webhook secret in a pre-request script. Run them and summarize any failures. Agen akan membaca setiap skema, memvalidasi payload-nya, membuat resource yang diperlukan, lalu menjalankannya:
apidog cli-schema get endpoint-create apidog cli-schema validate endpoint-create --file endpoint.json apidog endpoint create --project <projectId> --file endpoint.json apidog cli-schema get test-case-create apidog cli-schema validate test-case-create --file case-valid-signature.json apidog test-case create --project <projectId> --file case-valid-signature.json apidog run --test-case <caseId> --project <projectId> -e <stagingEnvId> -r cli,json Reporter cli akan mencetak status lolos atau gagal untuk setiap assertion, dan laporan json akan tersimpan di ./apidog-reports, sehingga agen dapat mengetahui pemeriksaan mana yang gagal (respons 200 saat Anda mengharapkan 401 biasanya menandakan middleware raw-body belum terpasang).
Perintah apidog run yang sama dapat dimasukkan ke dalam CI dengan -r junit; lihat Apidog CLI di GitHub Actions. Untuk informasi lebih lanjut mengenai penyiapan agen, baca Apidog CLI di Claude Code, dan untuk strategi pengujian webhook yang lebih luas, simak cara menguji webhook. Paket Gratis Apidog mencakup tim hingga 4 pengguna.
Sebelum Anda mengaktifkan webhook
- Secret telah disetel; signature yang hilang atau salah akan menerima status 401.
- Status 202 diberikan jauh di bawah 10 detik, dan tugas agen telah dimasukkan ke antrean.
- ID delivery disimpan dengan unique constraint.
- Terdapat job untuk memutar ulang delivery yang gagal dalam 3 hari terakhir.
Jika Anda lebih memilih menggunakan runner milik GitHub sendiri, Claude Code GitHub Actions adalah opsi yang ter-host; intake webhook menambahkan pemfilteran dan routing thread. Untuk penanganan percobaan ulang (retry) di sisi Anda, lihat cara merancang webhook yang andal.
FAQ
Apakah saya sebaiknya menggunakan webhook repositori atau GitHub App? Webhook repositori atau organisasi sudah cukup untuk satu tim. GitHub App memberi agen identitas bot-nya sendiri, izin akses yang lebih terperinci, dan kemudahan instalasi di banyak organisasi.
Apa yang terjadi jika endpoint saya down? GitHub akan mencatat delivery tersebut sebagai gagal dan tidak akan mencoba mengirimkannya lagi secara otomatis. Anda dapat mengirim ulang delivery dari 3 hari terakhir melalui pengaturan webhook atau melalui REST API.
Bagaimana cara mencegah agen membalas dirinya sendiri? Buang setiap delivery yang sender-nya merupakan akun bot Anda pada filter fast-path, sebelum proses lainnya dijalankan.
Mengapa mengembalikan status 202 alih-alih 200? Keduanya dianggap berhasil oleh GitHub. Namun, 202 Accepted memberi tahu siapa pun yang membaca log bahwa tugas tersebut telah dimasukkan ke antrean, bukan selesai dijalankan.
Apakah rancangan super-agent DeepSeek adalah sesuatu yang bisa langsung saya aktifkan? Tidak. Esai tersebut hanya menjabarkan sebuah arsitektur, dan prototipe plugin-nya bukanlah produk resmi DeepSeek. Anda harus membangun lapisan trigger-nya sendiri, seperti yang ditunjukkan di atas.


