docs(vercel): improve Codex prompts with progress trackers, preconditions, verification gates, and per-repo checklists

This commit is contained in:
saravanakumardb1 2026-03-29 16:29:42 -07:00
parent 5fb5a7d468
commit 80e6268924
2 changed files with 619 additions and 158 deletions

View File

@ -1,16 +1,67 @@
# Track A: Azure VM — Gateway, Dashboards & Security
> **Agent:** Codex on Azure VM (`/opt/bytelyst/`)
> **Prompts:** 4 (run in order)
> **Dependency:** None — this track runs first, unblocks Track B Prompt 4
> **Prompts:** 4 (run in dependency order below)
> **Unblocks:** Track B Prompt B4 (`.npmrc` migration — needs `gitea.bytelyst.com` live)
> **Reference docs:**
>
> - [`SECURE_API_EXPOSURE.md`](../single_azure_vm/docker/SECURE_API_EXPOSURE.md) — Caddy decision + architecture
> - [`DEPLOYMENT_STATUS_2026-03-29.md`](../single_azure_vm/docker/DEPLOYMENT_STATUS_2026-03-29.md) — current VM status
> - [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) — full Vercel audit
---
## Progress Tracker
| # | Prompt | Status | Commit SHA | Verified |
| --- | ------------------------ | :------------: | :--------: | :------: |
| A1 | Caddy Gateway Setup | ⬜ Not started | — | ⬜ |
| A2 | Gitea HTTPS Exposure | ⬜ Not started | — | ⬜ |
| A3 | Dashboard Containers Fix | ⬜ Not started | — | ⬜ |
| A4 | NSG Lockdown | ⬜ Not started | — | ⬜ |
**Execution order:**
```
A1: Caddy Gateway ──→ A2: Gitea HTTPS ──→ A4: NSG Lockdown
└──→ A3: Dashboard Fix (parallel with A2)
```
---
## DNS Prerequisites (manual — do before starting)
These DNS records must exist before Caddy can obtain Let's Encrypt certificates:
| Record | Type | Value | Purpose |
| ---------------------- | ---- | ---------------------- | ------------------- |
| `api.bytelyst.com` | A | `<Azure VM public IP>` | Backend API gateway |
| `gitea.bytelyst.com` | A | `<Azure VM public IP>` | Gitea npm registry |
| `admin.bytelyst.com` | A | `<Azure VM public IP>` | Admin dashboard |
| `tracker.bytelyst.com` | A | `<Azure VM public IP>` | Tracker dashboard |
**Verify DNS before starting A1:**
```bash
dig +short api.bytelyst.com # must return VM IP
dig +short gitea.bytelyst.com # must return VM IP
```
---
## A1: Caddy Gateway — Replace Traefik with Caddy
> **Depends on:** Nothing
> **Depends on:** DNS records for `api.bytelyst.com`
> **Blocks:** A2, A3, A4
### Preconditions
- [ ] `api.bytelyst.com` DNS A record resolves to Azure VM IP
- [ ] All 13 backend services are healthy: `docker compose ps | grep -c healthy` → 13+
- [ ] Ports 80 and 443 are open in Azure NSG
### Prompt
```
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
@ -18,34 +69,66 @@ TASK: Replace the existing Traefik gateway container with Caddy to provide HTTPS
CONTEXT:
- The decision doc is at docs/devops/single_azure_vm/docker/SECURE_API_EXPOSURE.md in the learning_ai_common_plat repo
- The domain is bytelyst.com
- The domain is bytelyst.com — DNS A records already point to this VM
- API hostname: api.bytelyst.com
- Currently 13 backend services are healthy on ports 4003, 4005, 4007, 4010-4019
- Traefik is running but only as a passthrough — no TLS, no path routing hardened
- All backend containers are on a Docker network
DELIVERABLES:
1. Create a Caddyfile with:
TASK LIST:
- [ ] 1. Create a Caddyfile at /opt/bytelyst/Caddyfile with:
- api.bytelyst.com as the main host (automatic Let's Encrypt TLS)
- Path-based routing to all 13 backends:
/platform/* → platform-service:4003
/extraction/* → extraction-service:4005
/mcp/* → mcp-server:4007
/peakpulse/* → peakpulse:4010
/chronomind/* → chronomind:4011
/jarvisjr/* → jarvisjr:4012
/nomgap/* → nomgap:4013
/mindlyst/* → mindlyst:4014
/lysnrai/* → lysnrai:4015
/notelett/* → notelett:4016
/flowmonk/* → flowmonk:4017
/platform/* → platform-service:4003
/extraction/* → extraction-service:4005
/mcp/* → mcp-server:4007
/peakpulse/* → peakpulse:4010
/chronomind/* → chronomind:4011
/jarvisjr/* → jarvisjr:4012
/nomgap/* → nomgap:4013
/mindlyst/* → mindlyst:4014
/lysnrai/* → lysnrai:4015
/notelett/* → notelett:4016
/flowmonk/* → flowmonk:4017
/actiontrail/* → actiontrail:4018
/localmemgpt/* → localmemgpt:4019
- Strip the path prefix before forwarding (backends expect / not /platform/)
2. Add a caddy service to docker-compose replacing or alongside the gateway service
3. Stop publishing backend ports (4003, 4005, 4007, 4010-4019) publicly — only expose 80/443
4. Verify all 13 backends respond via https://api.bytelyst.com/<service>/health
5. Update docs/devops/single_azure_vm/docker/README.md with the new access model
- [ ] 2. Add a caddy service to docker-compose replacing or alongside the gateway service
- Image: caddy:2-alpine
- Volumes: ./Caddyfile:/etc/caddy/Caddyfile, caddy_data:/data, caddy_config:/config
- Ports: 80:80, 443:443
- Network: same Docker network as all backends
- [ ] 3. Remove published backend ports from docker-compose (4003, 4005, 4007, 4010-4019)
— backends remain accessible internally via Docker DNS
- [ ] 4. Restart the stack: docker compose up -d
- [ ] 5. Wait for Caddy to obtain TLS certificates (check logs: docker logs caddy --tail 50)
- [ ] 6. Update docs/devops/single_azure_vm/docker/README.md with the new access model
VERIFICATION (run all — every check must pass):
# TLS certificate obtained
curl -sI https://api.bytelyst.com/platform/health | head -5
# Expected: HTTP/2 200 + valid TLS
# All 13 backends reachable via path routing
for svc in platform extraction mcp peakpulse chronomind jarvisjr nomgap mindlyst lysnrai notelett flowmonk actiontrail localmemgpt; do
echo -n "$svc: "; curl -sf https://api.bytelyst.com/$svc/health | jq -r '.status // "FAIL"'
done
# Expected: all 13 print "ok"
# Direct port access blocked from outside
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:4003/health && echo "FAIL: port still open" || echo "PASS: port closed"
# Expected: "PASS: port closed"
SUCCESS CRITERIA:
- All 13 health checks return "ok" via https://api.bytelyst.com/<service>/health
- TLS certificate is valid (Let's Encrypt)
- No backend ports (4003-4019) accessible directly from public internet
- Traefik config preserved but not in use
ROLLBACK:
If Caddy fails, revert docker-compose changes and restart Traefik:
git checkout -- docker-compose*.yml
docker compose up -d
DO NOT:
- Delete the existing Traefik config — just stop using it
@ -59,8 +142,16 @@ COMMIT: feat(gateway): replace Traefik with Caddy for HTTPS path routing
## A2: Gitea HTTPS Exposure via Caddy
> **Depends on:** A1 (Caddy must be running)
> **Blocks:** Track B Prompt B4
> **Depends on:** A1 ✅ (Caddy running + TLS working)
> **Blocks:** Track B → B4 (`.npmrc` update across all repos)
### Preconditions
- [ ] A1 is complete — Caddy is running with valid TLS on `api.bytelyst.com`
- [ ] `gitea.bytelyst.com` DNS A record resolves to Azure VM IP
- [ ] Gitea container is running: `docker compose ps gitea` → healthy
### Prompt
```
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
@ -69,66 +160,144 @@ TASK: Expose the Gitea npm registry over HTTPS via the Caddy gateway so that ext
CONTEXT:
- Gitea is running on port 3300 inside the Docker network
- Caddy is already configured for api.bytelyst.com (from A1)
- Caddy is already configured for api.bytelyst.com (from A1) and has valid TLS
- The Gitea npm registry URL pattern is: /api/packages/ByteLyst/npm/
- Gitea needs its own subdomain because its internal routing expects to be at root
- Target URL: https://gitea.bytelyst.com
DELIVERABLES:
1. Add a gitea.bytelyst.com block to the Caddyfile:
gitea.bytelyst.com {
reverse_proxy gitea:3300
}
2. Ensure Gitea's ROOT_URL / SERVER__ROOT_URL is updated to https://gitea.bytelyst.com
3. Verify https://gitea.bytelyst.com loads the Gitea web UI
4. Verify npm registry is accessible:
curl -s https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | head
5. Remove port 3300 from public NSG rules (Gitea only accessible via Caddy now)
6. Lock down other operational ports from public access where possible:
- 8025 (Mailpit)
- 8080 (Traefik dashboard — no longer needed)
- 10000 (Azurite)
TASK LIST:
- [ ] 1. Add a gitea.bytelyst.com block to the Caddyfile:
gitea.bytelyst.com {
reverse_proxy gitea:3300
}
- [ ] 2. Reload Caddy: docker exec caddy caddy reload --config /etc/caddy/Caddyfile
- [ ] 3. Update Gitea's ROOT_URL to https://gitea.bytelyst.com
— Edit docker-compose env: SERVER__ROOT_URL=https://gitea.bytelyst.com
— Restart Gitea container: docker compose restart gitea
- [ ] 4. Remove port 3300 from docker-compose published ports (Gitea only via Caddy)
- [ ] 5. Remove stale public NSG rules for ports that should not be exposed:
- 3300 (Gitea)
- 8025 (Mailpit)
- 8080 (Traefik dashboard — no longer needed)
- 10000 (Azurite)
VERIFICATION (run all — every check must pass):
# Gitea web UI loads
curl -sI https://gitea.bytelyst.com | head -3
# Expected: HTTP/2 200 (or 302 redirect to login)
# npm registry returns package metadata
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
# Expected: "@bytelyst/errors"
# Authenticated npm install works
export GITEA_NPM_TOKEN=<token>
npm view @bytelyst/errors --registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
# Expected: package info printed (version, description, etc.)
# Direct port 3300 access blocked from outside
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:3300 && echo "FAIL" || echo "PASS: port closed"
# Expected: "PASS: port closed"
# Internal Docker access still works
docker exec platform-service curl -sf http://gitea:3300/api/v1/version | jq '.version'
# Expected: Gitea version string
SUCCESS CRITERIA:
- https://gitea.bytelyst.com serves Gitea web UI with valid TLS
- npm registry API returns valid package metadata
- Authenticated `npm view` succeeds
- Port 3300 not accessible from public internet
- Docker-internal access to gitea:3300 still works (other containers unaffected)
DO NOT:
- Break existing Docker-internal Gitea access (other containers still use gitea:3300)
- Remove the Gitea container or change its internal port
COMMIT: feat(gateway): expose Gitea npm registry via HTTPS at gitea.bytelyst.com
AFTER COMPLETING: Notify the operator that Track B → B4 (.npmrc migration) is now unblocked.
```
---
## A3: Fix admin-web and tracker-web Containers
> **Depends on:** A1 (Caddy gateway for subdomain routing)
> **Blocks:** Nothing
> **Depends on:** A1 ✅ (Caddy running for subdomain routing)
> **Blocks:** Nothing (independent of Track B)
> **Can run in parallel with:** A2
### Preconditions
- [ ] A1 is complete — Caddy is running
- [ ] `admin.bytelyst.com` and `tracker.bytelyst.com` DNS A records resolve to VM IP
- [ ] Source code for dashboards is available on the VM
### Prompt
```
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
TASK: Resolve the remaining admin-web and tracker-web containers so they are running and healthy.
TASK: Resolve the remaining admin-web and tracker-web containers so they are running and healthy, then expose them via Caddy.
CONTEXT:
- Per DEPLOYMENT_STATUS_2026-03-29.md, all 13 backend services are healthy
- admin-web and tracker-web are the two remaining unresolved containers
- Both are Next.js 16 apps from the learning_ai_common_plat repo under dashboards/
- admin-web and tracker-web are the two remaining UNRESOLVED containers
- Both are Next.js 16 apps from learning_ai_common_plat under dashboards/
- Both use workspace:* dependencies resolved by pnpm
- Both use the --webpack build flag
- admin-web runs on port 3001, tracker-web on port 3003
- The Docker build context is dashboards/admin-web/ and dashboards/tracker-web/
- admin-web port: 3001, tracker-web port: 3003
- Docker build context: dashboards/admin-web/ and dashboards/tracker-web/
DELIVERABLES:
1. Diagnose why admin-web and tracker-web builds failed
2. Fix the build issues (likely @bytelyst/* package resolution or standalone entrypoint)
3. Rebuild and start both containers
4. Verify health:
curl -s http://127.0.0.1:3001 | head
curl -s http://127.0.0.1:3003 | head
5. Add Caddy routes for the dashboards:
- https://admin.bytelyst.com → admin-web:3001
- https://tracker.bytelyst.com → tracker-web:3003
6. Update DEPLOYMENT_STATUS_2026-03-29.md to reflect the fix
7. Mark Phase 7 as DONE if all services are now healthy
TASK LIST:
- [ ] 1. Check current container status:
docker compose ps admin-web tracker-web
docker compose logs admin-web --tail 100
docker compose logs tracker-web --tail 100
- [ ] 2. Diagnose the build/runtime failure (likely causes):
- @bytelyst/* package resolution — may need .docker-deps/ tarballs
- Standalone entrypoint not found
- Missing env vars (COSMOS_ENDPOINT, COSMOS_KEY, JWT_SECRET)
- [ ] 3. Fix the identified issues
- [ ] 4. Rebuild and restart:
docker compose up -d --build admin-web tracker-web
- [ ] 5. Add Caddy routes for the dashboards to the Caddyfile:
admin.bytelyst.com {
reverse_proxy admin-web:3001
}
tracker.bytelyst.com {
reverse_proxy tracker-web:3003
}
- [ ] 6. Reload Caddy: docker exec caddy caddy reload --config /etc/caddy/Caddyfile
- [ ] 7. Update DEPLOYMENT_STATUS_2026-03-29.md to reflect the fix
VERIFICATION (run all — every check must pass):
# Containers healthy
docker compose ps admin-web tracker-web
# Expected: both show "Up" and "healthy" (or at least "Up")
# Local port access
curl -sf http://127.0.0.1:3001 | head -5
curl -sf http://127.0.0.1:3003 | head -5
# Expected: HTML response from each
# HTTPS via Caddy
curl -sI https://admin.bytelyst.com | head -3
# Expected: HTTP/2 200 (or 302)
curl -sI https://tracker.bytelyst.com | head -3
# Expected: HTTP/2 200 (or 302)
# All containers now healthy
docker compose ps | grep -E "(unhealthy|Exit)" | wc -l
# Expected: 0
SUCCESS CRITERIA:
- Both admin-web and tracker-web containers are running
- Both respond on their ports (3001, 3003)
- Both accessible via HTTPS at admin.bytelyst.com and tracker.bytelyst.com
- DEPLOYMENT_STATUS doc updated with fix details
- Zero unhealthy containers in the full stack
COMMIT: fix(deployment): resolve admin-web and tracker-web containers
```
@ -137,41 +306,126 @@ COMMIT: fix(deployment): resolve admin-web and tracker-web containers
## A4: NSG Lockdown — Reduce Public Port Exposure
> **Depends on:** A1 + A2 (Caddy handling all traffic)
> **Depends on:** A1 + A2 + A3 all complete (all traffic routed through Caddy)
> **Blocks:** Nothing
> **Run this LAST in Track A**
### Preconditions
- [ ] A1 complete — all backends accessible via `api.bytelyst.com`
- [ ] A2 complete — Gitea accessible via `gitea.bytelyst.com`
- [ ] A3 complete — dashboards accessible via `admin.bytelyst.com` and `tracker.bytelyst.com`
- [ ] All services verified working through Caddy (no direct port access needed)
### Prompt
```
TASK: Reduce the Azure NSG (Network Security Group) rules so only ports 80, 443, and 22 are publicly accessible.
CONTEXT:
- The Azure VM currently exposes many service ports publicly (3000-3300, 4003-4019, 8025, 8080, 10000, 11434)
- Caddy now handles all public HTTPS traffic on 80/443
- Backend services, Gitea, Grafana, Mailpit, and Azurite are all accessed through Caddy
- Caddy now handles ALL public HTTPS traffic on ports 80/443
- All services (backends, Gitea, dashboards, monitoring) are accessed through Caddy subdomains
- Only SSH (22) and HTTP/HTTPS (80/443) should remain publicly open
- This follows the recommendation in SECURE_API_EXPOSURE.md
DELIVERABLES:
1. List current NSG rules: az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table
2. Remove or deny inbound rules for all ports except 22, 80, 443
3. Verify Caddy still serves all routes correctly
4. Verify SSH access still works
5. Document the changes in DEPLOYMENT_STATUS_2026-03-29.md
TASK LIST:
- [ ] 1. Snapshot current NSG rules (save output for rollback reference):
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table > /opt/bytelyst/nsg-rules-before.txt
cat /opt/bytelyst/nsg-rules-before.txt
- [ ] 2. Identify rules to remove — everything except:
- SSH (22/tcp)
- HTTP (80/tcp)
- HTTPS (443/tcp)
- [ ] 3. Delete each unnecessary rule:
az network nsg rule delete --resource-group <rg> --nsg-name <nsg> --name <rule-name>
- [ ] 4. List final NSG rules to confirm only 3 remain:
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table
- [ ] 5. Document changes in DEPLOYMENT_STATUS_2026-03-29.md
VERIFICATION (run all — every check must pass):
# SSH still works
ssh -o ConnectTimeout=5 <user>@<VM_IP> echo "SSH OK"
# Expected: "SSH OK"
# Caddy still serves all routes
curl -sf https://api.bytelyst.com/platform/health | jq '.status'
# Expected: "ok"
curl -sf https://gitea.bytelyst.com/api/v1/version | jq '.version'
# Expected: version string
curl -sI https://admin.bytelyst.com | head -1
# Expected: HTTP/2 200 (or 302)
# Direct port access blocked
for port in 3001 3003 3300 4003 4005 8025 8080 10000; do
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:$port && echo "FAIL: $port open" || echo "PASS: $port closed"
done
# Expected: all "PASS: <port> closed"
# Only 3 NSG rules remain
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table | grep -c Allow
# Expected: 3 (SSH, HTTP, HTTPS)
SUCCESS CRITERIA:
- Only ports 22, 80, 443 open in NSG
- SSH access confirmed working
- All Caddy routes still functional
- No direct port access possible from public internet
- Before/after NSG snapshots saved
ROLLBACK:
If services become unreachable after lockdown:
# Re-add a rule temporarily
az network nsg rule create --resource-group <rg> --nsg-name <nsg> \
--name AllowTemp --priority 200 --access Allow --direction Inbound \
--source-address-prefixes '*' --destination-port-ranges <port> --protocol Tcp
# Then investigate Caddy routing
DO NOT:
- Remove the SSH (22) rule
- Remove the HTTP (80) or HTTPS (443) rules
- Make changes without first listing the current rules
- Remove the SSH (22) rule — you will lose access
- Remove the HTTP (80) or HTTPS (443) rules — Caddy needs them
- Make changes without first saving the current rules snapshot
COMMIT: chore(security): lock down Azure NSG to 22/80/443 only
```
---
## Track A Execution Order
## Track A — Final Verification Checklist
```
A1: Caddy Gateway ──→ A2: Gitea HTTPS ──→ A4: NSG Lockdown
└──→ A3: Dashboards Fix
After all 4 prompts are complete, run this full end-to-end verification:
```bash
echo "=== Track A Final Verification ==="
echo "--- DNS ---"
for d in api.bytelyst.com gitea.bytelyst.com admin.bytelyst.com tracker.bytelyst.com; do
echo -n "$d → "; dig +short $d
done
echo "--- Backend Health (13 services) ---"
for svc in platform extraction mcp peakpulse chronomind jarvisjr nomgap mindlyst lysnrai notelett flowmonk actiontrail localmemgpt; do
echo -n "$svc: "; curl -sf https://api.bytelyst.com/$svc/health | jq -r '.status // "FAIL"'
done
echo "--- Gitea npm registry ---"
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
echo "--- Dashboards ---"
curl -sI https://admin.bytelyst.com | head -1
curl -sI https://tracker.bytelyst.com | head -1
echo "--- Port lockdown ---"
for port in 3001 3003 3300 4003 4005 8025 8080 10000; do
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:$port > /dev/null 2>&1 && echo "FAIL: $port open" || echo "PASS: $port closed"
done
echo "--- Docker containers ---"
docker compose ps --format 'table {{.Name}}\t{{.Status}}' | grep -E "(unhealthy|Exit)" | wc -l
# Expected: 0
```
A3 can run in parallel with A2. A4 runs last after everything is routed through Caddy.
**All checks must pass before Track A is considered complete.**
Once A2 verification passes, signal to Track B that Prompt B4 is unblocked.

View File

@ -2,6 +2,29 @@
> **Agent:** Any Codex agent with repo access (local or cloud)
> **Prompts:** 4 (B1B3 run in parallel, B4 runs last after Track A completes A2)
> **Reference docs:**
>
> - [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) — full Vercel audit + per-app status
> - Individual `ROADMAP_*.md` files — per-app gaps, env vars, and deployment steps
---
## Progress Tracker
| # | Prompt | Repos | Status | Commits | Verified |
| --- | ------------------------ | :---: | :--------------: | :-----: | :------: |
| B1 | Fix `file:` refs | 7 | ⬜ Not started | 0/7 | ⬜ |
| B2 | Fix `output: standalone` | 4 | ⬜ Not started | 0/4 | ⬜ |
| B3 | EffoRise `vercel.json` | 1 | ⬜ Not started | 0/1 | ⬜ |
| B4 | Update `.npmrc` | 12 | ⬜ Blocked on A2 | 0/12 | ⬜ |
**Execution order:**
```
B1: Fix file: refs ──────┐
B2: Fix standalone ──────┼──→ B4: Update .npmrc (blocked until Track A → A2 done)
B3: EffoRise vercel.json ┘
```
---
@ -10,15 +33,28 @@
> **Depends on:** Nothing (packages are already published to Gitea)
> **Blocks:** Nothing
### Per-Repo Checklist
| # | Repo | File | Packages to fix | Edited | Built | Committed | Pushed |
| --- | ------------------------------ | ------------------------ | ----------------- | :----: | :---: | :-------: | :----: |
| 1 | `learning_ai_clock` | `web/package.json` | design-tokens, ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 2 | `learning_ai_jarvis_jr` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 3 | `learning_ai_fastgap` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 4 | `learning_ai_flowmonk` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 5 | `learning_ai_notes` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 6 | `learning_ai_local_memory_gpt` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
| 7 | `learning_ai_local_llms` | `dashboard/package.json` | design-tokens, ui | ⬜ | ⬜ | ⬜ | ⬜ |
### Prompt
```
TASK: Convert all file: references to @bytelyst/* packages into semver ^0.1.0 references across 7 web app repos.
CONTEXT:
- 7 repos have web/package.json files that use file: references to ../../learning_ai_common_plat/packages/*
- These fail on Vercel because the sibling repo doesn't exist
- 7 repos have web/package.json (or dashboard/package.json) files with file: references to ../../learning_ai_common_plat/packages/*
- These fail on Vercel because the sibling repo doesn't exist during build
- The packages are already published to the Gitea npm registry
- Each fix is: change "file:../../learning_ai_common_plat/packages/X" to "^0.1.0"
- After changing, run pnpm install to update the lockfile, then verify pnpm build passes
- Each fix: change "file:../../learning_ai_common_plat/packages/X" to "^0.1.0"
REPOS AND FILES TO FIX:
@ -45,17 +81,35 @@ REPOS AND FILES TO FIX:
- "@bytelyst/design-tokens": "file:..." → "^0.1.0"
- "@bytelyst/ui": "file:..." → "^0.1.0"
FOR EACH REPO:
1. Edit the package.json — replace file: refs with ^0.1.0
2. Run: cd web && pnpm install (or cd dashboard for LLM Lab)
3. Run: pnpm build
4. If build passes, commit: fix(web): convert file: refs to registry semver for Vercel compatibility
5. Push to origin main
FOR EACH REPO (repeat 7 times):
- [ ] 1. Edit the package.json — replace file: refs with ^0.1.0
- [ ] 2. Run: cd web && pnpm install (or cd dashboard for LLM Lab)
- [ ] 3. Verify no file: refs remain: grep -r "file:.*common_plat" package.json
Expected: no output
- [ ] 4. Run: pnpm build
Expected: build succeeds with exit code 0
- [ ] 5. Commit: fix(web): convert file: refs to registry semver for Vercel compatibility
- [ ] 6. Push to origin main
VERIFICATION (after all 7 repos):
# Confirm zero file: refs remain across all repos
for repo in learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_local_memory_gpt learning_ai_local_llms; do
echo -n "$repo: "
grep -rl "file:.*common_plat" $repo/web/package.json $repo/dashboard/package.json 2>/dev/null | wc -l | tr -d ' '
echo " file: refs remaining"
done
# Expected: all show "0 file: refs remaining"
SUCCESS CRITERIA:
- All 7 repos have zero file: references in their web/dashboard package.json
- All 7 builds pass (pnpm build exits 0)
- All 7 commits pushed to origin main
- No other dependencies or source code modified
DO NOT:
- Change any other dependencies
- Modify any source code
- Skip the build verification step
- Skip the build verification step for any repo
```
---
@ -65,16 +119,28 @@ DO NOT:
> **Depends on:** Nothing
> **Blocks:** Nothing
### Per-Repo Checklist
| # | Repo | File | Pattern | Edited | Docker Build | Vercel Build | Committed | Pushed |
| --- | ------------------------------ | -------------------- | --------------------- | :----: | :----------: | :----------: | :-------: | :----: |
| 1 | `learning_ai_fastgap` | `web/next.config.ts` | output + tracing root | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
| 2 | `learning_ai_notes` | `web/next.config.ts` | output + tracing root | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
| 3 | `learning_ai_trails` | `web/next.config.ts` | output only | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
| 4 | `learning_ai_local_memory_gpt` | `web/next.config.ts` | output only | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
> **Skip:** `learning_ai_local_llms/dashboard/next.config.ts` — LLM Lab not viable on Vercel (needs local Ollama)
### Prompt
```
TASK: Make the Next.js output mode Vercel-aware in 4 repos that currently hardcode output: 'standalone'.
CONTEXT:
- Vercel manages its own output mode — hardcoded standalone breaks Vercel builds
- The fix is: wrap standalone output in a process.env.VERCEL conditional
- The fix: wrap standalone output in a process.env.VERCEL conditional
- Docker builds (which don't set VERCEL env var) will still get standalone mode
- 4 repos need this fix
REPOS AND FILES:
REPOS AND EXACT CHANGES:
1. learning_ai_fastgap/web/next.config.ts
Change:
@ -87,7 +153,7 @@ REPOS AND FILES:
}),
2. learning_ai_notes/web/next.config.ts
Same pattern as above.
Same pattern as #1 (output + outputFileTracingRoot).
3. learning_ai_trails/web/next.config.ts
Change:
@ -96,16 +162,36 @@ REPOS AND FILES:
...(process.env.VERCEL ? {} : { output: 'standalone' }),
4. learning_ai_local_memory_gpt/web/next.config.ts
Same pattern as #3.
Same pattern as #3 (output only).
NOTE: learning_ai_local_llms/dashboard/next.config.ts also has this but LLM Lab is NOT viable on Vercel (needs local Ollama), so skip it.
FOR EACH REPO (repeat 4 times):
- [ ] 1. Edit next.config.ts with the VERCEL conditional
- [ ] 2. Verify Docker build still works (standalone activates without VERCEL env):
cd web && pnpm build
# Check output: look for "Creating an optimized production build" + ".next/standalone/" dir
ls -d .next/standalone/ && echo "PASS: standalone created" || echo "FAIL"
- [ ] 3. Verify Vercel-mode build works (standalone skipped with VERCEL env):
cd web && VERCEL=1 pnpm build
# Check output: .next/standalone/ should NOT exist
ls -d .next/standalone/ 2>/dev/null && echo "FAIL: standalone still created" || echo "PASS: no standalone"
- [ ] 4. Commit: fix(web): make output mode Vercel-aware — conditional standalone
- [ ] 5. Push to origin main
FOR EACH REPO:
1. Edit next.config.ts with the conditional
2. Verify Docker build still works: pnpm build (standalone should still activate without VERCEL env)
3. Verify VERCEL=1 pnpm build also works (output should be default, not standalone)
4. Commit: fix(web): make output mode Vercel-aware — conditional standalone
5. Push to origin main
VERIFICATION (after all 4 repos):
for repo in learning_ai_fastgap learning_ai_notes learning_ai_trails learning_ai_local_memory_gpt; do
echo "=== $repo ==="
cd $repo/web
grep -c "process.env.VERCEL" next.config.ts
# Expected: 1 (the conditional)
cd ../..
done
SUCCESS CRITERIA:
- All 4 next.config.ts files contain process.env.VERCEL conditional
- Docker build (no VERCEL env) produces .next/standalone/
- Vercel build (VERCEL=1) does NOT produce .next/standalone/
- All 4 commits pushed to origin main
- No other config options changed
DO NOT:
- Change any other config options in next.config.ts
@ -120,33 +206,63 @@ DO NOT:
> **Depends on:** Nothing
> **Blocks:** Nothing
### Checklist
| Step | Description | Done |
| ---- | ------------------------- | :--: |
| 1 | Create `vercel.json` | ⬜ |
| 2 | Verify local build | ⬜ |
| 3 | Verify SPA routing config | ⬜ |
| 4 | Commit + push | ⬜ |
### Prompt
```
TASK: Create a vercel.json file for the EffoRise Vite SPA to handle client-side routing and API proxy configuration.
CONTEXT:
- EffoRise is a Vite + React 19 SPA (not Next.js) in the learning_ai_efforise repo
- The Vite config is at the repo root (vite.config.ts)
- EffoRise is a Vite + React 19 SPA (NOT Next.js) in the learning_ai_efforise repo
- The Vite config is at the repo root (client/ directory has the SPA)
- Build output goes to dist/public/ (custom, not default dist/)
- Uses wouter for client-side routing — all routes must serve index.html
- The backend API is at https://api.bytelyst.com/efforise
- Currently uses a dev proxy /api → localhost:4020
DELIVERABLES:
1. Create vercel.json at the repo root with:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"buildCommand": "pnpm build",
"outputDirectory": "dist/public",
"rewrites": [
{ "source": "/api/(.*)", "destination": "https://api.bytelyst.com/efforise/$1" },
{ "source": "/(.*)", "destination": "/index.html" }
]
}
TASK LIST:
- [ ] 1. Create client/vercel.json with:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"buildCommand": "pnpm build",
"outputDirectory": "dist/public",
"rewrites": [
{ "source": "/api/(.*)", "destination": "https://api.bytelyst.com/efforise/$1" },
{ "source": "/(.*)", "destination": "/index.html" }
]
}
- [ ] 2. Verify local build: cd client && pnpm build
Expected: exit code 0, dist/public/index.html exists
- [ ] 3. Verify vercel.json is valid JSON: cat client/vercel.json | jq .
Expected: formatted JSON output, no parse errors
- [ ] 4. Commit: feat(web): add vercel.json for Vite SPA deployment
- [ ] 5. Push to origin main
2. Verify pnpm build still works locally
3. Commit: feat(web): add vercel.json for Vite SPA deployment
4. Push to origin main
VERIFICATION:
# Build works
cd client && pnpm build && echo "BUILD: PASS" || echo "BUILD: FAIL"
# Output directory exists
ls client/dist/public/index.html && echo "OUTPUT: PASS" || echo "OUTPUT: FAIL"
# vercel.json valid
jq '.rewrites | length' client/vercel.json
# Expected: 2
SUCCESS CRITERIA:
- client/vercel.json exists with correct framework, build command, output directory, and rewrites
- Local build still produces dist/public/index.html
- vercel.json is valid JSON
- Commit pushed to origin main
DO NOT:
- Modify vite.config.ts
@ -158,12 +274,44 @@ DO NOT:
## B4: Update .npmrc Across All Product Repos
> **Depends on:** Track A Prompt A2 (gitea.bytelyst.com must be live and accessible)
> **Blocks:** Vercel deployment
> **Depends on:** Track A → A2 complete (`gitea.bytelyst.com` live + verified)
> **Blocks:** All Vercel deployments (this is the final gate)
### Pre-flight Check (must pass before starting)
```bash
# Verify gitea.bytelyst.com is live and serving packages
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
# Expected: "@bytelyst/errors"
# If this fails, DO NOT proceed — Track A → A2 is not complete
```
### Per-Repo Checklist
| # | Repo | .npmrc locations | Updated | Install OK | Committed | Pushed |
| --- | ----------------------------------- | -------------------------- | :-----: | :--------: | :-------: | :----: |
| 1 | `learning_voice_ai_agent` | root, user-dashboard-web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 2 | `learning_ai_clock` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 3 | `learning_ai_jarvis_jr` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 4 | `learning_ai_fastgap` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 5 | `learning_ai_flowmonk` | root, web/, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 6 | `learning_ai_notes` | root, web/, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 7 | `learning_ai_trails` | root, web/, sdk/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 8 | `learning_multimodal_memory_agents` | root, mindlyst-native/web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 9 | `learning_ai_local_memory_gpt` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 10 | `learning_ai_efforise` | root, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 11 | `learning_ai_local_llms` | dashboard/ | ⬜ | ⬜ | ⬜ | ⬜ |
| 12 | `learning_ai_peakpulse` | root | ⬜ | ⬜ | ⬜ | ⬜ |
### Prompt
```
TASK: Update .npmrc files in all product repos to point to the public Gitea npm registry at gitea.bytelyst.com.
PRE-FLIGHT (must pass before starting):
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
# Must return "@bytelyst/errors" — if not, STOP and report that Track A → A2 is not done
CONTEXT:
- All product repos currently have .npmrc pointing to http://localhost:3300 (local Gitea)
- Gitea is now accessible at https://gitea.bytelyst.com via Caddy reverse proxy
@ -171,67 +319,126 @@ CONTEXT:
- Auth token is passed via GITEA_NPM_TOKEN env var
- This change enables Vercel builds to install @bytelyst/* packages
NEW .npmrc CONTENT (same for all repos):
@bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
TARGET .npmrc CONTENT (same for all repos):
@bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
REPOS TO UPDATE (12 total):
REPOS TO UPDATE (12 total — see checklist above for .npmrc locations):
1. learning_voice_ai_agent (user-dashboard-web, backend)
2. learning_ai_clock (web, backend)
3. learning_ai_jarvis_jr (web, backend)
4. learning_ai_fastgap (web, backend)
5. learning_ai_flowmonk (web, backend, mobile)
6. learning_ai_notes (web, backend, mobile)
7. learning_ai_trails (web, backend, sdk)
8. learning_multimodal_memory_agents (mindlyst-native/web, backend)
9. learning_ai_local_memory_gpt (web, backend)
10. learning_ai_efforise (root, backend, mobile)
11. learning_ai_local_llms (dashboard)
12. learning_ai_peakpulse (backend)
1. learning_voice_ai_agent (root .npmrc + user-dashboard-web/.npmrc)
2. learning_ai_clock (root + web/)
3. learning_ai_jarvis_jr (root + web/)
4. learning_ai_fastgap (root + web/)
5. learning_ai_flowmonk (root + web/ + mobile/)
6. learning_ai_notes (root + web/ + mobile/)
7. learning_ai_trails (root + web/ + sdk/)
8. learning_multimodal_memory_agents (root + mindlyst-native/web/)
9. learning_ai_local_memory_gpt (root + web/)
10. learning_ai_efforise (root + mobile/)
11. learning_ai_local_llms (dashboard/)
12. learning_ai_peakpulse (root)
FOR EACH REPO:
1. Find all .npmrc files (there may be multiple — root, web/, backend/, mobile/)
2. Update the @bytelyst registry line to use gitea.bytelyst.com
3. Add the auth token line if not present
4. Run: GITEA_NPM_TOKEN=<token> pnpm install (verify packages resolve)
5. Commit: chore: update .npmrc to public Gitea registry at gitea.bytelyst.com
6. Push to origin main
FOR EACH REPO (repeat 12 times):
- [ ] 1. Find all .npmrc files: find . -name ".npmrc" -not -path "*/node_modules/*"
- [ ] 2. In each .npmrc, replace the @bytelyst registry line:
OLD: @bytelyst:registry=http://localhost:3300/api/packages/ByteLyst/npm/
NEW: @bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
- [ ] 3. Ensure the auth token line exists:
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
- [ ] 4. Verify no localhost:3300 references remain:
grep -r "localhost:3300" . --include=".npmrc"
Expected: no output
- [ ] 5. Verify packages resolve:
GITEA_NPM_TOKEN=<token> pnpm install
Expected: exit code 0, all @bytelyst/* packages resolved
- [ ] 6. Commit: chore: update .npmrc to public Gitea registry at gitea.bytelyst.com
- [ ] 7. Push to origin main
VERIFICATION:
After updating all repos, verify one end-to-end:
VERIFICATION (after all 12 repos — run from parent directory containing all repos):
echo "=== .npmrc Migration Verification ==="
# Check no localhost:3300 remains anywhere
for repo in learning_voice_ai_agent learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_trails learning_multimodal_memory_agents learning_ai_local_memory_gpt learning_ai_efforise learning_ai_local_llms learning_ai_peakpulse; do
count=$(grep -rl "localhost:3300" $repo/ --include=".npmrc" 2>/dev/null | wc -l | tr -d ' ')
echo "$repo: $count old refs remaining"
done
# Expected: all show "0 old refs remaining"
# End-to-end build test on one repo
cd learning_ai_clock/web
GITEA_NPM_TOKEN=<token> pnpm install
pnpm build
GITEA_NPM_TOKEN=<token> pnpm install && pnpm build && echo "E2E: PASS" || echo "E2E: FAIL"
# Expected: "E2E: PASS"
SUCCESS CRITERIA:
- All 12 repos have zero localhost:3300 references in .npmrc files
- All 12 repos can resolve @bytelyst/* packages via gitea.bytelyst.com
- At least one repo verified with full pnpm install + pnpm build
- All 12 commits pushed to origin main
- No package versions changed, no auth tokens hardcoded
DO NOT:
- Change any package versions
- Remove any other registry configurations (e.g., npmjs.org for non-@bytelyst packages)
- Hardcode the auth token — always use ${GITEA_NPM_TOKEN}
- Proceed if the pre-flight check fails
```
---
## Track B Execution Order
## Track B — Final Verification Checklist
```
B1: Fix file: refs ──────┐
B2: Fix standalone ──────┼──→ B4: Update .npmrc (waits for Track A → A2)
B3: EffoRise vercel.json ┘
After all 4 prompts are complete, verify the full picture:
```bash
echo "=== Track B Final Verification ==="
echo "--- B1: file: refs (7 repos) ---"
for repo in learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_local_memory_gpt learning_ai_local_llms; do
count=$(grep -rl "file:.*common_plat" $repo/web/package.json $repo/dashboard/package.json 2>/dev/null | wc -l | tr -d ' ')
echo "$repo: $count file: refs"
done
# Expected: all 0
echo "--- B2: standalone conditional (4 repos) ---"
for repo in learning_ai_fastgap learning_ai_notes learning_ai_trails learning_ai_local_memory_gpt; do
count=$(grep -c "process.env.VERCEL" $repo/web/next.config.ts 2>/dev/null)
echo "$repo: $count VERCEL conditionals"
done
# Expected: all 1
echo "--- B3: EffoRise vercel.json ---"
jq '.rewrites | length' learning_ai_efforise/client/vercel.json 2>/dev/null
# Expected: 2
echo "--- B4: .npmrc migration (12 repos) ---"
for repo in learning_voice_ai_agent learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_trails learning_multimodal_memory_agents learning_ai_local_memory_gpt learning_ai_efforise learning_ai_local_llms learning_ai_peakpulse; do
count=$(grep -rl "localhost:3300" $repo/ --include=".npmrc" 2>/dev/null | wc -l | tr -d ' ')
echo "$repo: $count old .npmrc refs"
done
# Expected: all 0
```
B1, B2, B3 can all run in parallel immediately. B4 must wait until `gitea.bytelyst.com` is live (Track A, Prompt A2).
**All checks must pass before Track B is considered complete.**
---
## After Both Tracks Complete
## After Both Tracks Complete — Vercel Project Setup (Manual)
```
Manual steps (Vercel UI):
→ Create Vercel projects for each app
→ Set GITEA_NPM_TOKEN + other env vars per project
→ Trigger first deploys and verify
```
Once Track A and Track B are both verified, the remaining work is manual in the Vercel UI:
See [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) for the full app list and per-app environment variables.
See individual `ROADMAP_*.md` files for per-app Vercel project setup details.
| # | App | Vercel Root Dir | Framework | Key Env Vars | Roadmap |
| --- | ----------------- | ------------------------ | --------- | ------------------------------------------------------ | ---------------------------------------------------------- |
| 1 | Admin Dashboard | `dashboards/admin-web` | Next.js | `COSMOS_ENDPOINT`, `COSMOS_KEY`, `JWT_SECRET` | [ROADMAP_ADMIN_WEB.md](./ROADMAP_ADMIN_WEB.md) |
| 2 | Tracker Dashboard | `dashboards/tracker-web` | Next.js | `JWT_SECRET`, `PLATFORM_SERVICE_URL` | [ROADMAP_TRACKER_WEB.md](./ROADMAP_TRACKER_WEB.md) |
| 3 | User Dashboard | `user-dashboard-web` | Next.js | `PLATFORM_SERVICE_URL`, `ACTIONTRAIL_SERVICE_URL` | [ROADMAP_USER_DASHBOARD.md](./ROADMAP_USER_DASHBOARD.md) |
| 4 | ChronoMind Web | `web` | Next.js | `GITEA_NPM_TOKEN` | [ROADMAP_CHRONOMIND_WEB.md](./ROADMAP_CHRONOMIND_WEB.md) |
| 5 | JarvisJr Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_PLATFORM_URL` | [ROADMAP_JARVISJR_WEB.md](./ROADMAP_JARVISJR_WEB.md) |
| 6 | NomGap Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_NOMGAP_WEB.md](./ROADMAP_NOMGAP_WEB.md) |
| 7 | FlowMonk Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_FLOWMONK_WEB.md](./ROADMAP_FLOWMONK_WEB.md) |
| 8 | NoteLett Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_NOTELETT_WEB.md](./ROADMAP_NOTELETT_WEB.md) |
| 9 | ActionTrail Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_ACTIONTRAIL_WEB.md](./ROADMAP_ACTIONTRAIL_WEB.md) |
| 10 | MindLyst Web | `mindlyst-native/web` | Next.js | `GITEA_NPM_TOKEN`, `COSMOS_ENDPOINT`, `OPENAI_API_KEY` | [ROADMAP_MINDLYST_WEB.md](./ROADMAP_MINDLYST_WEB.md) |
| 11 | LocalMemGPT Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_LOCALMEMGPT_WEB.md](./ROADMAP_LOCALMEMGPT_WEB.md) |
| 12 | EffoRise Client | `client` | Vite | `GITEA_NPM_TOKEN`, `VITE_BACKEND_URL` | [ROADMAP_EFFORISE.md](./ROADMAP_EFFORISE.md) |
**Every Vercel project needs `GITEA_NPM_TOKEN` set.** See individual roadmap files for the complete env var list per app.