Phase 3 of the banking->Intelligence-main migration. Self-hosted Intelligence
gates the paid `memory` feature behind a signed offline license; a locally-built
(unbaked) app-api trusts a runtime BAKED_LICENSE_KEYS_JSON, so a throwaway
keypair can sign an enterprise license with features.memory=true.
- scripts/mint-dev-license.mjs: prints (or --write upserts into .env)
COPILOTKIT_LICENSE_TOKEN + BAKED_LICENSE_KEYS_JSON + INTELLIGENCE_DEPLOYMENT_MODE.
Drives the signer from the PRIVATE Intelligence source via INTELLIGENCE_REPO
(same coupling the docker-compose image build already has) rather than
vendoring any signing code into this public repo. No secret is embedded; the
script is dev-only and never imported by the app runtime.
- .env.example: documents BOTH the managed path (CopilotKit-issued token, no
baked key — the eventual hosting target) and the self-hosted dev path, so the
demo is not locked to the local stack.
- package.json: add `mint-dev-license` script.
Replaces the ephemeral Intelligence/tmp/mint-banking-license.ts. .env stays
gitignored; nothing sensitive is committed. Local-only until verified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AUTHORED + statically validated (playwright --list compiles spec+config, fixtures/
package JSON valid, launcher syntax OK). NOT yet green-verified — needs aimock
installed (pnpm i), the docker memory stack up, and the dev server in Intelligence
mode (multi-process; not runnable in the current sandbox). Each file carries a
'VERIFY ON FIRST GREEN RUN' checklist for the shakedown.
- e2e/memory-learning.spec.ts: seeds the procedure via REST (recall-half isolation
per the plan), drives a fresh thread, asserts recall->unlock with no recording
offer + the over-limit gate lifted. Save half stays HITL+LLM (drift smoke / manual).
- e2e/fixtures/memory-learning.fixtures.json: pins recall_memory -> openPolicyException
-> finalizePolicyException -> approveTransaction.
- e2e/aimock-server.mjs: aimock launcher (programmatic, CLI fallback documented).
- playwright.config.ts: webServer array (aimock + dev in Intelligence mode, OPENAI_BASE_URL->aimock).
- package.json: +@copilotkit/aimock devDep; test:self-learning -> the spec.
- remove scripts/self-learning-smoke.mjs (dead #192 distill path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scripts/self-learning-smoke.mjs proves the banking demo's recording seam
end-to-end against a running Intelligence backend: posts four teaching
actions through the demo BFF /api/copilotkit/annotate (the platform
requires UUID clientEventIds), optionally runs one sl-worker sweep when
INTELLIGENCE_REPO is set, and asserts the distilled vendor policy reads
back through the platform /mcp knowledge tool. Wired as the
test:self-learning package script and documented in the README.
Verified live: PASS 6/6 against Intelligence @ mme/learn-from-user-activity
(records as rows 13-16, sweep editCount=0 steady-state, recall returns the
pre-cleared vendor policy).
next lint was removed in Next 16, so the demo's lint script failed before
linting anything. Switch to eslint . with a flat eslint.config.mjs built on
eslint-config-next's native flat exports (same shape as the other Next 16
example apps), and fix the findings the new react-hooks rules surfaced:
- actions.ts / team/actions.ts: wrap mount fetches in an async IIFE so
set-state-in-effect can see the setState calls are asynchronous
- auth-context: derive currentUser from selection ?? team[0] instead of
syncing state in an effect
- use-theme: lazy-init theme from localStorage (SSR-guarded) and apply the
DOM class in an effect keyed on theme; hoist applyTheme to module scope
- threads-drawer: copy timeout maps to locals inside the effect so cleanup
does not read refs that may have changed
package.json was pinning next@14 / react@18, but the root pnpm.overrides
were already forcing next@16 / react@19 at install time and the code uses
Next 16 async params. Bump the declared ranges to ^16.0.10 / ^19 (and
@types/react{,-dom} to ^19) so the manifest matches reality and matches
the v2 reference demos (mcp-apps, generative-ui-playground).
Also drop examples/showcases/banking/pnpm-lock.yaml: the demo is a
workspace package (listed in root pnpm-workspace.yaml and resolved in the
root pnpm-lock.yaml), so the per-demo lockfile was vestigial v1 cruft
that contradicted the v2 migration.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Banking was on Tailwind v3, which made the pre-compiled v2 stylesheet
(`@copilotkit/react-core/v2/styles.css`, built as Tailwind v4 output)
incompatible with the PostCSS pipeline. A temporary inline-CSS hack in
`layout.tsx` worked around this. Migrate to Tailwind v4 to match the
canonical v2 demos and remove the hack.
- package.json: tailwindcss ^4, add @tailwindcss/postcss ^4, replace
tailwindcss-animate with tw-animate-css (v4 drop-in)
- postcss.config.mjs: switch plugin to @tailwindcss/postcss
- globals.css: use @import "tailwindcss" + @import "tw-animate-css";
add @custom-variant dark for the existing .dark/.light class toggle;
move shadcn color/radius mapping into @theme inline (preserves
bg-background/text-foreground/rounded-{lg,md,sm} semantics)
- tailwind.config.ts: deleted; theme now lives in CSS
- components.json: clear stale tailwind.config reference
- layout.tsx: drop the readFileSync/dangerouslySetInnerHTML inline-CSS
workaround; import "@copilotkit/react-core/v2/styles.css" the normal
way alongside ./globals.css
Verified: tsc clean, next build clean, Playwright-rendered all four
pages (/, /dashboard, /cards, /team) with computed-style checks
(sidebar bg-gray-900 dark, rounded-lg=8px, .border=1px) and opened
the copilot popup which renders fully styled with the v2 stylesheet.
Replace eslint and prettier with oxlint and oxfmt for faster linting
and formatting across the monorepo. Remove all eslint and prettier
configs, dependencies, and related packages. Add .oxlintrc.json and
.oxfmtrc.json for the new tooling. Update CI workflows and lefthook
hooks accordingly. Reformat codebase with oxfmt.
https://claude.ai/code/session_01GMkSf29p78HuMR1mbXn8He