# Overview > What sideagent is and the two ways to run it: the open-source library or sideagent Cloud. Source: https://sideagent.dev/docs sideagent embeds a chat agent in your app. You give it an OpenAPI spec and an OpenAI-compatible LLM host and key. It gives you a secure agent endpoint and a React chat UI. The agent calls your API on behalf of the signed-in user, using that user's own credentials. ## Two ways to run it - **sideagent** (open source, MIT): a TypeScript library you run in your own server. See [Server](https://sideagent.dev/docs/server.md) and [Chat UI](https://sideagent.dev/docs/chat-ui.md). - **sideagent Cloud**: the same agent, hosted. You configure it in a dashboard and embed it with a publishable key. See [sideagent Cloud](https://sideagent.dev/docs/cloud.md). ## How a request flows 1. The browser sends a chat message to the agent endpoint, with the user's `Authorization` header. 2. The server verifies the user ([User authentication](https://sideagent.dev/docs/auth.md)) and loads the agent. 3. The model picks operations from your allowlist ([Operations](https://sideagent.dev/docs/operations.md)). 4. Calls that change data pause for the user's approval ([Approvals](https://sideagent.dev/docs/approvals.md)). 5. Allowed calls go to your API with the user's own credentials, and the result streams back to the chat. ## Where to go next - New here: [Quickstart](https://sideagent.dev/docs/quickstart.md). - Hosted setup, no server code: [sideagent Cloud](https://sideagent.dev/docs/cloud.md). - What protects you and your users: [Security model](https://sideagent.dev/docs/security.md). - Building your own client: [Wire protocol](https://sideagent.dev/docs/protocol.md). ## For LLMs and tools Every page here is also available as Markdown: add `.md` to the page URL, for example `/docs/quickstart.md`. [`/llms.txt`](https://sideagent.dev/llms.txt) lists all pages. [`/llms-full.txt`](https://sideagent.dev/llms-full.txt) has the whole documentation in one file. --- # Quickstart > Install sideagent, mount the agent on one route and render the chat in React. Source: https://sideagent.dev/docs/quickstart Install the package: ```bash npm i sideagent ``` Create the agent on your server and mount its handler on one route: ```ts import { createAgent, honoHandler } from "sideagent/server"; const agent = await createAgent({ spec: "https://api.example.com/openapi.json", baseUrl: "https://api.example.com", llm: { baseUrl: "https://api.openai.com/v1", apiKey: process.env.LLM_API_KEY!, model: "gpt-4o-mini" }, allow: ["listInvoices", "createInvoice"], allowedOrigins: ["https://app.example.com"], getAuth: (req) => ({ userId: "user-123", headers: { authorization: req.headers.get("authorization")! }, }), }); app.on(["POST", "OPTIONS"], "/agent", honoHandler(agent)); ``` Render the chat in your React app: ```tsx import { AgentChat } from "sideagent"; ``` ## Try it without an API key Clone the repo and run `pnpm demo`. It starts a fake invoices API, an agent with a mock LLM, and the UI. ## Next steps - Tune the options: [Server](https://sideagent.dev/docs/server.md). - Choose what the model may call: [Operations and allowlist](https://sideagent.dev/docs/operations.md). - Replace the hard-coded `userId`: [User authentication](https://sideagent.dev/docs/auth.md). - Skip the server: [sideagent Cloud](https://sideagent.dev/docs/cloud.md). --- # Server > createAgent options, adapters for Hono, Next.js and Express, and the doctor check. Source: https://sideagent.dev/docs/server `createAgent` is async: it parses the spec and, if you configured knowledge, embeds it. Create the agent once and reuse it. It returns an object with a request `handler` and a `doctor()` check. ## Options | Option | What it does | | --- | --- | | `spec` | OpenAPI 3.0 or 3.1: a URL, an object or a JSON string. | | `baseUrl` | Pinned API host. The spec's `servers` list is ignored. | | `llm` | `baseUrl`, `apiKey` and `model` of any OpenAI-compatible host. | | `allow` | Default-deny allowlist of operation IDs, or `tag:name`. | | `allowedOrigins` | Browser origins that may call the endpoint. | | `getAuth` | Returns the user ID and the headers to forward to your API. | | `approvalSecret` | Signs approval tokens. Set it on serverless or multi-instance deployments, so every instance verifies the same tokens. | | `checkpointer`, `threadStore` | Persistent chat history. See [Chat history](https://sideagent.dev/docs/history.md). | | `knowledge`, `vectorStore` | Markdown and URL sources the agent can search. See [Knowledge](https://sideagent.dev/docs/knowledge.md). | ## Adapters `honoHandler(agent)`, `nextRoute(agent)` and `expressHandler(agent)`. The core `agent.handler(request)` takes a standard `Request` and returns a `Response`. ## Doctor Call `await agent.doctor()` at startup. It reports what the agent can do (operations loaded, knowledge sources, warnings) and checks the LLM connection. --- # Operations and allowlist > Which API operations the model can call, and the x-agent hints you can add to your spec. Source: https://sideagent.dev/docs/operations Every operation in your spec with an `operationId` can become a tool. Only the ones you allow are exposed to the model. List IDs, or use `tag:reports` to allow a whole tag. New operations are never allowed by default. ## The x-agent extension Add hints to the spec with the `x-agent` extension on an operation: ```json "x-agent": { "approval": "required", "description": "Better text for the model than the summary", "invalidates": ["invoices"], "responseFields": ["id", "total"] } ``` - `approval`: force or skip the approval step. See [Approvals](https://sideagent.dev/docs/approvals.md). - `description`: what the model sees, in place of the spec's summary. - `invalidates`: tags the UI should refetch after the call succeeds (`hooks.onInvalidate` in the chat component). - `responseFields`: only these fields of the response reach the model and the browser. ## Limits on calls Calls use the pinned `baseUrl` and never follow redirects. Request and response sizes, the number of steps per turn and the time per turn are capped. --- # User authentication > How getAuth identifies the signed-in user and forwards their credentials to your API. Source: https://sideagent.dev/docs/auth The agent acts as the signed-in user. In `getAuth` you verify the request the way your API does, and return: ```ts getAuth: async (req) => { const user = await verifySession(req); // your code; return null to reject if (!user) return null; return { userId: user.id, headers: { authorization: req.headers.get("authorization")! } }; } ``` - `userId` scopes chat threads: a user can only see their own history. - `headers` are forwarded to your API on every tool call, so your API enforces its normal permissions. The agent never has more access than the user. ## Credentials must travel in Authorization The browser can only send `content-type` and `authorization` to the endpoint, so credentials must travel in `Authorization`. Cookies are not forwarded. --- # Approvals > How calls that change data pause for the user, and how approval tokens are bound to the exact arguments. Source: https://sideagent.dev/docs/approvals Calls that change data (anything that is not `GET`) need the user's approval. The agent pauses and the UI shows the exact call: operation, path and arguments. The user approves or rejects. - The server issues a signed approval token bound to the exact arguments. Changing an argument invalidates the token. - Tokens expire. The UI restores a pending approval after a page refresh. - Set `approvalSecret` yourself when more than one instance serves the agent. To force or skip the step for one operation, use `x-agent.approval` ([Operations](https://sideagent.dev/docs/operations.md)). --- # Knowledge > Give the agent documents it can search, from Markdown or public URLs, with a vector store. Source: https://sideagent.dev/docs/knowledge Give the agent documents it can search, so it answers questions about your product and not only your API. ```ts createAgent({ // ... knowledge: { embeddings: { model: "text-embedding-3-small" }, sources: [{ id: "guide", title: "Invoicing guide", content: markdownString }], urls: ["https://docs.example.com/payment-terms", { url: "https://example.com/shipping", title: "Shipping" }], }, vectorStore, // optional: pgvector, Vectorize, ... }); ``` The agent gets a `search_knowledge` tool. Answers show a Sources card, with links only for URLs you configured. ## Behavior - Passages reach the model as labelled untrusted data and never reach the browser. - URLs come only from config. They must be public http(s) and follow only same-host redirects. `maxSourceBytes` caps their size. - URL sources refresh in the background after `ttlMs` (default one hour), or when you call `agent.knowledge.refresh()`. - A source that fails to load is skipped with a warning, and shown in `doctor()`. - The default store is in memory, so every start embeds all sources again. Pass a persistent `vectorStore` for large knowledge. --- # Chat UI > The AgentChat and AgentProvider React components, the docked sidebar and result views. Source: https://sideagent.dev/docs/chat-ui The `sideagent` package exports React components. React 18 or later is an optional peer dependency. ```tsx import { AgentChat } from "sideagent"; tag === "invoices" && refetchInvoices() }} /> ``` ## Docked sidebar Wrap your app in `AgentProvider` to dock the chat on the right, beside the app instead of over it. It takes the same props as `AgentChat`. The user drags the panel's left edge, or uses the arrow keys on it, to resize; the width is remembered. ```tsx import { AgentProvider } from "sideagent"; ``` Anything under `AgentProvider` can call `useAgent()` to get `{ open, setOpen }`, for example an "Ask assistant" button in a toolbar. ## Results Tool results render as readable views. Arrays of objects become tables (up to 50 rows and 8 columns), objects become labelled fields, and errors get their own state. Raw JSON stays under "Details". Everything is plain text, never HTML. Override a view per operation: ```tsx }} /> ``` --- # Chat history > Persistent threads with a checkpointer and a threadStore, and the History button in the chat. Source: https://sideagent.dev/docs/history `AgentChat` has a History button (list, open, delete), reopens the last conversation after a refresh, and restores a pending approval. Messages live in your LangGraph `checkpointer`. The list of threads lives in a `threadStore`, in memory by default. Both must be persistent in production: ```ts createAgent({ /* ... */ checkpointer: new PostgresSaver(/* ... */), threadStore: myThreadStore }); ``` A `ThreadStore` implements `list`, `has`, `touch` and `delete`. History is only shown from the user's own index. --- # Theming > Match the chat to your design system with CSS variables and light or dark themes. Source: https://sideagent.dev/docs/theming The chat is neutral by default: grayscale, your font, a 10px radius. `theme="auto"` follows the OS and a host `.dark`, `data-theme="dark"` or `data-bs-theme="dark"`. Pass `"light"` or `"dark"` to force one. Match your design system with CSS variables: ```css :root { --sideagent-accent: var(--primary); --sideagent-accent-fg: var(--primary-foreground); --sideagent-bg: var(--background); --sideagent-fg: var(--foreground); --sideagent-border: var(--border); --sideagent-surface: var(--muted); --sideagent-muted: var(--muted-foreground); --sideagent-radius: 10px; --sideagent-font: inherit; } ``` --- # Wire protocol > The request bodies and server-sent events the agent endpoint speaks. Source: https://sideagent.dev/docs/protocol The endpoint takes `POST` with a JSON body. A chat turn answers with server-sent events; history actions answer with JSON. ## Requests ```ts { "threadId"?: string, "message": string, "context"?: unknown } { "threadId": string, "approval": { "token": string, "decision": "approve" | "reject" } } { "action": "threads.list" } { "action": "threads.get", "threadId": string } { "action": "threads.delete", "threadId": string } ``` ## Events in a turn | Event | Meaning | | --- | --- | | `turn.start` | Carries the `threadId`. | | `text.delta` | A piece of the assistant's text. | | `tool.start` | The agent began calling an operation. | | `approval.request` | The call needs approval. Carries the arguments, a token and an expiry. | | `tool.complete` | The call finished: HTTP status, arguments, result, and tags to invalidate. | | `tool.rejected` | The user rejected the call. | | `error` | A `code` and a `message`. | | `turn.end` | The turn is over. | --- # Security model > Default deny, user credentials, approvals, pinned host, limits, origins and redaction. Source: https://sideagent.dev/docs/security - **Default deny.** Only allowlisted operations are exposed to the model. - **User credentials.** Your API sees the signed-in user's own credentials, never a service account. - **Approvals.** Non-`GET` calls need server-verified approval, bound to the exact arguments. - **Pinned host.** API calls go to `baseUrl` only. SSRF guards block private and metadata addresses, and redirects are not followed. - **Limits.** Size, step and time limits apply to every turn. - **Origins.** Browser calls from origins you did not list are refused. - **Threads.** Chat history is bound to the user and only shown to them. - **Redaction.** Audit events are redacted. LLM keys, approval secrets and user tokens do not appear in logs or errors. - **Untrusted text.** Knowledge passages and API results are passed to the model as data, and rendered as plain text, never HTML. --- # sideagent Cloud > The hosted version: configure an agent in a dashboard and embed it with a publishable key. Source: https://sideagent.dev/docs/cloud sideagent Cloud runs the agent for you. You do not host a server or write `createAgent` code. ## Set up an agent 1. [Sign in](https://sideagent.dev/app) with your email. You get a magic link. 2. Create an agent. Each agent has its own configuration, history, limits and audit log. Test and live environments are separate agents. 3. Add instructions, knowledge sources (URLs or pasted text) and, optionally, your OpenAPI spec and the operations to allow. 4. Pick an LLM: the built-in model, or any OpenAI-compatible host with your own key. Keys are encrypted at rest and shown only as their last four characters. 5. Pick how users are identified: token verification (JWKS or a userinfo URL), a backend proxy, or anonymous for public, knowledge-only chat. 6. Add the origins that may embed the chat, then go live. ## Keys Each agent has a publishable key, safe in the browser, and up to two secret keys for server-side use. A secret key is shown once, when you create it. ## Knowledge-only agents Knowledge-only agents work without a spec. This documentation is the knowledge for the assistant on the [home page](https://sideagent.dev/), which is a sideagent Cloud agent. ## Status sideagent Cloud is in development. The dashboard, agent configuration and knowledge indexing are available. The public agent endpoint currently serves anonymous, knowledge-only agents; token verification, API calls and approvals are not yet available there.