The standalone threads template is retired: the ENT-679 rollout was
reverted from main (#5215/#5216/#5217) and the settled model is base
langgraph-python + Intelligence activation overlay. The Intelligence
CLI (main and published copilotkit@3.0.2) no longer references it.
Also drops its two entries from .github/config-allowlist.txt.
## Summary
The pool-fleet cutover manually created a new staging-only Railway
service `showcase-harness-worker` (HARNESS_ROLE=worker, 2 replicas) and
flipped the existing `harness` service to HARNESS_ROLE=control-plane.
The new service was **not in the SSOT**
(`showcase/scripts/railway-envs.ts`), so `verify-railway-image-refs.ts`
failed the "Showcase: Build & Push" workflow on every push to main:
```
✗ [railway] showcase-harness-worker
reason: Railway service "showcase-harness-worker" is not in the SSOT.
```
Because the `build` job `needs: [verify-image-refs]`, that gate failure
**skipped the harness build** — meaning recent harness fixes (e.g.
#5279's chat-rung probe) never rebuilt to staging. The secondary
`Aggregate build results` ENOENT failure was a downstream consequence of
the skipped build.
This PR adds `showcase-harness-worker` to `SERVICES`, matching the live
Railway service:
- **`ciBuilt: false`** — the worker runs the SAME `showcase-harness`
GHCR image the existing harness build slot produces; there is no
separate worker build slot.
- **`gateIgnore: true` / `gateValidated: false`** — the worker is
staging-only (no prod serviceInstance) and domain-less (it pulls jobs
from the control-plane queue rather than serving HTTP), so it does not
fit the symmetric dual-env / public-domain shape the image-ref gate
validates. `gateIgnore` clears the "untracked Railway service" failure
(any SSOT entry counts as known) **without** triggering a false "missing
from prod" failure (`findMissingServices` only checks `gateValidated:
true` entries).
- **`repoNameOverride` → `showcase-harness`** so the image-ref shape
resolves correctly.
- **probe disabled in both envs** — no externally-reachable health
endpoint.
The existing `harness` (now control-plane) entry is unchanged and
remains correct (it still builds + serves the `showcase-harness` image
on its public domain).
Also regenerates `railway-envs.generated.json` and updates the
SSOT-count / gate-coverage test invariants (27 → 28 services; the worker
is the sole intentional `gateIgnore`/`gateValidated:false` entry).
## Proof
Against live Railway (CLI auth):
- Before: `✗ Railway image-ref drift detected (... 1 untracked Railway
services ...)`
- After: `✓ 54 env-scoped instances verified (1 skipped)` — worker is
the 1 skipped (gateIgnore), 0 untracked.
- `emit-railway-envs-json.ts --check`: up to date.
## Test plan
- [x] `verify-railway-image-refs.ts` passes against live Railway (0
untracked)
- [x] `emit-railway-envs-json.ts --check` passes (generated JSON
regenerated)
- [x] Full `showcase/scripts` vitest suite: 1772 passed (49 files)
- [ ] CI green on "Showcase: Build & Push" after merge (the gate failure
that skipped the harness build is removed)
The pool-fleet cutover manually created the staging-only
`showcase-harness-worker` Railway service (HARNESS_ROLE=worker, 2
replicas) and flipped the existing `harness` service to
HARNESS_ROLE=control-plane. The new service was untracked in the SSOT,
so verify-railway-image-refs.ts failed the "Showcase: Build & Push"
workflow on every push to main (1 untracked Railway service), which
skipped the harness `build` job and blocked harness image rebuilds.
Add the worker to SERVICES as a staging-only, domain-less queue worker:
- ciBuilt:false — it runs the SAME `showcase-harness` image the existing
harness build slot produces; there is no separate worker build.
- gateIgnore:true / gateValidated:false — no prod instance and no public
domain, so it does not fit the symmetric dual-env shape the image-ref
gate validates. gateIgnore clears the "untracked Railway service"
failure (any SSOT entry counts as known) without tripping a false
"missing from prod" failure.
- repoNameOverride → showcase-harness so the image-ref shape resolves.
- probe disabled in both envs (no externally-reachable health endpoint).
Regenerate railway-envs.generated.json and update the SSOT-count and
gate-coverage test invariants (27→28 services; worker is the sole
intentional gateIgnore/gateValidated:false entry).
## Summary
The harness `starter-smoke` **chat** rung 503'd on staging because its
probe is a raw `fetch()` POST that sends only `Content-Type` — it omits
`X-AIMock-Context`. The scoped per-integration "Hello" fixtures in
`showcase/aimock/d4/<integration>/chat.json`
(`{match:{userMessage:"Hello", context:"<ctx>"}}`) only match under
aimock **strict mode** when the request carries
`x-aimock-context:<ctx>`. The local browser e2e passes only because each
integration's `playwright.config.ts` injects `extraHTTPHeaders:{
"X-AIMock-Context": "<ctx>" }`, forwarded by the integration's
`HeaderForwardingMiddleware` to aimock.
**Fix:** send `X-AIMock-Context: <columnSlug>` on the chat POST **only**
(the GET health/agent/interaction rungs hit the runtime `/info` route +
app shell, not aimock — matching what the browser does). The driver
already resolves `columnSlug` via `starterToColumnSlug(...)` before the
chat rung runs, and that column slug is exactly the fixture/playwright
context value, so the slug↔context skews resolve for free.
### Definitive starter → X-AIMock-Context map
The context token equals the **dashboard column slug** for every mapped
starter. Verified two ways: each integration's
`showcase/integrations/<col>/playwright.config.ts`
`extraHTTPHeaders["X-AIMock-Context"]`, and the
`showcase/aimock/d4/<col>/chat.json` `match.context` field — both equal
the column slug.
| probe starter slug | X-AIMock-Context (= column slug) | skew? |
|---|---|---|
| `langgraph-js` | `langgraph-typescript` | yes |
| `adk` | `google-adk` | yes |
| `strands-python` | `strands` | yes |
| `ms-agent-framework-dotnet` | `ms-agent-dotnet` | yes |
| `ms-agent-framework-python` | `ms-agent-python` | yes |
| `crewai-crews` | `crewai-crews` | no |
| `langgraph-fastapi` | `langgraph-fastapi` | no |
| `langgraph-python` | `langgraph-python` | no |
| `agno` | `agno` | no |
| `llamaindex` | `llamaindex` | no |
| `mastra` | `mastra` | no |
| `pydantic-ai` | `pydantic-ai` | no |
No genuinely-absent contexts: all 12 mapped starters have a `{Hello,
<col>}` fixture, and an **unmapped** starter returns a red aggregate
*before* any chat probe fires (so `aimockContext` is always populated
when the chat POST runs).
## Red → Green proof
**Unit (harness):** 5 new tests assert the chat POST carries
`x-aimock-context = column slug` (direct + skew maps), only on the chat
rung, alongside `Content-Type`/`Accept`. RED first (5 failed against
unfixed source: header `undefined`), GREEN after the fix.
**Live staging aimock**
(`https://aimock-staging.up.railway.app/v1/chat/completions`, `Hello`
turn):
| starter | RED (no header) | GREEN (`X-AIMock-Context: <col>`) |
|---|---|---|
| `langgraph-js` → `langgraph-typescript` | 503 `no_fixture_match` | 200
|
| `adk` → `google-adk` | 503 `no_fixture_match` | 200 |
| `strands-python` → `strands` | 503 `no_fixture_match` | 200 |
| `langgraph-python` | 503 `no_fixture_match` | 200 |
| `mastra` | 503 `no_fixture_match` | 200 |
## Test plan
- [x] RED: 5 new context tests fail against unfixed source
- [x] GREEN: `starter-smoke.test.ts` 47/47 pass
- [x] Full harness suite: 2073/2073 pass (119 files)
- [x] tsc clean (only the pre-existing `toReversed` lib error remains)
- [x] oxfmt clean, oxlint 0 errors
- [x] Live-staging RED→GREEN for 5 starters incl. 3 skewed names
The harness starter-smoke CHAT rung 503'd on staging because its raw fetch()
POST sent only Content-Type — omitting X-AIMock-Context. The scoped
per-integration "Hello" fixtures in showcase/aimock/d4/<integration>/chat.json
only match (under aimock strict mode) when the request carries
X-AIMock-Context:<context>, and that context token IS the dashboard column
slug (verified against each integration's
showcase/integrations/<col>/playwright.config.ts extraHTTPHeaders and the
fixture's match.context). The local browser e2e passes only because Playwright
injects the header, forwarded by HeaderForwardingMiddleware to aimock.
Send X-AIMock-Context: <columnSlug> on the chat POST only (matching the
browser; the GET rungs hit the runtime /info route, not aimock). columnSlug is
already resolved via starterToColumnSlug before the chat rung runs, so the skew
cases (langgraph-js->langgraph-typescript, adk->google-adk,
strands-python->strands, ms-agent-framework-*->ms-agent-*) get the correct
context for free.
Proven RED->GREEN against live staging aimock
(https://aimock-staging.up.railway.app): without the header -> 503
no_fixture_match; with the mapped column-slug context -> 200 matching the
scoped fixture.
Framework landing heroes (e.g. /langgraph-typescript) now show the same
two StartCommandCards as the home hero, and the "new project" command
pre-fills the framework via the CLI's --framework flag (e.g.
--framework langgraph-js). The mapping from docs slug to CLI framework is
verified against the CLI's AGENT_FRAMEWORKS enum; slugs with no 1:1
template fall back to a bare `npx copilotkit@latest create`. Frameworks
with bespoke setup (a2a git clone, ms-agent-dotnet) keep their own single
copy-command chip. Drops the old "Start the quickstart" button and the
legacy `npx copilotkit@latest init` chip.
Replace the home landing hero's Quickstart dropdown + command-copy chip
with a two-card <HeroStartCommands> block, framed by situation:
- Start a new project -> npx copilotkit@latest create
- Add to an existing project -> npx copilotkit@latest skills onboard
Both cards are equal weight with no pre-selected default. Each command
row copies on click with an aria-live announcement and a clipboard-blocked
fallback. Commands pin @latest so npx never reuses a stale cached CLI.
Removes the now-unused hero-quickstart-dropdown and hero-command-copy
components.
## Summary
- Bumps all starter integration examples under `examples/integrations/*`
to the latest published `@copilotkit` packages: `react-core`,
`react-ui`, `runtime`, `runtime-client-gql` (where present), `sdk-js`,
and the peer `a2ui-renderer` → **1.59.5**.
- Real prior pins were a mix of 1.59.3 / 1.59.1 / 1.56.5; all unified to
1.59.5.
- Regenerated each affected `package-lock.json` (starters use npm
per-app lockfiles and are intentionally excluded from the root pnpm
workspace — `pnpm-lock.yaml` untouched).
- Representative starter (`adk`) `next build` compiles successfully
against 1.59.5.
## Test plan
- [ ] CI build-checks green for the touched starters
- [ ] Starter dashboard greens on staging after image rebuild (chat rung
also depends on the aimock greeting fixture landing)
## Summary
Rewrites the `starter-smoke` probe to the **v2 path-based multi-route**
runtime protocol the deployed starters actually speak — proven via a
local build+curl gate against `examples/integrations/crewai-crews` at
1.59.5 (the runtime mounts `createCopilotEndpoint` in default
`mode:"multi-route"`, identical at 1.59.3 and 1.59.5).
- **agent** → `GET /api/copilotkit/info` requiring 200 + `version` (was:
"any non-404", which a health-JSON/HTML error page wrongly passed)
- **chat** → `POST /api/copilotkit/agent/<id>/run` (`Accept:
text/event-stream`), asserting ≥1 `TEXT_MESSAGE_CONTENT` delta **+**
terminal `RUN_FINISHED` **+** no `RUN_ERROR` (was: "non-empty body")
- **health** → repointed to `GET /api/copilotkit/info` (the starters
serve no `/api/health` route)
- **interaction** → `GET /` (unchanged)
- **drop the trailing slash** on runtime POSTs — `POST /api/copilotkit/`
308-redirects and drops the POST → 404, the core cause of the red rungs
Plus a **unified abort/body-read error classification** (one
`abortOutcome()` helper keyed on the local `externallyAborted` flag): a
self-timeout or a non-abort error → `transport-error` (soft), only a
genuine external abort → `aborted`; a cut-short body read softens to
`transport-error` instead of hard `smoke-failed`; the level loop
short-circuits on external abort. Reviewed across 3 CR rounds
(path-based rewrite + 2 abort-classification fix rounds + confirmation).
> **NOTE:** the content-level chat rung will correctly read **RED**
against the deployed starters until the Python-side `ag-ui-crewai`
`RUN_ERROR` (a real-LLM, in-process agent failure — *not* a probe bug)
is fixed. That is the truthful signal.
## Deferred follow-ups (tracked, not in scope)
- **Verify the alert/staleness consumer branches on `errorClass`, not
`state`** — else the soft/hard (`transport-error` vs `smoke-failed`)
split is cosmetic at the dashboard layer
- `res.text()` resolve-partial (truncated-but-resolved body) precision
edge → could mis-class as `smoke-failed`
- `redirect:"follow"` POST→GET edge; health/interaction success-path
body drain; health/agent share `/info` (correlated signals)
- `CLASS_RANK` ranks `aborted` lowest (design call); unmapped-starter
`columnSlug` invariant + prototype-key collision
- test-coverage gaps: `resolveTimeoutMs` env parsing,
`deriveStarterSlug` fallback, real-timer abort path
## Test plan
- [x] Harness unit suite — 1829 tests pass (105 files); starter-smoke
35/35; red-green verified for protocol + all abort/body-read fixes
- [x] Typecheck (no new errors), oxlint (0 errors), oxfmt, harness build
- [ ] Post-merge: redeploy harness, re-probe; chat rung greens once the
Python-side RUN_ERROR is fixed (separate workstream)
## Summary
Splits the showcase test harness into a **pool-fleet**: ONE Docker image
whose runtime role is selected at boot by `HARNESS_ROLE` into either a
**control-plane** (scheduler / job-producer / result-consumer /
result-aggregator / fleet-health) or a **worker** (BrowserPool +
claim/run/report loop). Roles communicate over a **PocketBase-backed
pull queue** (`probe_jobs`, `workers`) with a JSVM compare-and-set claim
hook (`fleet-claim.pb.js`) guaranteeing exactly-one-winner per claim.
Workers self-bound their own BrowserPool under the cgroup PID ceiling;
the control-plane runs no Chromium.
Key capabilities:
- **REQ-B — pool communication errors surface to the dashboard.** Worker
crashes, lost results, and unreachable-pool conditions are turned into a
`⚡` "unreachable" overlay on the affected cells (never silently
dropped). Three legs feed it: producer lease-driven sweep,
heartbeat-driven fleet-health reclaim, and the result-consumer's
resultless-past-grace latch — each preserving the prior observed colour
rather than fabricating green.
- **Browser-pool PID-ceiling hardening** carried over from the
single-process harness.
- **Role-dispatch is fail-loud:** an unset or invalid `HARNESS_ROLE` (or
`HARNESS_POOL_COUNT`) throws on boot, so a misconfigured fleet member
dies immediately instead of mis-running.
Reviewed via 5 CR fix rounds + 2 full 9-agent confirmation rounds
(cr-loop). 60 files, harness 2041 tests + dashboard 847 tests green,
both production builds green.
## Deferred follow-ups (bucket-(b): non-triggerable at N=2 / design
tensions, tracked not blocking)
- `isWorkerStale` PB-date parse works on Node V8 but doesn't share the
fleet-wide `PB_DATE_SEP_RE` normalization — align for goja-parity /
robustness.
- Never-observed-service comm-error coloring (`aggregateCommError`
writes `"error"` → history-only vs `aggregate()` using `"degraded"`) —
reviewers disagree on the correct direction; revisit as a deliberate
design decision.
- Recovered service can show "unreachable" until the next successful
aggregate run (self-clears within a producer cycle) — consider a
positive clear-on-green for the aggregate row.
- `terminalJobStatus` maps `degraded` → `failed` in run-history
(run-history widget over-reports failures for amber).
- Lease-renew guard uses strict `<` rather than a safety margin (only
matters at near-lease heartbeat config; defaults are 4× safe).
- Dashboard scans `health:`/`chat:`/`tools:` keys for comm-errors that
no harness leg writes (dead/defensive scope).
- `showcase test --isolate <name>` arg-order ambiguity in the CLI.
- Local `docker-compose.local.yml` worker `restart: unless-stopped` can
auto-revive a killed worker during the local REQ-B demo (use `docker
stop` / `restart: no`).
- Result-lost latch-failure can re-surface the same comm-error each
cycle (benign churn; needs result-lost + persistent PB write failure).
## Test plan
- [x] Harness unit suite — 2041 tests pass (119 files)
- [x] Dashboard unit suite — 847 pass / 1 skipped (53 files)
- [x] Typecheck (harness + dashboard), oxlint (0 errors), oxfmt
- [x] Production builds — harness `tsc` + dashboard `next build`
- [ ] Staging cutover to N=2 (gated; plan published separately on
Notion)
The chat rung hardcoded `/api/copilotkit/agent/default/run`, which 404s for
mastra — it registers dynamic non-`default` agent keys via
`MastraAgent.getLocalAgents` rather than `agents:{default}`. Resolve the
agent id per-starter from the first key of the `/info` `agents` map (the same
info response the health + agent rungs already fetch), falling back to
`default` only when that map is empty/unreadable, and surface the resolved id
on the chat row signal for drilldown.
Rewrite the starter-smoke probe to the v2 path-based multi-route runtime
protocol the deployed starters actually speak (proven via a local
build+curl gate against examples/integrations/crewai-crews at 1.59.5):
- agent rung: GET /api/copilotkit/info -> 200 + version (was: any non-404)
- chat rung: POST /api/copilotkit/agent/<id>/run (Accept: text/event-stream)
asserting >=1 TEXT_MESSAGE_CONTENT delta + terminal RUN_FINISHED + no
RUN_ERROR (was: non-empty body)
- health rung: repointed to GET /api/copilotkit/info (the starters serve
no /api/health route)
- interaction rung: GET / (unchanged)
- drop trailing slash on all runtime POSTs (the old /api/copilotkit/ 308s
and drops the POST -> 404, the core cause of the red rung)
Plus a unified abort/body-read error classification (one abortOutcome()
helper keyed on the local externallyAborted flag): a self-timeout or a
non-abort error is transport-error (soft), only a genuine external abort
is 'aborted'; a cut-short body read softens to transport-error instead of
hard smoke-failed; the level loop short-circuits on external abort.
NOTE: the content-level chat rung will correctly read RED against the
deployed starters until the Python-side ag-ui-crewai RUN_ERROR (a
real-LLM, in-process agent failure, NOT a probe bug) is fixed.
Deferred follow-ups: verify the alert/staleness consumer branches on
errorClass (not state) so the soft/hard split is actually consumed;
res.text() resolve-partial precision edge; redirect:follow POST edge;
health/interaction body-drain; health/agent shared /info; CLASS_RANK
aborted-lowest; unmapped-starter columnSlug/prototype-key; test-coverage
gaps (resolveTimeoutMs, deriveStarterSlug, real-timer abort).
## What
Updates the README to reflect CopilotKit's expansion beyond React:
- **New "Works With Your Stack" section** — platform table for
React/Next.js, Angular, Vue, and React Native
- **New "Beyond the Browser" section** — Slack & Microsoft Teams support
with an early access CTA
- Tagline updated to "on any framework, on any surface"
- "Chat UI" feature bullet made framework-neutral (was "React-based")
- useAgent section no longer anchors to the legacy useCoAgent hook
- AG-UI section: LangGraph → LangChain, added Mastra and PydanticAI to
named integrations
- New "How it works" bullet: one agent across web, mobile, and chat
platforms
## Before merging (draft)
- [ ] Replace `EARLY_ACCESS_FORM_LINK` placeholder with the real early
access form URL
- [ ] Point Angular / Vue / React Native quickstart links at their
framework-specific docs pages
- [ ] Confirm status labels (GA vs Supported vs Beta) for Angular / Vue
/ React Native
- [ ] Confirm `npx copilotkit create -f` accepts the new framework
values
Draft content also lives in Notion:
https://app.notion.com/p/copilotkit/New-GitHub-README-3763aa38185280788920fc81780c8ad6
## Summary
Follow-up to #5256 (the concurrent-paged initial-fetch perf fix). Trims
the live-status payload and hardens the realtime/SSE path of the
showcase Coverage dashboard.
- **Trim initial projection** — drop the heavy `signal` field from the
initial PocketBase fetch via a compiler-guarded `STATUS_LIST_FIELDS`
projection + `skipTotal` + length-based bounded-concurrency pagination.
Consumers adapted: `CellDrilldown` lazy-loads `signal` on demand
(genuine failures only), `DiscoveryAuthBanner` self-fetches detail
(identity-tagged cache), legacy `LiveBadge` degrades gracefully when
`signal` is absent.
- **Harden the realtime path** — `flushPending` teardown guards,
keyless-delete `id→key` buffer collapse (per-row last-write-wins, pure
ref+effect mirror), SSE-delta signal-presence upsert, and a `degraded`
flapping flag (clears on heartbeat success, resets on terminal error).
- **Grid/UX** — a `stale` (muted, non-authoritative) tally state
distinct from the no-rows loading state, an amber-chip/green-D5
dimension-classification fix, and `degraded` surfaced in the header
`LiveIndicator` (offline outranks degraded).
## Test plan
- [x] `tsc --noEmit` clean
- [x] `vitest run` — 879 passed / 1 skipped (56 files); +63 new
behavioral tests across the changed areas (real-SDK socket tests for
fetch/autocancel/lazy-signal, fake-timer tests for the flapping detector
and reconnect chain, exhaustive resolveCell truth-tables)
- [x] `next build` — compiled successfully, 5/5 static pages
- [x] oxfmt + oxlint clean
- [ ] CI green
- [ ] Visual verification on staging after deploy
## Known follow-ups (deferred — pre-existing / out-of-subject, not
introduced by this PR)
These were surfaced during review, verified pre-existing on `main` (or
unreachable in the shipping config), and intentionally not fixed here to
keep the PR scoped:
- Column-header tally counts deprecated features hidden from the grid
body (`computeColumnTally` iterates the full `features` list while the
body renders `visibleFeatures`) — pre-existing, header/body over-count
identical before and after. Strong candidate for a dedicated follow-up.
- `resolveCell` rollup does not suppress amber/degraded cells when
`connection === "error"` (only green is suppressed) — pre-existing
precedence.
- `formatTooltip` offline branch renders "degraded since
<transitioned_at>" for a staleness-downgraded green row.
- `LiveBadge` arms the `useLastTransition` fetch for
staleness-downgraded amber badges (no `isGenuineFailure` filter, unlike
the drilldown).
- `CellStatus` passes the raw `featureId` as the CV-badge transition
key, so mapped D5 families query a non-existent history row.
- Cosmetic: `extractSignalFields` renders `{}` for an empty-object error
field; `degraded` lacks an effect-cleanup reset on the
(production-unused) `dimension` param path; minor comment-accuracy nits
(reconnect backoff tiers, rollup-precedence JSDoc).
The check-config-files job blocked the strands-crm showcase PR
(examples/showcases/strands-crm/frontend/next.config.ts was not in
the build-config allowlist). Adding it next to strands-file-analyzer.
## Problem
CLI starters for Mastra, Agno, PydanticAI, AWS Strands, Google ADK, MS
Agent Framework, and LlamaIndex fail on `npm run dev` with:
```
Error: dependency failed to start: container copilotkit-intelligence-intelligence-1 is unhealthy
intelligence-1 | error: database "intelligence_app" does not exist
```
## Root cause
The overlay compose relied on a bind-mounted `docker/init-db/` script to
create `intelligence_app`, but the CLI's Intelligence activation copies
**only** `docker-compose.yml` into scaffolded projects. The mount source
never exists there, so Docker creates it as an empty directory, postgres
initializes with only the default DB, and the composite's migrations
fail.
`langgraph-python-threads` was unaffected because its template ships its
own compose + `docker/init-db/` in-repo.
## Why it keeps biting internal testers
The compose project name is fixed (`copilotkit-intelligence`), so
**every starter on a machine shares one `postgres-data` volume** — and
postgres only honors `POSTGRES_DB`/init scripts on first init of an
*empty* volume. One broken run poisons the volume for every subsequent
starter, regardless of framework.
## Fix (self-contained + self-healing)
- `POSTGRES_DB: intelligence_app` and drop the `docker/init-db` bind
mount + script (the shadow DB it also created is only used by repo-local
dev tooling, never by the composite)
- Add an idempotent `provision-db` one-shot (same pattern as the
existing `provision-user`) that creates `intelligence_app` when missing
— this heals already-poisoned volumes on the next `docker compose up`,
with no manual `down -v`
- Gate `intelligence` on `provision-db` completion; align the postgres
healthcheck dbname
Because the CLI fetches this overlay live from `main` at scaffold time,
merging this fixes every CLI version in the wild immediately — no CLI
release needed.
## Verification
Tested with real Docker on isolated compose projects:
1. **Poisoned volume** (reproduced by running the old compose revision
with the empty `init-db` dir the CLI leaves behind → volume with no
`intelligence_app`): new compose → `provision-db` exits 0, migrations
run, composite **Healthy**, `up -d --wait` exits 0
2. **Fresh volume**: DB created via `POSTGRES_DB`, `provision-db`
no-ops, composite **Healthy**
3. **Idempotency**: second `up -d --wait` on a running stack exits 0
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Why
New users are still finding cloud.copilotkit.ai even though they
shouldn't be. An org-wide audit found the live funnels; this PR closes
every source in this repo.
## What changed
Replaced all **user-facing web links** to `https://cloud.copilotkit.ai`
with `https://dashboard.operations.copilotkit.ai` (the same destination
the copilotkit.ai marketing CTAs already use):
- **Live docs pages** (`docs/` + `showcase/shell-docs/`) —
premium/observability/threads/oss-vs-enterprise/intelligence-platform
pages, integration quickstarts/tutorials, V1 reference pages, shared
snippets
- **`LinkToCopilotCloud` component** (both copies) — was routing through
`go.copilotkit.ai/copilot-cloud-button-docs` → cloud sign-in; now points
at the dashboard directly
- **README** — the `?ref=github_readme` CTA (label updated to "Try the
Enterprise Intelligence Platform")
- **Example READMEs** (`examples/v1/*`, showcases)
- **Shipped package code** so future releases stop reseeding the
problem: `console-styling.ts` key warnings, `usage-banner.tsx`,
`developer-console-modal.tsx`, V2 `license-warning-banner` (React +
Vue), provider JSDoc
## Deliberately untouched
- `api.cloud.copilotkit.ai` endpoints (`COPILOT_CLOUD_API_URL`,
check-for-updates, telemetry tests) — existing cloud customers depend on
these
- "Copilot Cloud" prose/product naming in docs copy — link targets only;
copy rewrite is a separate editorial pass
## Out of repo (follow-ups, not in this PR)
- `go.copilotkit.ai/GetStarted` still 302s to cloud — zero code
references org-wide, so traffic is from old emails/posts; needs
repointing at the shortener
- Already-published npm versions carry the old links forever — only a
cloud-side signup gate closes that vector
## Verification
- `nx run-many -t test,build -p @copilotkit/shared
@copilotkit/react-core @copilotkit/vue` ✅
- `@copilotkit/sqlite-runner:test` ✅ (failed initially from a stale
Node-20 `better-sqlite3` binary in the fresh worktree, unrelated to this
change)
- Zero remaining non-`api.` `cloud.copilotkit.ai` references in
docs/packages/examples
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The activation overlay's docker-compose.yml relied on a bind-mounted
docker/init-db script to create the intelligence_app database, but the
CLI copies only docker-compose.yml into scaffolded projects. The mount
source never exists there, Docker creates it as an empty directory,
postgres initializes without intelligence_app, and the composite's
migrations fail: 'database "intelligence_app" does not exist' →
'dependency failed to start: container ...intelligence-1 is unhealthy'.
Make the compose file self-contained:
- Set POSTGRES_DB: intelligence_app (drop the init-db bind mount and
the now-unused init script; the shadow DB it also created is only
used by repo-local dev tooling, never by the composite).
- Add an idempotent provision-db one-shot that creates the database
when missing. POSTGRES_DB only applies on first init of an empty
volume, and the volume is shared across all scaffolds via the fixed
compose project name — so machines that already hit the bug have a
data volume without the database. The one-shot heals those on the
next 'docker compose up' with no manual 'down -v'.
- Gate the composite on provision-db completion instead of postgres
health, and align the postgres healthcheck dbname.
New users were still discovering cloud.copilotkit.ai through docs pages,
the README, example READMEs, and in-app banners/console messages. Replace
all user-facing web links with dashboard.operations.copilotkit.ai (the
destination the marketing-site CTAs already use). Functional API endpoints
(api.cloud.copilotkit.ai) are deliberately untouched since existing cloud
customers depend on them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Why
The langgraph-python template's `uv.lock` was stale: it locked
`copilotkit 0.1.87` / `ag-ui-langgraph 0.0.33` while `pyproject.toml`
pins `copilotkit==0.1.93`. Because the lock didn't match, every
scaffold's `uv sync` discarded it and re-resolved fresh against PyPI
latest.
That silent re-resolution is how fresh `copilotkit init` scaffolds
(langgraph-py / a2ui / opengenui) broke today: they picked up
`ag-ui-langgraph 0.0.39`, which imported a then-unpublished
`ag-ui-a2ui-toolkit` symbol and failed at import time (`ImportError:
cannot import name 'run_a2ui_generation_with_recovery'`). The other
python templates (langgraph-fastapi, langgraph-python-threads,
strands-python) survived precisely because their locks are in sync.
## What
Regenerated `uv.lock` with `uv lock` so it matches `pyproject.toml`. It
now locks the fixed pair published by the ag-ui maintainers:
`ag-ui-langgraph 0.0.40` + `ag-ui-a2ui-toolkit 0.0.2` (verified to
import cleanly and load the template graph). With the lock in sync,
scaffolds become deterministic — a future broken upstream release can no
longer break `copilotkit init` until the lock is deliberately updated.
Tracking the upstream release-process issue in OSS-256.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## What
Move the langgraph A2UI demos + docs off alphas now that the stable
packages are out.
### Deps (commit 1)
- `copilotkit` `0.1.94a3` → **`0.1.94`** (langgraph-python,
langgraph-fastapi)
- `@copilotkit/*` `1.59.2` → **`1.59.4`** + `@copilotkit/sdk-js`
`1.59.3-alpha.3` → **`1.59.4`** (langgraph-typescript + agent)
- **Dropped the `@ag-ui/langgraph` override** —
`@copilotkit/runtime@1.59.4` now carries `@ag-ui/a2ui-middleware@0.0.6`
(the `injectA2UITool` forward) + `@ag-ui/langgraph@0.0.37` (the state
surface). Locks regenerated; `npm ci` in sync.
### Docs (commit 2)
- Rewrote the **dynamic-schema** A2UI pages (langgraph + deepagents +
generic) for the middleware flow:
- **prebuilt agent** → just add `CopilotKitMiddleware`
- **graph agent** → wire `get_a2ui_tools`
- `injectA2UITool` is the single on/off switch
- Removed the stale hand-rolled `render_a2ui`/`generate_a2ui` +
`a2ui_prompt` framing; corrected streamed op names
(`createSurface`/`updateComponents`/`updateDataModel`).
## Why
The merged middleware PR made A2UI opt-in via the forwarded
`injectA2UITool` flag; the showcase was pinned to alphas + a transitive
override, and the docs still described the pre-middleware design.
Left over from instrumenting the HITL render lifecycle while verifying that
clicking a card in the in-chat picker resolves `respond()` and triggers the
agent's continuation run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Teach-mode UX (staged on the no-op recorder shim, ready for the live hook):
- Suggested-prompt pill leads the welcome screen — "Approve the $5,000
Marketing transaction" — a one-click path straight into the
over-policy-limit gate (seed t-1: Google Ads -$5,000, Marketing limit
$5,000 / spent $500). The same pill drives both halves of the arc:
fails pre-learning, succeeds post-learning.
- Pulsating violet recording vignette frames the canvas while the officer
is teaching. Ref-counted around every `recordUserAction` call so it
stays continuous across opened+finalized; minimum 1.2s visible duration;
non-blocking; static fallback under prefers-reduced-motion. Mounted at
z-1300 to read clearly even over the docked chat panel.
- Inline policy-exception card replaces the popup modal: the officer's
whole demonstration (see symptom → file exception → record) now
happens in the chat as a single HITL card, with identical REST
callers and identical `policy_exception.opened`→`finalized` recording
payloads to the old modal.
CK v2 provider fix:
- Swap the v1 `CopilotKit` compatibility bridge for the v2-native
`CopilotKitProvider`. The bridge wraps the chat in a heavier stack
(ThreadsProvider + a second CopilotChatConfigurationProvider + listeners);
that churn re-fires CopilotChat's /connect effect cleanup mid-run, and
the cleanup calls AG-UI `detachActiveRun()` — which silently tears down
the in-flight run the instant the agent emits a frontend HITL tool call.
Symptom was a clean run with no error but no HITL render. With
CopilotKitProvider the `/connect` storm and ERR_ABORTED are gone and
runs complete cleanly. The inbox keeps working because v2 `useThreads`
reads CopilotKitProvider's own context.
- `reactStrictMode: false` in next.config to remove the dev double-mount
that aggravates the same teardown class. Production unaffected.
Other:
- Switch model to `openai/gpt-5.4-mini-2026-03-17` (verified reachable;
same tool-calling surface).
- Add `selectCard` HITL tool + visual `CardPicker` (in-chat brand+last4
picker) so card-targeted flows (PIN, policy assign) get a visual
picker instead of a text list.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Our previous doc site had a fumadocs/shadcn theme that was a bit
hodge-podge. This brings all of it into one clean and visually appealing
design. The border radii are standardized, colors are standardized and
bunch of passes for mobile/tablet have been done. An added bonus is that
the header nav has been redone to feel more natural to the eyes.
<img width="1850" height="1256" alt="Screenshot 2026-06-05 at 7 48
00 AM"
src="https://github.com/user-attachments/assets/0c6032f2-e406-4e51-9c31-d69a9d258d61"
/>