Copilot — display spec, behaviour and knowledge base
One copilot component for every portal. Its look, positions and controls are identical everywhere; only the instructions, greeting, notices and knowledge base differ, and those are edited from Admin → Copilot & Knowledge Base, never in code. Last updated 2026-09-02.
1. Where it appears
| Portal | Mounted by | Knowledge base | Talks to |
|---|---|---|---|
| School (admins, teachers, staff) | PortalShell | SCHOOL + GLOBAL | how the school portal works; never the school's own records |
| Startup / vendor | PortalShell | STARTUP + GLOBAL | leads, pilots, integration |
| Platform admin | PortalShell | ADMIN + GLOBAL | operations, audit, KB upkeep |
| Parent | PortalShell | PARENT + GLOBAL | what the portal shows, how to ask the school |
The onboarding wizard keeps its own embedded step copilot (it is a single flow with a fixed script); the pupil launcher has none (children's surface).
2. Display spec (components/copilot/copilot.tsx)
| Mode | Appearance | How you get there |
|---|---|---|
| closed | a launcher pill at the bottom-right edge; an amber dot when the page is a function page | Close, or Esc from panel/docked |
| panel | slides out from the right over the page, 420 px wide, full height, shadow | click the pill; Undock |
| docked | sits beside the page at 420 px and pushes the content (the main column reserves --copilot-dock) | Dock |
| max | fills the viewport; conversation centred at 3xl width | Maximise |
Toolbar, left to right: Dock / Undock, Maximise / Revert, Close. *Revert* returns to whichever mode the copilot was in before it was maximised. Esc reverts from max, otherwise closes. The chosen mode is remembered per portal in localStorage (eduspaze.copilot.<portal>).
Panel anatomy: header (avatar, display name, current module, state), function-page notice bar (amber, when applicable), greeting bubble, suggested prompts (before the first question), conversation, input row. Assistant answers list the knowledge-base articles they drew on; when no LLM key is configured they say so in small print.
Accessibility: role="complementary", labelled toolbar buttons with aria-pressed, an aria-live region that announces entering and leaving a function page, input disabled with an explanatory placeholder when blocked.
3. Function pages
A function page is any page where the user can create, edit or delete model data (forms and actions). On such pages the copilot:
- announces, once, that it is not enabled for the module (
functionPageNotice, with{module}replaced by the menu name), both in the conversation and viaaria-live; - disables the input and shows the notice bar;
- announces it is back when the user leaves the page.
The classification lives in one registry, lib/copilot/registry.ts (MODULES), so the server enforces the same rule: the chat API refuses questions from function pages and logs the refusal. Unknown pages under a portal are treated as function pages (fail closed).
| Portal | Function pages | Information pages |
|---|---|---|
| School | Staff & Access, Students, Classes & Groups, School Settings, Needs Survey, Challenge Statements, Parent Questions, a pipeline conversation, Bundles & Credits, Audit Log, Matchmaking Trips, a marketplace listing | Dashboard, Recommendations, Marketplace, My Pipeline, Benchmarking, Engagement, Platform discovery |
| Startup | Profile & Pilot Offer, Integration & API, a lead conversation, Challenge Statements, Matchmaking Trips | Dashboard, Lead Inbox, Market Insights |
| Admin | Vetting, Schools, Bundles, Credits, Trips, Grants, Challenges, Settings, Audit, Copilot & KB | Dashboard, CRM, Reports |
| Parent | App detail & questions | Your children, Apps, Timeline, Activity |
4. Answering (lib/copilot/rag.ts)
Retrieval-augmented generation over the portal's knowledge base:
- Retrieve: Postgres full-text search (
ts_rankover title, summary, tags, body) across *published* articles for the portal plusGLOBAL, top 4; keyword fallback on title/tags. - Generate: the admin-selected LLM (Admin → Settings) with the portal's instructions plus platform guardrails: answer only from the excerpts, say when they do not cover the question, never reveal or guess other tenants' data, under 150 words, cite excerpt numbers, never claim to have performed an action.
- Fallback (no key or provider error): the best article's summary and related titles, so the copilot is useful with zero keys (NFR-1).
- Log: every exchange is stored (
CopilotExchange: portal, route, user, tenant, question, answer, source, articles used). Questions are free text, so the row carries the PII flag columns and is captured by the audit harness like any other write.
The copilot never queries business tables. It knows how the platform works, not what is in it; that keeps the parent-module and tenant-isolation guarantees intact by construction.
5. Knowledge base (database, not code)
| Model | Purpose |
|---|---|
CopilotConfig (per portal) | enabled, display name, greeting ({name}), instructions, function-page notice ({module}), suggested prompts |
KnowledgeArticle | portal (or GLOBAL), slug, title, summary, markdown body, tags, status (draft / published / archived), version |
CopilotExchange | question/answer log for gap review |
Admin → Copilot & Knowledge Base shows, per portal: the settings form, the article list with status and version, 30-day counts by answer source, and recent questions with a badge when none matched an article. Articles render with the same markdown renderer as /docs.
Seed content: prisma/seed-data/knowledge.ts (starting set only; edits live in the database and are audited like every other change).
6. Adding the copilot to a new portal
- Add the portal to
CopilotPortal,PORTAL_PREFIX,MODULESandROLE_PORTAL. - Pass
portal="…"toPortalShell. - Seed a
CopilotConfigand a few articles; the admin page picks the portal up automatically.
7. Open items
- Streaming responses and message history persistence across page loads.
- Per-tenant article overrides (a school's own how-tos) — the schema allows a
tenantIdlater; the retrieval query would union them. - Feedback buttons on answers feeding the gap review.
