hall-monitor

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.

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.