Monitor CI with Webhooks
Custom webhook hook turns CI failure payloads into agent prompts. Verified with curl, then wired to GitHub Actions.
What you will build
This recipe connects a CI pipeline to the runtime through a custom webhook hook. When a build fails, the CI system POSTs a JSON payload to the runtime; the hook renders a Mustache template against the payload, launches a session with the review skill active, and the agent investigates.
You should already understand the webhook lifecycle and delivery states from Webhooks. This recipe does not re-explain them.
Prerequisites
- GolemCore Bot is running on a host reachable from your CI system. For local experiments,
ngrokor a tailnet is enough. - Webhooks are enabled in
preferences/webhooks.json("enabled": true). - A shared secret is set. Any CI sender must include it in the
Authorizationheader. - A skill named
ci-triage(or similar) exists. It can be a minimal stub for now — the review skill from the scheduled-code-review recipe is a good starting point.
1. Define the custom hook
Hooks live under webhooks.hooks in the preferences file. Each hook has a path, a Mustache template that renders the payload into the initial agent prompt, and optionally a skill to activate for the session.
{
"enabled": true,
"secret": "change-me-before-production",
"hooks": {
"ci-failure": {
"name": "ci-failure",
"path": "/api/hooks/ci-failure",
"active": true,
"skill": "ci-triage",
"messageTemplate": "CI build failed on branch {{branch}}.\nCommit: {{commit}}\nSummary: {{summary}}\nLogs: {{log_url}}\n\nInvestigate the failure and propose a fix."
}
}
}docker exec golemcore-bot curl -s -X POST http://localhost:8080/api/admin/reload-webhooks{"ok":true,"hooks":["ci-failure"]}2. Send a test payload
Before touching your CI config, simulate the payload with curl. This isolates template rendering and authentication from the CI plumbing.
curl -sS -X POST http://localhost:8080/api/hooks/ci-failure \
-H "Content-Type: application/json" \
-H "Authorization: Bearer change-me-before-production" \
-d '{
"branch": "main",
"commit": "9f3a1c2",
"summary": "3 of 412 tests failing in PaymentServiceTest",
"log_url": "https://ci.example.com/builds/1234"
}'{
"delivery_id": "wh_01HZ7K3V2Q",
"state": "DELIVERED",
"session_id": "sess_2026-04-10_091422"
}The session is created immediately; the agent starts working on the rendered prompt in the background. Check Sessions to see the turn unfold.
3. Wire the CI system
Once the local curl works, configure your CI provider to call the same endpoint on failure. The exact shape depends on the provider; the pattern is always the same.
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/test.sh
- name: Notify GolemCore on failure
if: failure()
run: |
curl -sS -X POST ${{ secrets.GOLEMCORE_WEBHOOK_URL }} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${{ secrets.GOLEMCORE_WEBHOOK_SECRET }}" \
-d @- <<'EOF'
{
"branch": "${{ github.ref_name }}",
"commit": "${{ github.sha }}",
"summary": "Test job failed in ${{ github.workflow }}",
"log_url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
EOFTrigger a failing build intentionally. Within a few seconds a new session should appear in the dashboard with the rendered prompt as its first turn.
Variants
No skill, just a prompt
Drop the skill field. The session starts without any overlay and the agent uses default tools only — useful when different CI systems need different follow-ups.
Lightweight
Separate success and failure hooks
Add a second hook at /api/hooks/ci-success that only runs on deployments. Use a different messageTemplate to signal 'verify the deploy went live' instead of 'investigate the failure'.
Multi-hook
Feed an Auto Mode goal
Route the hook to an Auto Mode goal instead of a one-shot session by setting goal instead of skill. Builds that fail repeatedly accumulate into the same diary.
Accumulate
Custom signature verification
Proxy through an HMAC-verifying gateway (Cloudflare Worker, nginx) if the CI provider signs payloads differently. The runtime only checks the Bearer secret — put any extra verification in front.
Security
Gotchas
401 Unauthorized
Check: curl response body. A 401 means the Authorization header is missing or the secret does not match preferences/webhooks.json. Fix: re-check the secret value and the Bearer prefix.
auth
Delivery stuck in PENDING
Check: the delivery state in Dashboard → Webhooks. If it is PENDING for more than a few seconds, the runtime is under load or the hook session could not start. Fix: inspect the Sessions page for a stuck session and the logs for skill activation errors.
delivery
Placeholders not substituted
Check: the rendered prompt in the Session first turn. If it contains literal {{branch}} instead of the value, the payload field name does not match the template. Fix: align the curl/CI payload fields with the Mustache placeholders exactly.
template
404 on the hook URL
Check: docker logs for 'hook not found'. Fix: the path in the hook definition must exactly match the URL the sender hits. The path is case-sensitive and includes the /api/hooks/ prefix.
routing
What to do next
Related pages
User Guide
Webhooks
How external systems start agent turns over HTTP: built-in endpoints, custom hooks with Mustache templates, and delivery states.
User Guide
Skills
What a skill is, how sticky activation works, and the SKILL.md contract. For concrete recipes, see the Cookbook.
Reference
Troubleshooting
Symptom-driven lookup for common runtime problems. Each entry is strict: symptom, likely cause, check, fix.