The dashboard needs OPS_BASE_URL at build time to connect to the local
harness. Without this, the dashboard container builds with no API URL
and cannot display probe results locally.
The dashboard Dockerfile uses COPY paths prefixed with `showcase/...`
which expect the repo root as build context. The compose entry was
using `build: ./shell-dashboard` which set context to
showcase/shell-dashboard/, causing COPY failures in worktrees.
Split into explicit context (../ relative to compose file = repo root)
and dockerfile path so COPY paths resolve correctly.
TanStack's chat() engine runs a multi-turn agent loop: after the model
returns tool calls, it tries to execute them via processToolCalls().
Frontend-only tools (like render_pie_chart) are unknown to TanStack, so
executeToolCalls() treats them as errors and buildToolResultChunks()
re-emits TOOL_CALL_END without a preceding TOOL_CALL_START. The ag-ui
verify middleware rejects this duplicate.
Fix: track a runFinished flag in convertTanStackStream and discard all
events after the first RUN_FINISHED, which marks the boundary between
the streaming pass and TanStack's internal tool execution loop.
Also adds built-in-agent to docker-compose.local.yml and local-ports.json.
The host bind mount `src:/app/src` in docker-compose.local.yml overlays
the container's /app/src directory, clobbering src/agent/node_modules
that was installed during the Docker build. This causes `node --import tsx`
to fail with ERR_MODULE_NOT_FOUND at container startup.
Add an anonymous volume for /app/src/agent/node_modules so Docker
preserves the image's copy even when the parent directory is bind-mounted.
Production showcase-aimock was running a week-old image because fixture
file changes in showcase/aimock/ did not trigger a CI rebuild. This adds
showcase-aimock to the Build & Deploy workflow matrix so it auto-deploys
on merge, creates a thin Dockerfile that bakes fixture files into the
image, documents the local-vs-production parity requirement in
docker-compose.local.yml, and adds an aimock fixture deployment section
to the RUNBOOK.
- Mount D5/smoke/feature-parity fixtures into aimock via volumes
- Add --host 0.0.0.0 so other containers can reach aimock
- Switch healthcheck from curl to node fetch (aimock image has no curl)
- Delete dev-local.sh (redundant with bin/showcase CLI)
Add x-integration-defaults YAML anchor to DRY 17 service definitions.
Switch aimock from local build to ghcr.io/copilotkit/aimock:latest.
Add healthchecks to all 20 services (internal ports, not host-mapped).
Add pocketbase and dashboard infra services with proper depends_on
conditions. Add profiles to every service so compose enumeration works.
Wires up a single-command path to run the full integration smoke suite
against a local Docker stack instead of Railway. Useful when Railway is
degraded (OOM, rate limits) or when testing changes that haven't been
deployed yet.
Additions:
- showcase/docker-compose.local.yml: add `aimock` as 18th service so
integration containers can reach http://aimock:4010 on the compose
network, mirroring the Railway setup where they call showcase-aimock.
- showcase/tests/e2e/integration-smoke.spec.ts: `LOCAL_PORTS=1` env
rewrites each integration's Railway URL to http://localhost:<port>
via showcase/shared/local-ports.json. Starters are skipped under this
flag because they aren't in local-ports.json.
- showcase/scripts/smoke-local.sh: orchestrates build → up → wait → run
Playwright → tear down. Supports --level=L1/L2/L3/L4, --keep, --no-build.
- showcase/tests/package.json: `pnpm smoke:local[:L1|:keep|:nobuild]`
scripts delegate to the helper.
- showcase/.env.example: document optional OPENAI_BASE_URL +
ANTHROPIC_BASE_URL (route through local aimock) and package-specific
GitHubToken + GOOGLE_API_KEY (ms-agent-dotnet, google-adk).
Verified locally: `pnpm smoke:local:L1` → 17/17 L1 green against the
local stack.
Adds a single command to spin up the exact image Railway deploys,
for any of the 17 showcase packages, with a single shared .env:
./showcase/scripts/dev-local.sh up [<slug> ...] # all if empty
./showcase/scripts/dev-local.sh down|build|logs|ps|ports
Pieces:
- `docker-compose.local.yml` with a service per package. Ports come
from `shared/local-ports.json` (langgraph-python -> 3100, ...).
- `.env.example` as a commit-safe template. Real `.env` is gitignored
and fed to every container via `env_file`, so keys (OPENAI_API_KEY,
etc.) live in one place.
- `dev-local.sh` wraps `docker compose` and handles the
`shared_python/` / `shared_typescript/` staging step that CI does
before `docker build` (see showcase_deploy.yml).
- Staged `shared_*` dirs added to .gitignore.
Shell wiring:
- `shell/next.config.ts` reads `shared/local-ports.json` when
`SHOWCASE_LOCAL=1` is set and injects it as a public env.
- `/integrations/[slug]/[demo]/preview` uses that map to iframe
`http://localhost:<port>` instead of `integration.backend_url`.
Per-slug; any slug not running locally falls back to Railway.
Unset SHOWCASE_LOCAL -> prod behavior, unchanged.
Full workflow + prerequisites (Colima / Docker Desktop) documented in
showcase/README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>