A local playground for experimenting with a chat UI + backend + Copilot integration. The Docker Compose stack works locally (frontend, backend, and copilot services), and the Copilot service supports both the Copilot SDK (default) and the Copilot CLI (fallback).
This repo is a pnpm workspace with separate packages under src/.
Frontend ran a prompt against the Copilot service using the SDK mode.
YouTube Demo Video: YouTube Demo Video Demo Video downscaled here: Demo Video in Repo
src/frontend— Vite + React + shadcn/ui UIsrc/backend— Node.js API (streaming bridge; scaffold)src/copilot— Copilot SDK / Copilot CLI wrapper service (uses SDK by default)src/shared— shared types/utilities (LogEvent, EventBus, NDJSON helper)
- Backend routing stays thin in
src/backend/src/app.ts; services live insrc/backend/src/services/*. - ChatPlayground UI is split into a container (
src/frontend/src/components/chat-playground.tsx) and presentational components (src/frontend/src/components/chat-playground/*). - RedVsBlue engine core + entities live under
src/frontend/src/redvsblue/engine/*, with higher-level orchestration insrc/frontend/src/redvsblue/*.
There’s an “eastergg” in the playground: RedVsBlue, a mini game orchestrated and mediated by Copilot. It lives in the frontend and uses the backend’s RedVsBlue endpoints for match lifecycle, snapshots, and AI commentary.
- Coverage thresholds are enforced per package (backend/frontend/copilot) via
vitestcoverage settings. - Router thinness is enforced by a simple line-count guard:
pnpm ci:guardrails(seescripts/ci/check-router-thin.mjs).
-
Enable pnpm via Corepack (recommended)
corepack enable
-
Install deps
pnpm install
-
Run everything in dev
pnpm dev
pnpm dev:frontendpnpm dev:backendpnpm dev:copilot
The copilot service supports two modes:
- SDK Mode (default): Uses
@github/copilot-sdkfor structured streaming with full event support - CLI Mode: Direct CLI spawning for simpler use cases
Set USE_COPILOT_SDK=false in your environment to use CLI mode.
For Docker/Compose usage with encrypted .env files, see the repo guidance in docs/library/dotenvx/README.md. It documents safe-by-default key handling, recommended secret injection patterns, and install options.
Tip: Commit a .env.example or .env.sample (without secrets) that documents required environment variables and example shapes. Do not commit actual .env files or any real secrets — use .env.example solely as a reference for developers.
For running containers (including Milestone E workspace mounts) prefer a secrets-first approach:
- Keep
.env.keysout of source control (it containsDOTENV_PRIVATE_KEY_*). The repo already ignores it via.gitignoreand keeps it out of the Docker build context via.dockerignore. - Inject secrets at runtime (Docker secrets / orchestrator secrets / mounted secret file). Do not bake secrets into images.
- Avoid passing secrets on the CLI (e.g.,
docker run -e ...orDOTENV_PRIVATE_KEY_*=... docker compose up) except as a small dev-only convenience.
This repo’s src/copilot/entrypoint.sh supports reading secrets from /run/secrets/ and exporting them into env at container start:
DOTENV_PRIVATE_KEY_*(fordotenvxruntime decryption)GH_TOKEN/GITHUB_TOKEN(Copilot auth)
See docs/milestone-e-workspace-mount.md for workspace-mount specific guidance and warnings. For an end-to-end quick start and troubleshooting steps, see the Docker setup guide: docs/docker-setup-guide.md.
Docker build tip: When installing dependencies inside Docker, prefer deterministic installs by using a frozen lockfile. Example in a Dockerfile:
RUN corepack enable && pnpm install --frozen-lockfile --prodKeeping pnpm-lock.yaml available to Docker builds helps ensure reproducible images (do not add it to .dockerignore if you expect it to be used during image builds).
Quick verification — Docker & Copilot ✅
- Build & run the full stack:
docker compose up --build- Or run detached:
docker compose up -d --build
- Verify running services:
docker compose psdocker compose logs -f copilot
- Check Copilot health and mode (works for SDK and CLI):
curl -s http://localhost:3210/health | jq .(inspectmode,tokenConfigured,binaryAvailable)
- Quick API test (requires
GH_TOKENconfigured):curl -X POST http://localhost:3210/chat -H 'Content-Type: application/json' -d '{"prompt":"What is GitHub Copilot?"}'
Note: The Copilot service uses the SDK by default. To force the CLI fallback set USE_COPILOT_SDK=false (env or Compose override).
- The Compose stack mounts the host
./workspaceinto thecopilotcontainer as a read-only bind mount by default (e.g../workspace:/workspace:ro) to avoid accidental modification of your working tree or host secrets. - If you need write access for builds or tests, prefer a named volume or a dedicated writable path instead of making the entire repo writable.
- To enable writable access in a dev-only override, create a
docker-compose.override.ymland adjust thevolumesentry forcopilot, for example:
services:
copilot:
volumes:
- ./workspace:/workspace:rw- Quick verification inside a running container:
# Should print "read-only mount" when mount is read-only
docker compose exec copilot sh -c 'touch /workspace/should_fail 2>/dev/null || echo "read-only mount"'
# Inspect mount options on Linux
docker compose exec copilot sh -c 'grep /workspace /proc/mounts || mount | grep /workspace'See docs/milestone-e-workspace-mount.md for additional checks and safety guidance.
-
Enable pnpm via Corepack (recommended)
corepack enable
-
Install deps
pnpm install
-
Run everything in dev
pnpm dev
pnpm dev:frontendpnpm dev:backendpnpm dev:copilot
