Relay Bot — Architecture and Operations
Relay is HungryHub’s Slack AI assistant. It answers questions from team docs, ClickUp tasks, and GitHub; reviews PRs; generates release notes; and maintains per-user memory across sessions.
- Repo: hungryhub-team/hh-relay
- Infrastructure: hungryhub-team/hungryhub-ai (
ecs-relay/) - URL (prod): Internal ECS Fargate service behind ALB (not public-facing; receives Slack + GitHub webhooks)
Architecture
Slack (Socket Mode) GitHub Webhooks
│ │
▼ ▼
FastAPI / Slack Bolt pr_webhook.py
(main.py) │
│ │
▼ ▼
Strands Agent ──────► Amazon Bedrock (Nova Pro / Nova Lite)
│
├── Knowledge Base retrieval (Bedrock KB — Aurora pgvector)
├── ClickUp tools (clickup_tools.py)
├── GitHub tools (github_tools.py)
└── Slack tools (slack_tools.py)
Deployment: ECS Fargate, relay-prod cluster, relay-bot-prod service — AWS account 512438352490 (hungryhub-ai), us-east-1.
Dev environment: relay-dev cluster, relay-bot-dev service — AWS account 965444437277 (genai-sandbox), us-east-1.
Key modules
| Module | Purpose |
|---|---|
main.py | Slack Bolt app, per-user agent, feedback buttons, memory management |
pr_webhook.py | GitHub webhook handler — PR notifications, review assignments, CI status, nag timers |
release_notes.py | AI-generated release notes from merged PRs |
comment_digest.py | Digests PR review thread comments into a summary |
kb_distill.py | Distils new PRs into Knowledge Base documents |
kb_distill_scheduler.py | Schedules KB distillation jobs |
clickup_tools.py | ClickUp task lookup tools for the agent |
github_tools.py | GitHub PR/issue lookup tools for the agent |
feedback_store.py | Persists reaction-based feedback to S3 for nightly eval |
token_server.py | Serves the ClickUp token submission form |
Environment variables (key ones)
| Variable | Description |
|---|---|
RELAY_ENV | prod or dev — gates DM-vs-channel routing for author nag messages |
PR_CHANNEL | Slack channel ID for PR notifications (default: #github-pr-reviews) |
PR_DEV_CHANNEL | Dev-only channel for nag message visibility (unset on prod) |
KNOWLEDGE_BASE_ID | Bedrock Knowledge Base ID |
AGENTCORE_MEMORY_ID | AgentCore memory resource ID (RelayBotMemory-zwhFEAFiqs) |
GITHUB_APP_ID | GitHub App ID for PR webhook authentication |
PR_THREADS_TABLE | DynamoDB table mapping PR URLs → Slack thread timestamps |
PR_STATE_TABLE | DynamoDB table for PR lifecycle state |
RELAY_FEEDBACK_BUCKET | S3 bucket for feedback records (nightly eval pipeline) |
Secrets (SLACK_BOT_TOKEN, SLACK_APP_TOKEN, GITHUB_WEBHOOK_SECRET, GITHUB_APP_PRIVATE_KEY, CLICKUP_TOKEN) are stored in Secrets Manager: relay/slack-tokens-{env}.
PR notifications flow
- GitHub sends a webhook to Relay’s
/github/webhookendpoint. pr_webhook.pyverifies the HMAC signature and routes by event type.- On
pull_requestopened: posts a summary card toPR_CHANNEL, assigns a reviewer, stores the thread TS in DynamoDB. - On
pull_request_review/check_suite: updates the root message with CI and review status. - On merge: fires release notes draft creation.
- Nag messages (missing tests, missing tracking link): on
prod, sent as a DM to the PR author. Ondev, posted toPR_DEV_CHANNEL(orPR_CHANNELif unset) with a “dev mode” footer.
CI/CD
- Dev: auto-deploys on every push to
main— builds image, pushes to ECR (965444437277), callsecs update-service --force-new-deployment. - Prod: deploys on GitHub Release published (via release-please) or manual
workflow_dispatch— builds separate image, pushes to ECR (512438352490). - Terraform for both environments lives in
hungryhub-ai/ecs-relay/.
Common operations
Tail prod logs
aws logs tail /ecs/relay-prod --follow --profile genai-prod --region us-east-1
Force a prod redeploy (no code change)
aws ecs update-service \
--cluster relay-prod \
--service relay-bot-prod \
--force-new-deployment \
--profile genai-prod \
--region us-east-1
Check running task environment
TASK=$(aws ecs list-tasks --cluster relay-prod --service-name relay-bot-prod \
--query 'taskArns[0]' --output text --profile genai-prod --region us-east-1)
aws ecs describe-tasks --cluster relay-prod --tasks $TASK \
--profile genai-prod --region us-east-1 \
--query 'tasks[0].containers[0].environment'
Update a secret (e.g. rotate Slack token)
aws secretsmanager get-secret-value \
--secret-id relay/slack-tokens-prod \
--profile genai-prod --region us-east-1
# Edit locally, then:
aws secretsmanager put-secret-value \
--secret-id relay/slack-tokens-prod \
--secret-string '{"SLACK_BOT_TOKEN":"xoxb-...","SLACK_APP_TOKEN":"xapp-..."}' \
--profile genai-prod --region us-east-1
# Force redeploy to pick up new secret
aws ecs update-service --cluster relay-prod --service relay-bot-prod \
--force-new-deployment --profile genai-prod --region us-east-1
Feedback loop
Slack reactions (👍 / 👎) on Relay responses are captured by feedback_store.py and written to S3 (relay-feedback-prod-512438352490). The nightly eval pipeline (eval/nightly.py) replays these as evaluation cases against the current model.
Memory
Per-user conversation memory uses Amazon Bedrock AgentCore Memory:
- Resource ID:
RelayBotMemory-zwhFEAFiqs - Each user gets a named session; Relay recalls prior context across separate conversations.