Unify on vx serve: drop CF cloud + otel-bridge package, SPA over HTTP#143
Merged
Conversation
One stack: vx serve runs locally OR in Docker for hosted use; no separate CF Workers project. The hosted SPA connects to either a local server (file://-equivalent local cloud) or a remote one — same HTTP surface either way. OpenTelemetry emit moves into core as src/orchestrator/otel-emit.ts — no bridge package, no custom wire format. Users still opt in via OTEL_EXPORTER_OTLP_ENDPOINT + installing the three @opentelemetry/* peer deps; missing deps silently skip. New src/orchestrator/insights-queries.ts: pure SQL over a bun:sqlite Database (listRuns, getRun, getCacheStats, getHistory, explainCacheKey, whyDidThisRerun). Backs the upcoming vx serve /v1/* routes. - delete apps/cloud/ (entire CF Workers project) - delete packages/otel-bridge/ - drop "packages/*" from root workspaces - inline OTel emit into core (attachOtelEmit) - new insights-queries module + 10 tests
The hosted SPA needs to read cache.db via HTTP — not direct ATTACH or DuckDB-WASM tricks. vx serve now opens the workspace cache once and exposes: GET /v1/runs?project=&task=&runId=&limit= GET /v1/invocations?limit= GET /v1/runs/:runId GET /v1/cache/stats GET /v1/history?project=&task=&limit= GET /v1/explain/:taskId GET /v1/why/:runId/:taskId GET /v1/events (SSE alias of /events) Every response carries `Access-Control-Allow-Origin: *` and OPTIONS preflights answer 204 — the hosted SPA must be able to reach a localhost vx serve from a foreign origin. The surface is read-only + the WS run-submission already authenticated by being on the same machine, so wide-open CORS is safe. /version now also reports the workspace root. 4 new tests covering the API, 404 behavior, CORS preflight, and the extended /version payload.
The insights SPA is now a thin client over the unified vx serve API: - delete apps/insights/src/duckdb.ts (no more 30MB WASM payload, no more ATTACH/registerFileBuffer dance) - rewrite api.ts as a typed HTTP client over /v1/* with a connection store (localStorage-persisted origin, defaults from VITE_DEFAULT_ORIGIN at dev time) - Shell gains a connection picker (URL input + status dot, footer shows the connected workspace + vx version) - Overview now reads /v1/invocations + /v1/cache/stats; RunDetail uses /v1/runs/:id; Flamegraph adapts to the camelCase shape - listRuns SQL now returns wallclockStartNs/EndNs as decimal strings so flamegraphs work over HTTP vx insights drops the static cache.db server entirely: it boots vx serve (same backend everywhere) and the Vite dev server with VITE_DEFAULT_ORIGIN pointing at the server's origin. One stack. Drop @duckdb/duckdb-wasm dep + the obsolete insights-static test.
- delete guides/vx-cloud.md (CF deployment); replace with
guides/self-hosting.md (Docker compose + Caddy auth/TLS recipe +
the browser-localhost gotcha documented)
- rewrite guides/otel-bridge.md to "OpenTelemetry — native"; no
more @vzn/vx-otel-bridge — three optional @opentelemetry/* peers
- rewrite guides/insights.md around the connection picker UX +
/v1/* HTTP surface
- mark docs/design/vx-cloud-2026-06.md as superseded with a header
note pointing at the unification
- update sidebar (drop vx-cloud, add self-hosting)
- update landing-page card ("Cloudflare-template" → "Self-hostable,
Docker-ready")
- update introduction + wire-protocol stray references
- update README: vx insights now talks HTTP, OTel is native, self-
hosted cloud row replaces CF-template row
- append unification step to the 2026-06 implementation log
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Owner directive (2026-06-21): "vx cloud is exactly the same as vx serve. We don't need a separate stack for it. It can run in Docker just fine. Cf is no longer a requirement. Simplify and unify architecture where possible only what we really need. Also instead of Otel bridge we could natively talk in that. No custom format and standard."
This PR collapses the platform layer onto one backend (
vx serve) and one OTel path (native, no bridge package).What changed
One backend. Delete
apps/cloud/(the entire CF Workers project — wrangler.toml, R2/D1/DO/Queue/KV bindings, HMAC wrapper, queue→D1 consumer).vx serveis the cloud — same Bun binary, samebun:sqlitecache, same JSON shape — and it runs in Docker for hosted use.OTel inline. Delete
packages/otel-bridge/. OTel emit moves into core assrc/orchestrator/otel-emit.ts, opting in viaOTEL_EXPORTER_OTLP_ENDPOINT+ three optional@opentelemetry/*peer deps. Missing peers / missing env var = silent skip; core's 19-dep tree stays untouched.New
/v1/*HTTP surface onvx serve.GET /v1/runs,/v1/invocations,/v1/runs/:idGET /v1/cache/stats,/v1/historyGET /v1/explain/:taskId,/v1/why/:runId/:taskIdGET /v1/events(SSE alias of/events)Access-Control-Allow-Origin: *+ 204 OPTIONS preflight (hosted SPA must reach localhost from a foreign origin)src/orchestrator/insights-queries.ts: pure SQL overbun:sqlitebacking all of the aboveSPA rewritten as a thin HTTP client.
apps/insights/drops DuckDB-WASM (no more 30 MB payload, no more ATTACH/registerFileBuffer dance). Newapi.tsis typed HTTP over/v1/*.Shellgains a connection picker (URL chip + status dot, localStorage-persisted, defaults fromVITE_DEFAULT_ORIGINat dev time). Same UI for local OR hosted; pick your backend at runtime.vx insightssimplified. Bootvx serve+ the Vite dev server, pass the server's origin through asVITE_DEFAULT_ORIGIN. Static cache.db server gone.Docs
guides/vx-cloud.md→ REPLACE withguides/self-hosting.md(Docker compose + Caddy auth/TLS recipe + browser-localhost Secure Context exception)guides/otel-bridge.mdas "OpenTelemetry — native"guides/insights.mdaround the connection picker UX +/v1/*surfacedocs/design/vx-cloud-2026-06.mdmarked superseded with a header notedocs/progress/implementation-log-2026-06.mdTest plan
bun src/bin.ts run ci— full gate green/versionadvertises workspace root + RPC capabilitiesNet
−1646/+896LOC across 25 files (delete cloud + bridge, inline OTel, new insights-queries)+239/−19(serve/v1/*+ CORS + tests)−603/+422across 13 files (SPA refactor)One stack everywhere; the SPA is a thin client;
vx serveis the only backend.Generated by Claude Code