Skip to content

2026-04-27 โ€” Admin AI Assistant (Lantern Chat) โ€‹

Outcome: Complete โ€” backend + UI + wiring shipped, admin build green, smoke-tested locally.

Scope โ€‹

Add an agentic Claude-powered chat assistant to the admin portal. The assistant answers questions contextually and may, when it decides it's needed, read repo files (docs/code), grep the repo, list directories, list registered API services, or query a small allow-list of Firestore collections.

Files Added โ€‹

Backend โ€” services/api/assistant/ (new Cloud Run service) โ€‹

Admin UI โ€” apps/admin/ โ€‹

  • src/components/LanternChat/LanternChat.jsx โ€” floating bubble (bottom-right) + slide-up panel. Persists last 30 messages to localStorage (lantern-chat:messages:v1). Page context (useLocation) sent every turn. AbortController for in-flight cancel. Markdown rendering (react-markdown + remark-gfm). 4 starter suggestions.
  • src/components/LanternChat/LanternChat.css โ€” 56ร—56 amber radial-gradient bubble, lantern-glow keyframe pulse (3.2s), 420ร—640 panel, dark #0f172a surface, amber accent. Tool-call <details> collapsible.
  • src/components/LanternChat/index.js
  • src/lib/assistantApi.js โ€” sendAssistantChat() via authRequest. URL from VITE_ASSISTANT_API_URL (defaults to /api proxy โ†’ http://localhost:8086).

Files Modified โ€‹

  • packages/shared/services/index.js โ€” added assistant-api entry (auto-surfaces in admin API Reference page; CLAUDE.md rule #8).
  • package.json โ€” added services/api/assistant workspace; scripts assistant-api:dev, assistant-api:start, assistant-api:test, assistant-api:deploy:dev, logs:assistant-api, logs:assistant-api:prod. Extended apis:dev, apis:kill, kill:ports to include 8086 (also backfilled missing 8081/8084/8085).
  • tooling/vscode-extension/src/config.js โ€” Assistant API in PORT_MAP.apis (8086); assistant-api:dev + log scripts in DEV_SERVER_SCRIPTS; INPUT_PROMPTS entries.
  • apps/admin/vite.config.mjs โ€” /api/assistant proxy โ†’ env.ASSISTANT_API_ORIGIN.
  • .env.local.example โ€” added ASSISTANT_API_ORIGIN, VITE_ASSISTANT_API_URL, commented ASSISTANT_MODEL / ASSISTANT_MAX_TOKENS.
  • apps/admin/src/components/AdminDashboard.jsx โ€” renders <LanternChat /> for admin users only.

Architecture Notes โ€‹

  • API-first (CLAUDE.md rule #9): new HTTP service, not a Cloud Function.
  • Stateless backend: full conversation passed each turn. Server runs the agentic loop, executes tool calls, feeds tool_result blocks back until the model returns a non-tool_use stop_reason.
  • Auth model: admin only. Merchant access intentionally deferred to a future phase (different system prompt + tighter tool allow-list expected).
  • Rate limit: 30 chat turns / 5 minutes per user (UID-keyed in-memory window โ€” fine for single-instance Cloud Run; replace with Redis if we scale horizontally).
  • Repo root resolution: env ASSISTANT_REPO_ROOT โ†’ /app/repo-snapshot (production Docker layout) โ†’ repo root (dev). The repo-snapshot/ directory must be populated before gcloud run deploy (the deploy script needs to copy a sanitized snapshot โ€” TODO before first deploy).

Verification โ€‹

  • npm install clean โœ…
  • node --check on all new JS files โœ…
  • ESLint on all new code: clean (one warning auto-fixed) โœ…
  • Boot smoke test: /health returns ok with anthropic: false (no key set) โœ…; /openapi.json serves spec โœ…; POST /assistant/chat without auth โ†’ 401 UNAUTHORIZED โœ…; with fake bearer โ†’ 401 Invalid or expired token โœ….
  • npm run build -w apps/admin โœ… (LanternChat included in main bundle).

Outstanding / Future โ€‹

  • Smoke test against real Anthropic: requires ANTHROPIC_API_KEY env. Verify model id claude-sonnet-4-5 resolves; if not, override via ASSISTANT_MODEL.
  • Deploy script: needs a step to copy a sanitized repo-snapshot/ (excluding .env*, node_modules, secrets, build artifacts) before gcloud run deploy.
  • Merchant assistant: separate system prompt + narrower tool allow-list (no query_firestore cross-tenant; scope read_file/grep_repo to merchant-facing docs).
  • Telemetry: log token usage per turn for cost tracking once we go live.
  • Persistence: if we ever want cross-device chat history, move localStorage persistence to Firestore under the user's record.

Built with VitePress