Skip to content

Commit 4fee4db

Browse files
cosmic-floodclaude
andcommitted
chore: prep for release pipeline — drop project-agent + skills-project, align image env contract
Removes the project-agent backend module (already gone from modules/), its orphan web frontend (`components/project-agent/*`, `api/agent-context`, `api/agent-session`), the AgentSession Prisma model + a drop migration, and the standalone skills-project catalogue. Aligns docker-compose with the actual runtime env contract of each image: - web: adds SANDBOX0_API_KEY (chat 401s without it) + SANDBOX0_BASE_URL, plus optional knobs as comments - track-service: adds ClickHouse__{Database,FlagEvaluationsTable,MetricEventsTable} overrides matching the chart Adds .github/workflows/{publish-docker-images,release-charts}.yml and RELEASING.md for the upcoming GitHub-driven release flow. Renames published image repos to featbit/featbit-rda-{track-service,web} for namespace clarity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6348e4e commit 4fee4db

32 files changed

Lines changed: 234 additions & 2373 deletions

File tree

.dockerignore

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,3 @@
55
**/dist
66
**/.env
77
**/.env.local
8-
9-
# Codex runtime state — volume-mounted at container start, must not be in build context
10-
modules/project-agent/codex-config/sessions
11-
modules/project-agent/codex-config/memories
12-
modules/project-agent/codex-config/shell_snapshots
13-
modules/project-agent/codex-config/tmp
14-
modules/project-agent/codex-config/*.sqlite
15-
modules/project-agent/codex-config/*.sqlite-shm
16-
modules/project-agent/codex-config/*.sqlite-wal
17-
modules/project-agent/codex-config/logs_*
18-
modules/project-agent/codex-config/state_*
19-
modules/project-agent/codex-config/installation_id
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Publish Docker Images
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "Image version (e.g. 0.3.0). Becomes the image tag."
8+
required: true
9+
build-latest:
10+
description: "Also tag and push :latest"
11+
type: boolean
12+
default: false
13+
required: false
14+
next-public-featbit-api-url:
15+
description: "NEXT_PUBLIC_FEATBIT_API_URL baked into the web image at build time"
16+
required: false
17+
default: "https://app-api.featbit.co"
18+
debug:
19+
description: "Print GitHub context"
20+
type: boolean
21+
default: false
22+
required: false
23+
24+
env:
25+
LATEST_TAG: latest
26+
VERSION_TAG: ${{ github.event.inputs.version }}
27+
28+
jobs:
29+
build-publish:
30+
name: Build and publish ${{ matrix.app }}
31+
runs-on: ubuntu-latest
32+
environment: Production
33+
strategy:
34+
fail-fast: false
35+
matrix:
36+
include:
37+
- app: featbit-rda-track-service
38+
build-dir: modules/track-service
39+
file: ./Dockerfile
40+
- app: featbit-rda-web
41+
build-dir: modules/web
42+
file: ./Dockerfile
43+
steps:
44+
- name: Dump GitHub context
45+
if: ${{ github.event.inputs.debug == 'true' }}
46+
run: echo "${{ toJson(github) }}"
47+
48+
- name: Set up QEMU
49+
uses: docker/setup-qemu-action@v3
50+
51+
- name: Set up Docker Buildx
52+
uses: docker/setup-buildx-action@v3
53+
54+
- name: Login to Docker Hub
55+
uses: docker/login-action@v3
56+
with:
57+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
58+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
59+
60+
- name: Build and push - ${{ matrix.app }} (${{ env.VERSION_TAG }})
61+
uses: docker/build-push-action@v5
62+
with:
63+
context: "{{defaultContext}}:${{ matrix.build-dir }}"
64+
file: ${{ matrix.file }}
65+
platforms: linux/amd64,linux/arm64
66+
push: true
67+
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ matrix.app }}:${{ env.VERSION_TAG }}
68+
build-args: |
69+
NEXT_PUBLIC_FEATBIT_API_URL=${{ github.event.inputs.next-public-featbit-api-url }}
70+
cache-from: type=gha
71+
cache-to: type=gha,mode=max
72+
73+
- name: Build and push - ${{ matrix.app }} (${{ env.LATEST_TAG }})
74+
if: ${{ github.event.inputs.build-latest == 'true' }}
75+
uses: docker/build-push-action@v5
76+
with:
77+
context: "{{defaultContext}}:${{ matrix.build-dir }}"
78+
file: ${{ matrix.file }}
79+
platforms: linux/amd64,linux/arm64
80+
push: true
81+
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ matrix.app }}:${{ env.LATEST_TAG }}
82+
build-args: |
83+
NEXT_PUBLIC_FEATBIT_API_URL=${{ github.event.inputs.next-public-featbit-api-url }}
84+
cache-from: type=gha
85+
cache-to: type=gha,mode=max
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Release Charts
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'charts/**'
9+
- '.github/workflows/release-charts.yml'
10+
11+
permissions:
12+
contents: write
13+
14+
jobs:
15+
release:
16+
runs-on: ubuntu-latest
17+
environment: Production
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Install Helm
25+
uses: azure/setup-helm@v4
26+
27+
- name: Configure Git
28+
run: |
29+
git config user.name "$GITHUB_ACTOR"
30+
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
31+
32+
- name: Run chart-releaser
33+
uses: helm/chart-releaser-action@v1.6.0
34+
env:
35+
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

.gitignore

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,28 +61,6 @@ yarn-error.log*
6161
.pnpm-debug.log*
6262

6363

64-
# =======
65-
# modules/project-agent/ (ts)
66-
# =======
67-
modules/project-agent/dist/
68-
modules/project-agent/node_modules/
69-
modules/project-agent/.pnp
70-
modules/project-agent/.pnp.*
71-
modules/project-agent/.yarn/*
72-
!modules/project-agent/.yarn/patches
73-
!modules/project-agent/.yarn/plugins
74-
!modules/project-agent/.yarn/releases
75-
!modules/project-agent/.yarn/versions
76-
modules/project-agent/coverage/
77-
modules/project-agent/.next/
78-
modules/project-agent/out/
79-
modules/project-agent/build/
80-
modules/project-agent/.vercel/
81-
modules/project-agent/next-env.d.ts
82-
modules/project-agent/*.tsbuildinfo
83-
modules/project-agent/.env
84-
!modules/project-agent/.env.example
85-
8664
# =======
8765
# modules/sandbox/ (ts)
8866
# =======

AGENTS.md

Lines changed: 17 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@
2020
│ modules/web (Next.js + Prisma) :3000 │
2121
│ Dashboard + REST API + Analysis Engine + Memory API │
2222
│ + server-side /api/sandbox0/* (Managed-mode chat proxy) │
23-
└──────┬─────────────────────────────────────────────────────┘
24-
│ TRACK_SERVICE_URL │ MEMORY_API_BASE / SYNC_API_URL
25-
26-
┌─────────────────────┐ ┌────────────────────────┐
27-
│ modules/track- │ │ modules/project-agent │
28-
│ service (.NET 10) │ │ (Codex, SSE) │
29-
│ :5050 → :8080 │ │ :3031 → :3031 │
30-
│ POST /api/track │ │ POST /query │
31-
│ POST /api/query/ │ │ (project memory + │
32-
│ experiment │ │ onboarding) │
33-
│ GET /health │ │ │
34-
└──────────┬──────────┘ └────────────────────────┘
23+
└──────┬─────────────────────────────────────────────────────┘
24+
│ TRACK_SERVICE_URL
25+
26+
┌─────────────────────┐
27+
│ modules/track- │
28+
│ service (.NET 10) │
29+
│ :5050 → :8080 │
30+
│ POST /api/track │
31+
│ POST /api/query/ │
32+
│ experiment │
33+
│ GET /health │
34+
└──────────┬──────────┘
3535
3636
┌──────────────────────┐
3737
│ modules/run-active- │
@@ -53,7 +53,7 @@ Storage:
5353
ClickHouse ← track-service read/write
5454
```
5555

56-
The four runtime services (web, track-service, project-agent, run-active-test) are wired together in `modules/docker-compose.yml`. The local-mode connector is published to npm and is **not** part of `docker compose` — each end user runs it themselves on their own machine.
56+
The runtime services (web, track-service, run-active-test) are wired together in `modules/docker-compose.yml`. The local-mode connector is published to npm and is **not** part of `docker compose` — each end user runs it themselves on their own machine.
5757

5858
---
5959

@@ -66,7 +66,7 @@ The four runtime services (web, track-service, project-agent, run-active-test) a
6666
### Responsibilities
6767

6868
- **UI**: Experiment dashboard, wizard stages (intent → hypothesis → exposure → measurement → analysis → decision → learning)
69-
- **REST API**: Experiment / run CRUD, activity log, memory, agent-session proxy
69+
- **REST API**: Experiment / run CRUD, activity log, memory
7070
- **Analysis Engine**: Bayesian A/B + Bandit analysis (in-process TypeScript)
7171
- **Memory API**: Per-project and per-user AI memory storage (`/api/memory/`)
7272

@@ -86,8 +86,7 @@ modules/web/src/
8686
│ ├─ experiments/[id]/experiment-run/ ← Run CRUD
8787
│ ├─ experiments/running/ ← GET running runs (used by workers)
8888
│ ├─ memory/project/ ← Project-scoped AI memory
89-
│ ├─ memory/user/ ← User-scoped AI memory
90-
│ └─ agent-session/[projectKey]/ ← Agent session proxy
89+
│ └─ memory/user/ ← User-scoped AI memory
9190
├─ lib/
9291
│ ├─ stats/
9392
│ │ ├─ analyze.ts ← Bayesian A/B orchestrator
@@ -267,43 +266,7 @@ The pre-connector containerised sandbox lives at `modules/sandbox/`. It is no lo
267266

268267
---
269268

270-
## 4️⃣ modules/project-agent — Project-Level AI Assistant (SSE)
271-
272-
**Language**: TypeScript (Node.js, Codex CLI)
273-
**Port** (docker): 3031
274-
**Type**: Server-Sent Events streaming
275-
276-
### Responsibilities
277-
278-
- Project onboarding assistant powered by OpenAI Codex CLI
279-
- Reads and writes shared project memory via `MEMORY_API_BASE`
280-
- Per-session env vars: `FEATBIT_PROJECT_KEY`, `FEATBIT_USER_ID`
281-
282-
### Key Files
283-
284-
```
285-
modules/project-agent/src/
286-
├─ server.ts ← Express, /query route
287-
├─ agent.ts ← Codex CLI wrapper
288-
├─ prompt.ts ← Builds system prompt with project context
289-
├─ session-store.ts ← In-memory session tracking
290-
└─ sse.ts ← SSE helpers
291-
```
292-
293-
Skills in `modules/project-agent/skills/` — loaded on demand.
294-
295-
### Environment Variables
296-
297-
| Variable | Notes |
298-
|---|---|
299-
| `OPENAI_API_KEY` | Required for Codex |
300-
| `MEMORY_API_BASE` | `http://web:3000` |
301-
| `PORT` | Default: 3031 |
302-
| `CODEX_HOME` | `/app/codex-config` (volume-mounted) |
303-
304-
---
305-
306-
## 5️⃣ modules/run-active-test-worker — Synthetic Data Generator (Cloudflare Worker)
269+
## 4️⃣ modules/run-active-test-worker — Synthetic Data Generator (Cloudflare Worker)
307270

308271
**Language**: TypeScript (Cloudflare Workers)
309272
**Trigger**: Cron, every minute
@@ -346,7 +309,7 @@ All services (except the Cloudflare Worker) run via `modules/docker-compose.yml`
346309
```
347310
modules/
348311
docker-compose.yml
349-
.env ← DATABASE_URL, CLICKHOUSE_CONNECTION_STRING, SANDBOX0_API_KEY, OPENAI_API_KEY, …
312+
.env ← DATABASE_URL, CLICKHOUSE_CONNECTION_STRING, SANDBOX0_API_KEY, TRACK_SERVICE_SIGNING_KEY, …
350313
```
351314

352315
### Service Map
@@ -355,7 +318,6 @@ modules/
355318
|---|---|---|---|
356319
| `track-service` | `featbit/track-service:local` | 5050 | ClickHouse |
357320
| `run-active-test` | `featbit/run-active-test:local` || track-service (healthy) |
358-
| `project-agent` | `featbit/project-agent:local` | 3031 | web (healthy) |
359321
| `web` | `featbit/web:local` | 3000 ||
360322

361323
The `Local Claude Code` chat path is **not** a docker service — users run `npx @featbit/experimentation-claude-code-connector` on their own machines.
@@ -567,7 +529,6 @@ Use the language-native dev loop:
567529
|---|---|
568530
| `modules/web` | `npm run dev` (Next.js HMR) — or `npx tsc --noEmit` + `npm run lint` for compile-time only |
569531
| `modules/track-service` | `dotnet run` from the project directory |
570-
| `modules/project-agent` | `npm run dev` in the module |
571532
| `modules/experimentation-claude-code-connector` | `npm run dev` (tsx watch) — only when modifying the connector itself; end-user verification is `npx @featbit/experimentation-claude-code-connector` from outside the repo |
572533
| `modules/run-active-test-worker` | `npm run dev` (wrangler dev) |
573534

RELEASING.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Releasing
2+
3+
Release flow modelled on [`featbit/featbit`](https://github.com/featbit/featbit) (Docker images) +
4+
[`featbit/featbit-charts`](https://github.com/featbit/featbit-charts) (Helm chart).
5+
6+
Two GitHub Actions workflows do all the work:
7+
8+
| Workflow | File | Trigger | Output |
9+
|---|---|---|---|
10+
| Publish Docker Images | [`.github/workflows/publish-docker-images.yml`](.github/workflows/publish-docker-images.yml) | Manual (`workflow_dispatch`) | Multi-arch images on Docker Hub: `featbit/featbit-rda-track-service:<version>` and `featbit/featbit-rda-web:<version>` |
11+
| Release Charts | [`.github/workflows/release-charts.yml`](.github/workflows/release-charts.yml) | Push to `main` under `charts/**` | A new GitHub Release `featbit-rda-<chart-version>` containing the packaged `.tgz`, plus an updated `index.yaml` on the `gh-pages` branch |
12+
13+
## One-time GitHub setup
14+
15+
1. **Create a `Production` environment** in repo Settings → Environments → New environment → name it `Production` (capital P, matches the `environment:` key in both workflows).
16+
2. **Add Docker Hub secrets to the `Production` environment**:
17+
- `DOCKER_HUB_USERNAME` — Docker Hub user/org that owns the images. Must be `featbit` to publish under the official namespace.
18+
- `DOCKER_HUB_ACCESS_TOKEN` — Docker Hub PAT with `Read, Write, Delete` on the `featbit` namespace.
19+
3. **Enable a `gh-pages` branch** for the Helm repo. The chart-releaser action will create it on first run if missing; you only need to flip Settings → Pages → Source = `gh-pages` / `/ (root)` *after* the first successful chart release so the index becomes browseable at `https://featbit.github.io/featbit-release-decision-agent`.
20+
4. **Workflow permissions** — Settings → Actions → General → Workflow permissions → "Read and write permissions". chart-releaser needs this to push to `gh-pages` and create releases.
21+
22+
## Cutting an image release
23+
24+
When you've merged code changes that need to ship in a new image:
25+
26+
1. Decide the version (e.g. `0.4.0` for track-service, or whatever you'll pin in `values.yaml` next).
27+
2. GitHub → Actions → **Publish Docker Images** → Run workflow:
28+
- **version**: `0.4.0`
29+
- **build-latest**: usually leave off; flip on for stable cuts you want `:latest` to follow.
30+
- **next-public-featbit-api-url**: defaults to `https://app-api.featbit.co` (FeatBit SaaS). Override if you're publishing an image targeting a self-hosted FeatBit backend — this value is baked into the web bundle and cannot be changed at runtime.
31+
3. Wait for both matrix jobs (`featbit-rda-track-service`, `featbit-rda-web`) to go green. Verify on Docker Hub.
32+
33+
## Cutting a chart release
34+
35+
The chart release is automatic on every push to `main` that touches `charts/**`, but only publishes when `Chart.yaml`'s `version:` is **new** (i.e. no existing GitHub Release tag matches `featbit-rda-<version>`). Workflow:
36+
37+
1. Bump image tags in `charts/featbit-rda/values.yaml` to the just-published version(s).
38+
2. Bump `version:` (and usually `appVersion:`) in `charts/featbit-rda/Chart.yaml`. Use SemVer; chart-releaser refuses to re-release a version that already has a Release.
39+
3. Commit + merge to `main`.
40+
4. The `Release Charts` workflow runs, creates GitHub Release `featbit-rda-<version>`, attaches the packaged `.tgz`, and pushes the updated `index.yaml` to `gh-pages`.
41+
42+
## Consuming the published chart
43+
44+
Once the first chart release ships and `gh-pages` is exposed via GitHub Pages:
45+
46+
```bash
47+
helm repo add featbit-rda https://featbit.github.io/featbit-release-decision-agent
48+
helm repo update
49+
helm install my-rda featbit-rda/featbit-rda --version 0.2.0
50+
```
51+
52+
Until then, point `helm install` at the local checkout (the existing flow documented in `charts/README.md`).
53+
54+
## Recommended cadence
55+
56+
- Publish images first; verify by pulling them in a smoke environment.
57+
- Then bump `values.yaml` + `Chart.yaml` in a single commit so the chart release strictly follows working images.
58+
- Image tags and chart `appVersion` don't have to match each other — track-service and web typically version independently — but the chart's own `version:` must always be bumped per release.

charts/featbit-rda/examples/aks/values.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,10 @@ trackService:
107107
secretName: "track-service-tls"
108108

109109
# ── web ────────────────────────────────────────────────────────────────────────
110-
# NOTE: `NEXT_PUBLIC_*` build args are baked at `next build` time. The default
111-
# agent backend is sandbox0 (Managed Agents) and only needs the FeatBit auth
112-
# URL at build time:
110+
# NOTE: `NEXT_PUBLIC_FEATBIT_API_URL` is baked at `next build` time:
113111
# docker build modules/web \
114112
# --build-arg NEXT_PUBLIC_FEATBIT_API_URL=https://app-api.featbit.co \
115-
# -t your-acr.azurecr.io/featbit/web:0.2.0
116-
#
117-
# `NEXT_PUBLIC_SANDBOX_URL` is only relevant when explicitly setting
118-
# `NEXT_PUBLIC_AGENT_BACKEND=classic` to revert to the SSE backend.
113+
# -t your-acr.azurecr.io/featbit/featbit-rda-web:<version>
119114
#
120115
# Server-side runtime envs (`SANDBOX0_API_KEY`, `SANDBOX0_BASE_URL`) are NOT
121116
# build-time — pass them via `extraEnv` below or project them from Azure

0 commit comments

Comments
 (0)