Half your helpdesk tickets are "how do I reset my SSO password" and "how do I get a new laptop" — questions your IT docs already answer. You want a page that answers them before a ticket gets filed, without pulling an engineer off other work to build it.
Not yet tested end-to-end on a live Lovable account. The prompt below states the exact, corrected Chat API shape literally rather than describing it in prose, so an agent can't guess wrong — that part is verified. Whether Lovable actually produces a working app from it is not, since that's outside this cookbook's control.
Get your secrets ready before you start.
GLEAN_API_TOKEN— Admin Console → Platform → API Tokens → scope it toCHATonly.GLEAN_INSTANCE— the<instance>part of yourhttps://<instance>-be.glean.comURL.
Start a new Lovable project and paste this whole block — fill in your instance name first.
Build "Acme IT Deflection Page" — a single-page chat tool that answers
common IT helpdesk questions (SSO/password resets, laptop issues, VPN
setup) using the Glean Chat API, so employees get an answer before they
file a ticket. I don't want to write or review implementation code; you
own that. I do want to review the running app and its use of secrets.
The browser must never see a Glean API token. If a question calls a
Glean API from the client, the token is exposed to anyone who opens
devtools — that's not acceptable here. Route the Glean call through
whatever server-side mechanism you use for secrets and backend calls
(you may need to connect a backend/database integration to get one) —
ask me before you do, and ask me for the two values below when it's
ready. Don't skip this by calling Glean directly from React.
1. Build a React page: a text input, a submit button, an answer area,
and a "Sources" list below the answer. Frame it as "Ask before you
file a ticket."
2. Server-side, install `@gleanwork/api-client` (pin the version — do
not use a `^` or `latest` range) and construct the client like this:
```ts
import { Glean } from '@gleanwork/api-client';
const glean = new Glean({
apiToken: process.env.GLEAN_API_TOKEN,
instance: process.env.GLEAN_INSTANCE, // e.g. "<your-glean-instance>"
});
```
Both `GLEAN_API_TOKEN` and `GLEAN_INSTANCE` must be stored as
server-side secrets, never hardcoded and never bundled into the
frontend. Stop and ask me for these two values by name before running
the app — do not invent placeholder values and move on.
3. Call the Chat API like this — the response shape is specific, follow
it exactly rather than guessing at field names:
```ts
export async function askGlean(question: string) {
const response = await glean.client.chat.create({
messages: [{ author: 'USER', fragments: [{ text: question }] }],
});
const contentMessages = (response.messages ?? []).filter(
(m) => m.messageType === 'CONTENT',
);
const fragments = contentMessages.flatMap((m) => m.fragments ?? []);
const answer = fragments.map((f) => f.text ?? '').join('');
const citations = fragments
.map((f) => f.citation?.sourceDocument)
.filter(
(doc): doc is NonNullable<typeof doc> => !!doc?.title && !!doc?.url,
);
const uniqueCitations = Array.from(
new Map(citations.map((doc) => [doc.url, doc])).values(),
);
return { answer, citations: uniqueCitations };
}
```
Notes on the response shape, since guessing at field names here is
easy to get wrong:
- The response can include earlier step-narration messages
(search/read progress) before the real answer — filter to
`messageType === 'CONTENT'` or that narration text ends up
prepended to the answer.
- Citations live per-fragment, in `fragment.citation.sourceDocument`
— not a top-level `citedDocuments` field, and not the older
`message.citations[]` field (deprecated, and not populated at all
on a live agentic response). Dedupe by `url` since the same source
is commonly cited by more than one fragment.
4. Frontend: on submit, call your server-side function with the
question, render `answer` as text, and render each citation as a link
using its `title` and `url`. Show a loading state while waiting. Show
the raw error message if the request fails (this is an internal tool
— don't hide errors from me while I'm testing it).
5. Give the assistant a short system framing so it stays on-topic: it
should present itself as "Acme IT Help" and answer IT/helpdesk
questions using only what Glean returns — don't have it improvise
troubleshooting steps Glean didn't cite.
6. When you're done, tell me the two things I need to test:
- Ask "Where do I reset my SSO password?" and confirm the answer
cites the SSO reset guide.
- Ask "How do I request a new laptop?" and confirm it cites the IT
helpdesk FAQ (loaner laptops, same-day, from the IT desk).
Do not add authentication, a ticketing integration, or user accounts —
Glean already enforces per-user permissions on the backend token's
behalf for this demo, and this is a single-tenant internal tool.
Lovable's default stack leans on a connected backend/database integration for anything server-side, including secrets — that surface changes over time, so the prompt asks the agent to set one up rather than assuming a fixed mechanism. What doesn't change is the constraint: the token never reaches the browser.
Test with the two demo queries below, then check your browser's Network
tab to confirm requests to *.glean.com originate from your backend, not
the page itself.
CHAT token even further if your Glean plan supports
per-collection tokens, so this tool can only ever answer from IT content.no-code-pto-lookup-replit — same Chat API call, same "browser never holds the token" constraint, different no-code tool and persona.acme-answers shows the same pattern as a hand-written, version-controlled app.Copies a prompt your AI assistant can build from.