Documentation
Everything you need to set up and use hall-monitor.
Getting started
Setup
Install the Slack app
Add hall-monitor to your Slack workspace from the Slack App Directory. Grant the requested permissions — hall-monitor needs access to post messages and read reactions in your chosen channels.
Connect GitHub
In the hall-monitor dashboard, add a GitHub webhook pointing to your hall-monitor instance. Select push, pull_request, check_run, and deployment events. hall-monitor will validate the webhook secret automatically. Configure this in Dashboard > Settings > Webhooks.
Configure channels
Set up your channel mapping: choose which Slack channels receive PR threads, deploy threads, and incident updates. Most teams use #eng-prs, #deployments, and let incidents flow in any channel. Configure this in Dashboard > Channels.
Quickstart
Your first monitored PR
Once connected, open a PR on any monitored repo. Within seconds, a thread appears in your configured PR channel. Push a commit and watch the CI status update in real time.
Verify webhooks
Visit the hall-monitor dashboard and check the Webhooks page. You should see incoming events listed with their status. Green means processed successfully, amber means pending, red means failed. View this in Dashboard > Webhooks.
Features
PR lifecycle
Thread creation
When a PR is opened, hall-monitor creates a thread in your PR channel. The parent message shows the PR title, author, and current status. As the PR moves through its lifecycle, the parent message updates to reflect the latest state.
CI status updates
Check runs and check suites post results as thread replies. Failed checks include the failure summary and a direct link. When a fix is pushed and CI passes, a follow-up reply confirms the green status.
Review tracking
Review requests, approvals, and change requests appear as thread replies. The parent message badge updates to show current review state — pending, changes requested, or approved.
Merge and linking
When the PR merges, the thread gets a final reply with a link to the deploy thread that will include this change. The parent message updates to show merged status.
Deploy tracking
Deploy threads
Each deploy to main creates a thread in #deployments listing all included PRs. The thread updates as the deploy progresses through build, staging, and production environments.
Health checks
After each environment deploy, hall-monitor watches for health check signals. Degraded health triggers a thread reply with details. Healthy deploys get a confirmation reply before proceeding to the next environment.
Incident linking
Error report detection
When a user reports an error in any Slack channel, hall-monitor identifies the likely causing deploy by matching timestamps and error signatures. It replies on the original message with links to the deploy thread and originating PRs.
Fix lifecycle tracking
Tag a PR as a fix for an incident and hall-monitor threads its entire lifecycle back to the original error report. CI updates, reviews, deploy progress — all flow back to the incident thread so everyone watching gets the full picture.
Resolution confirmation
When the fix PR ships to production and health checks pass, the original incident thread gets a final reply confirming the fix is live. The loop is closed.
Cross-channel threading
How linking works
hall-monitor maintains a graph of related threads across channels. When an event occurs on one thread, it fans out updates to all linked threads. A deploy update in #deployments shows up as a reply on every linked PR thread in #eng-prs.
Link types
Three link types: PR-to-deploy (created on merge), deploy-to-incident (created on error detection), and incident-to-fix-PR (created when a fix is tagged). Updates flow in both directions across all link types.
Integrations
GitHub
Setting up GitHub webhooks
In your GitHub repo (or org) settings, go to Webhooks > Add webhook. Set the Payload URL to your hall-monitor instance's webhook endpoint (e.g. https://your-instance.hall-monitor.dev/api/webhooks/github). Choose application/json content type. Enter the webhook secret from your hall-monitor dashboard. Select individual events: pull_request, check_run, check_suite, push, deployment, deployment_status.
Org-level vs repo-level webhooks
Org-level webhooks deliver events for all repos in the org — useful if you want hall-monitor to cover everything. Repo-level webhooks are per-repo. Do not configure both for the same repo, or events will be delivered twice, causing duplicate threads. If using org-level webhooks, you can filter which repos hall-monitor tracks from the dashboard.
GitHub App installation (alternative)
Instead of manual webhooks, you can install the hall-monitor GitHub App from the GitHub Marketplace. The app automatically configures webhooks and permissions for selected repos. This is the recommended approach for orgs with many repos, as it avoids managing webhook secrets per-repo.
GitHub Actions
How it works
GitHub Actions natively reports status via check runs and check suites. No additional configuration is needed — if your GitHub webhook includes check_run events, Actions results appear in PR threads automatically. Each workflow run posts a status update (running, passed, failed) as a thread reply.
Deploy tracking with Actions
To track deploys triggered by GitHub Actions, your workflow must create a GitHub deployment. Add a step using actions/github-script or the GitHub CLI: gh api repos/{owner}/{repo}/deployments -f ref=$SHA -f environment=production. This triggers a deployment event that hall-monitor picks up to create a deploy thread.
CircleCI
How it works
CircleCI reports build status to GitHub as check runs when configured with GitHub Checks. hall-monitor reads these check runs from GitHub webhook events — no direct CircleCI integration is needed. Ensure your CircleCI project has GitHub Checks enabled in Project Settings > Advanced.
Deploy tracking with CircleCI
Add a deploy step that creates a GitHub deployment using the GitHub API or CLI. In your deploy job, run: curl -X POST -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/{owner}/{repo}/deployments -d '{"ref":"$CIRCLE_SHA1","environment":"production"}'. Update the deployment status to success or failure after your deploy completes.
GitLab CI
How it works
GitLab CI can report status to GitHub when using GitHub as a mirror or integration. Configure a GitHub integration in GitLab under Settings > Integrations > GitHub. This posts pipeline status as commit statuses on GitHub, which hall-monitor picks up via check_run events.
Limitations
GitLab CI integration requires GitLab Premium or Ultimate for the native GitHub integration. Alternatively, use a CI step to post status to GitHub via the GitHub API. GitLab pipeline details (individual job names) may not appear — only the overall pipeline status is reported to GitHub.
Jenkins
How it works
Jenkins reports build status to GitHub via the GitHub Checks Plugin or the older GitHub Status Plugin. Install the GitHub Checks Plugin in Jenkins, configure it with a GitHub App or token, and build status will appear as check runs on GitHub. hall-monitor reads these from webhook events.
Required Jenkins plugins
Install: GitHub plugin (for webhook triggers), GitHub Checks plugin (for reporting check runs), and Pipeline plugin (if using Jenkinsfile). Configure a GitHub server in Jenkins system settings with your GitHub API credentials. In your Jenkinsfile, use publishChecks step to report status.
Deploy tracking with Jenkins
In your deploy pipeline stage, add a step to create a GitHub deployment: sh "curl -X POST -H 'Authorization: token ${GITHUB_TOKEN}' https://api.github.com/repos/${REPO}/deployments -d '{\"ref\":\"${GIT_COMMIT}\",\"environment\":\"production\"}'". Update the deployment status in a post block to report success or failure.
API reference
Authentication
API keys
All API requests require an API key passed in the Authorization header as a Bearer token: Authorization: Bearer hm_live_xxxxxxxxxxxx. Generate and rotate keys in Dashboard > Settings > API Keys. Keys are scoped per workspace.
Authentication errors
Missing or invalid API keys return 401 Unauthorized with { "error": "invalid_api_key", "message": "The provided API key is invalid or has been revoked." }. Expired keys return the same error — generate a new key from the dashboard.
Webhooks
POST /api/webhooks/github
Receives GitHub webhook payloads. Requires a valid webhook secret configured in your dashboard. Supports push, pull_request, check_run, check_suite, deployment, and deployment_status events. Returns 200 { "received": true, "event_id": "evt_xxxx" } on success. Returns 400 for unsupported events, 401 for invalid signatures.
Webhook validation
All incoming webhooks are validated against the configured secret using HMAC-SHA256. The signature is read from the X-Hub-Signature-256 header. Invalid signatures return 401 { "error": "invalid_signature" }. Missing signatures return 400 { "error": "missing_signature" }. Example: to verify manually, compute HMAC-SHA256 of the raw body using your webhook secret and compare with the header value.
Supported event types
pull_request — opened, closed, merged, reopened, review_requested, synchronize. check_run / check_suite — created, completed, rerequested. push — commits pushed to any branch. deployment / deployment_status — deploy created, status changed (pending, success, failure, error). Each event type maps to specific thread actions: PR events update PR threads, deployment events create/update deploy threads.
Endpoints
GET /api/health
Returns 200 with JSON: { "status": "ok", "version": "1.26.0", "uptime_seconds": 86400 }. No authentication required. Use this to verify your hall-monitor instance is running and reachable. Returns 503 if the database connection is unhealthy.
GET /api/events
Lists recent events with pagination. Query parameters: type (filter by event type, e.g. "pull_request"), status ("processed", "failed", "pending"), since/until (ISO 8601 timestamps), limit (default 50, max 200), cursor (for pagination). Response: { "events": [{ "id": "evt_xxxx", "type": "pull_request", "action": "opened", "status": "processed", "received_at": "2026-04-22T10:32:00Z", "processed_at": "2026-04-22T10:32:01Z" }], "next_cursor": "..." }.
GET /api/events/:id
Returns full details for a single event, including the original webhook payload, processing status, and any linked threads. Response: { "id": "evt_xxxx", "type": "pull_request", "action": "opened", "status": "processed", "payload": { ... }, "threads": [{ "channel": "C123", "ts": "1234567890.123456" }], "received_at": "...", "processed_at": "..." }.
POST /api/events/:id/replay
Re-processes a previously received event. Useful for debugging or recovering from transient Slack API failures. Request body (optional): { "force": true } to replay even if the event was already processed successfully. Response: { "replayed": true, "event_id": "evt_xxxx", "new_status": "processed" }. Returns 404 if the event ID does not exist.
GET /api/threads
Lists active threads across all channels. Query parameters: type ("pr", "deploy", "incident"), repo (repository full name), limit/cursor. Response: { "threads": [{ "id": "thr_xxxx", "type": "pr", "title": "PR #482: Refactor webhook validation", "channel": "C123", "ts": "...", "status": "merged", "linked_threads": ["thr_yyyy"] }], "next_cursor": "..." }.
GET /api/threads/:id
Returns full thread details including all linked threads, timeline of updates, and current status. Response includes the thread graph: PR threads link to deploy threads, deploy threads link to incident threads, and incident threads link back to fix PR threads.
GET /api/channels
Lists configured channels with their event type mappings and permission status. Response: { "channels": [{ "id": "C123", "name": "eng-prs", "types": ["pull_request", "check_run"], "permissions": { "chat:write": true, "reactions:read": true } }] }.
Rate limits
API rate limits
API endpoints are rate-limited to 100 requests per minute per workspace. Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix timestamp). When exceeded, returns 429 Too Many Requests with a Retry-After header.
Webhook processing limits
Webhook ingestion is not rate-limited — all events are accepted and queued. Processing throughput depends on Slack API rate limits. The SLACK_RATE_LIMIT environment variable controls max Slack API calls per second (default: 1). Events are processed in order with exponential backoff on transient failures.
Configuration
Environment variables
Required variables
SLACK_BOT_TOKEN — your Slack bot OAuth token. SLACK_SIGNING_SECRET — used to verify incoming Slack events. GITHUB_WEBHOOK_SECRET — shared secret for GitHub webhook validation. DATABASE_URL — Postgres connection string.
Optional variables
LOG_LEVEL — defaults to "info". SLACK_RATE_LIMIT — max Slack API calls per second, defaults to 1. HEALTH_CHECK_INTERVAL — seconds between health checks after deploy, defaults to 30.
Channel mapping
Setting up channels
In the dashboard, navigate to Dashboard > Channels and map your Slack channels to event types. PR events go to your PR channel, deploy events to your deploy channel. Incident detection works in any channel — no mapping needed.
Required permissions
hall-monitor needs to be invited to each configured channel. It requires chat:write, chat:write.public, reactions:read, and channels:history scopes. Check permission status for each channel in Dashboard > Channels.
Troubleshooting
Webhook issues
Webhooks not arriving
Check the GitHub webhook delivery log in your repo settings under Webhooks > Recent Deliveries. Common causes: incorrect webhook URL (ensure it ends with /api/webhooks/github), firewall blocking inbound requests, or the webhook is paused. hall-monitor's dashboard also shows a webhook events feed — if events appear there but threads aren't created, the issue is downstream.
Signature validation failing (401)
The webhook secret in GitHub must exactly match the secret configured in hall-monitor. Regenerate the secret in both places if unsure. Common pitfalls: trailing whitespace when copying the secret, using the GitHub App secret instead of the webhook secret, or encoding differences. Check the dashboard's webhook log for the specific error.
Events received but not processed
If events show as "pending" in the dashboard, the event queue may be backed up. Check the SLACK_RATE_LIMIT setting — if set too low, processing slows under high volume. You can replay stuck events via POST /api/events/:id/replay. If events show as "failed", check the error details for Slack API errors.
Slack permission problems
Bot not posting to channels
hall-monitor must be invited to each channel it posts in. Type /invite @hall-monitor in the channel. If already invited, check the dashboard's Channels page — it shows permission status per channel. Missing chat:write scope means the Slack app needs to be reinstalled with updated permissions.
Thread replies not appearing
If the parent message posts but replies don't, check for Slack API rate limiting in the dashboard event log. hall-monitor queues replies and processes them in order. During high-volume periods (e.g. many CI checks finishing simultaneously), replies may be delayed by a few seconds. If replies consistently fail, verify the channels:history scope is granted.
Reinstalling the Slack app
If permission scopes need updating, an admin must reinstall the app. Go to your Slack workspace settings > Manage Apps > hall-monitor > Reinstall. This preserves your configuration but refreshes OAuth tokens and scopes. Existing threads continue working — only new threads use the updated permissions.
Common setup issues
Duplicate threads being created
Usually caused by multiple webhook subscriptions for the same repo. Check GitHub repo settings for duplicate webhooks pointing to hall-monitor. Also check if both a repo-level and org-level webhook are configured — this causes every event to be delivered twice. Remove the duplicate and replay any affected events.
Events going to wrong channel
Review channel mappings in the dashboard under Channels. Each event type (PR, deploy, incident) routes to a configured channel. If a repo isn't mapped, events go to the default channel. Update mappings to route specific repos to specific channels.
CI status not updating in threads
hall-monitor reads CI status from GitHub check_run and check_suite events. If your CI doesn't report via GitHub's Checks API (some older Jenkins setups, for example), status updates won't appear. Verify your CI posts check runs by viewing the PR's Checks tab on GitHub. If checks appear there but not in Slack, the check_run event may not be included in your webhook subscription — add it in GitHub webhook settings.
Deploys not being tracked
Deploy tracking requires GitHub deployment or deployment_status events. If your deployment pipeline doesn't create GitHub deployments, hall-monitor won't see them. Most CI providers have a step to create GitHub deployments — check your CI config. Alternatively, you can create deployments via the GitHub API in your deploy script: POST /repos/{owner}/{repo}/deployments.
Dashboard quick links
Jump directly to the relevant section of your admin dashboard.