This document describes how to host CDA-AgentX on AWS EC2 using the repo Dockerfile, docker-compose.yml, and scripts/web-slack-entry.sh. It assumes ByteRover context lives under /app/.brv inside the container and Slack uses Socket Mode (no public Slack webhook URL).
| Component | Role |
|---|---|
Next.js (App Router, server.js) |
Web UI + API routes on port 3000 (PORT / HOSTNAME=0.0.0.0) |
Slack Bolt (lib/slack/bot.ts) |
Socket Mode bot — no inbound HTTP from Slack; needs outbound HTTPS |
ByteRover (brv) |
CLI baked into image; /app/.brv is the persistent context tree (same path as Compose volume) |
| MongoDB | Optional but typical in prod — Atlas or self-managed; app degrades gracefully if DB is down |
Image facts (from repo):
- Multi-stage
node:22-slimbuild;byterover-cliinstalled globally in base. - Next
output: "standalone"— runtime copies.next/standalone, static assets,lib/,scripts/. - Default Dockerfile CMD:
bash scripts/web-slack-entry.sh→ starts Next then Slack after/api/healthreturns 200 or 503 (503 = degraded but alive, e.g. DB). docker-compose.yml:cda-web=node server.js,cda-slack=node --import tsx lib/slack/bot.ts, shared volumebrv-data:/app/.brv.
- Run the image with default CMD:
bash scripts/web-slack-entry.sh. - One process group, one place to persist
/app/.brv. - Fits: one EC2 instance, simple systemd +
docker run, or ECS/Fargate one task.
cda-webandcda-slacksharebrv-dataso both see the same ByteRover tree (matches local dev).- Do not deploy web on instance A and Slack on B unless both share storage (EFS/NFS). This app expects one coherent
.brv.
| Piece | Recommendation |
|---|---|
| EC2 | Amazon Linux 2023 or Ubuntu 22.04/24.04 LTS; t3.small minimum (t3.medium+ under load); private subnet OK with NAT for egress |
| EBS | Durable GP3 volume; mount e.g. /data/cda-agent-x/brv and bind-mount to /app/.brv |
| Security groups | Inbound 443/80 (ALB/nginx) → instance 3000, or bind 127.0.0.1:3000 if reverse proxy on host; outbound: 443 for Slack/LLM/Atlas/Google/ByteRover as needed |
| TLS | ALB + ACM or nginx/Caddy on host with Let’s Encrypt |
| Secrets | Secrets Manager or SSM Parameter Store (SecureString); inject at deploy — never bake into AMI |
| MongoDB | Atlas with EC2 egress / NAT IP allowlist |
- Install Docker CE (+ Docker Compose v2 if using Option B); enable
dockerservice. - Create persistent path, e.g.
/data/cda-agent-x/brv, ownership compatible with container user (nextjs uid 1001 in image — match withchownon host or run with adjusted user mapping). - Plan disk: ingestion can write
raw/under project root patterns; ByteRover context grows — monitor disk.
docker pull <YOUR_ECR_REPO>/cda-agent-x:<tag>
docker run -d --name cda-agent-x \
--restart unless-stopped \
-p 127.0.0.1:3000:3000 \
-v /data/cda-agent-x/brv:/app/.brv \
--env-file /etc/cda-agent-x.env \
<YOUR_IMAGE>Prefer 127.0.0.1:3000 if TLS terminates on nginx/ALB on the same host or upstream.
From the repo directory, with .env on the host (not committed):
docker compose up -dFor durability clarity, operators may replace the named brv-data volume with an explicit bind mount to /data/cda-agent-x/brv.
Canonical list: .env.example. Highlights from lib/config.ts and project conventions:
Core production:
GROQ_API_KEYand/orOPENAI_API_KEY(optionalLLM_PROVIDER,LLM_MODEL,LLM_BASE_URL)SLACK_BOT_TOKEN,SLACK_APP_TOKEN- If
SLACK_ENV=personal:PERSONAL_SLACK_BOT_TOKEN,PERSONAL_SLACK_APP_TOKEN
Recommended:
MONGODB_URI,MONGODB_DB
ByteRover cloud bootstrap (ephemeral disks or disposable instances):
BYTEOVER_API_KEY— runsscripts/brv-remote-bootstrap.sh→brv login+brv pull. Seedocs/brv-cloud-sync.md.
Optional:
BRV_PATH,BRV_PROJECT_ROOT
Build note: GROQ_API_KEY is set to a placeholder only during docker build; runtime must supply real keys.
| Check | Detail |
|---|---|
| LB / scripted | GET /api/health — treat 200 or 503 as “process up” (matches scripts/web-slack-entry.sh) |
| Compose | Defined healthcheck on cda-web |
| Slack | Validate Socket Mode connectivity + message in workspace |
Rollback: pinned image digest/tag and previous container/task definition while keeping the .brv volume data.
flowchart LR
subgraph EC2["EC2 or ECS task"]
D[Docker]
N[Next server.js]
S[Slack bot tsx]
B["/app/.brv volume"]
D --> N
D --> S
N --> B
S --> B
end
User[Browser] --> ALB[ALB / nginx TLS]
ALB --> N
S <-->|Outbound wss/https| SlackAPI[Slack API]
N --> LLM[Groq / OpenAI]
N --> MG[(MongoDB)]
EC2 <-->|Optional brv pull/push| BRVCloud[ByteRover cloud]
- CI builds
Dockerfile, pushes to ECR. - Provision EC2 + EBS + SG + TLS + secrets.
- First run: pull image, attach
.brv, inject env from Secrets Manager/SSM. - With
BYTEOVER_API_KEY: bootstrap pull → Next → health → Slack. - Upgrade: new image tag + preserve
/app/.brv.
- Persistent
/app/.brvon EBS (or EFS only if concurrency/file semantics are validated for ByteRover). - Outbound 443 for Slack, LLMs, Atlas, optional Google APIs, ByteRover.
- IAM for
secretsmanager:GetSecretValueor SSM reads; no secrets in user-data history. -
brv pushafter important curates when using remote space — seescripts/brv-remote-push.shanddocs/brv-cloud-sync.md. - Atlas IP allowlist if EC2/NAT egress changes.
- Alerts: Docker restarts, disk,
/api/healthfailures from localhost.
- Running
cda-webandcda-slackon different hosts without a shared.brv— unsupported; context will diverge.
brv-cloud-sync.md- Root
README.md— Docker / Render deployment notes Dockerfile,docker-compose.yml