# Set up Copilot

> Put Giov Copilot in your signed-in dashboard in three steps, then publish. In most cases no backend changes are needed.

Setup happens in **Giov Copilot → Overview**. On your first visit a setup guide opens. It checks the [requirements](/docs/copilot#requirements), walks you through the three steps below, lets you try Copilot on your own dashboard, and ends with publishing. It takes about 10 minutes, and nothing goes live until you publish.

First, choose the assistant: a published GiovBot agent. The default agent is preselected.

## Set it up with your AI editor

If you build with Cursor, Claude Code, Codex, Windsurf, Lovable, Bolt, v0 or Replit, your AI editor can write the code for you. Paste the prompt below into it. The prompt adds the widget once, computes `userHash` on your server, passes the signed-in user to the widget, fits the panel into your dashboard layout and adds an **Ask AI** button, then reports the files it changed.

For a prompt with your own settings filled in (website address, paths, side and docking), finish step 1 and choose **Giov Copilot → Website setup → Copy prompt**. The version below uses the defaults: Copilot on the right, sharing the screen. The prompt never contains your identity secret; add `GIOV_IDENTITY_SECRET` to your server's environment yourself.

```text title="Prompt for your AI editor"
Set up Giov Copilot in this project. Copilot is an AI assistant that docks beside the signed-in dashboard, answers questions about it and runs the tasks the workspace approved, as the signed-in user.

Workspace ID: YOUR_WORKSPACE_ID
App address: set it in Giov: Copilot setup, step 1
Copilot pages: /dashboard (each path includes everything under it)
Panel side: right (the navigation goes on the left)
When docked: shares the screen (the dashboard narrows to make room)
Floating button: on

Before changing anything, read the project and find:
- the framework and its root layout (index.html, app/layout.tsx, pages/_app.tsx, src/routes/+layout.svelte, App.vue or similar);
- where the server knows the signed-in user (session, loader, API route, middleware);
- the dashboard shell: the element that wraps the navigation or sidebar, the top bar and the main content on the Copilot pages.

1. Widget script, once. If the Giov widget is not installed yet, load it once from the root layout:
   <script src="https://widget.giovchat.app/YOUR_WORKSPACE_ID" async></script>
   If it is already installed, keep it. Never add a second script tag or a second ChatWidget.init call.

2. User identity, on the server only. Compute userHash for the signed-in user: the lowercase hex HMAC-SHA256 of the user's id, keyed with the workspace identity secret read from server configuration as GIOV_IDENTITY_SECRET. In Node.js:
   createHmac("sha256", process.env.GIOV_IDENTITY_SECRET).update(String(user.id)).digest("hex")
   If the app has no server of its own (a static, Supabase or Firebase app), add a small server function (an API route, edge function or cloud function) that verifies the user's session and returns { userId, userHash, firstName }.
   Never send the secret to the browser, never give it a NEXT_PUBLIC_, VITE_ or PUBLIC_ prefix, and never commit it. Add GIOV_IDENTITY_SECRET= with an empty value to the example env file.

3. Pass the signed-in user to the widget on every Copilot page.
   - Server-rendered pages: before the widget script, render
     window.GiovChatSettings = { userId: "USER_ID", userHash: "USER_HASH", firstName: "FIRST_NAME" };
   - Single-page apps: when the user is signed in (on load and after sign-in) call ChatWidget.identify({ userId, userHash, firstName }) with the values from your server. On sign-out call ChatWidget.identify(null), then await ChatWidget.resetSession().
   window.ChatWidget exists once the script has loaded, and the window event "giov:modechange" fires when the widget starts; guard calls that can run earlier.
   firstName is optional and display-only, so Copilot greets people by name; leave it out if unsure.

4. Dashboard layout (desktop). Copilot docks on the right and the page gives up the panel's width, like a built-in assistant; nothing is covered. The finished layout is:
   navigation | main content | Copilot
   - Copilot belongs on the side opposite the navigation. If this dashboard's navigation is on the right, stop and tell me: the side is a Giov setting (Copilot setup, step 1), not something to change in code.
   - Make the dashboard shell (the one element around the navigation, the top bar and the main content) able to shrink: flex or grid with min-width: 0 on the main column, and no 100vw or fixed pixel widths on the shell or main column. Fix any table or chart that forces a minimum width.
   - Register the shell when it mounts and release it when it unmounts (use the framework's ref or the shell's own id instead of app-shell). The widget can load after your layout, so attach again when it reports its mode:
     // The element that holds your navigation, header and main content.
     const shell = document.getElementById("app-shell");
     const attach = () => window.ChatWidget?.setLayoutTarget(shell);

     attach();
     window.addEventListener("giov:modechange", attach); // the widget has started

     // When the shell unmounts
     window.removeEventListener("giov:modechange", attach);
     window.ChatWidget?.setLayoutTarget(null);
   - position: fixed elements (a fixed sidebar, a top bar, drawers, sheets, toasts) don't follow the shell's width. Position them with the variables Copilot sets while it is docked (0px otherwise):
     /* Copilot sets these while it is docked; they are 0px otherwise. */
     .app-sidebar {            /* a fixed navigation on the left */
       left: var(--giov-copilot-inset-left, 0px);
     }
     .app-topbar {             /* a fixed header across the page */
       left: var(--giov-copilot-inset-left, 0px);
       right: var(--giov-copilot-inset-right, 0px);
     }
     .app-drawer {             /* a drawer or sheet on the right */
       right: var(--giov-copilot-inset-right, 0px);
     }
     .app-toasts {             /* toasts in the bottom-right corner */
       right: calc(1rem + var(--giov-copilot-inset-right, 0px));
     }
   - Do not add an overlay, a placeholder column, padding or your own resize logic for the panel. Copilot restores every style when it closes, collapses or the user signs out.

5. Phones and tablets: build nothing extra. On phones Copilot opens full screen with a way back to the page, and on tablets and small windows the docked panel floats over the edge of the page.

6. Ask AI button. Add it to the dashboard top bar, next to search or the profile menu.
   <button type="button" data-giov-copilot>Ask AI</button>
   Any element with data-giov-copilot opens Copilot docked and closes it on the next click; it needs no other code. Style it like the app's other top-bar buttons.

7. API access. Copilot runs approved actions from the user's browser with their own session. Only if the API authenticates with a header token instead of cookies, register it:
   ChatWidget.setAuthHeaders(() => ({ Authorization: `Bearer ${getAccessToken()}` }));

8. Check your work. Run the project's type check, linter and build, and fix anything you broke. Then tell me how to test it: sign in, open /dashboard, select Ask AI. On a wide screen the dashboard narrows beside the panel instead of being covered, fixed elements stay visible, and closing the panel restores the layout; at phone width Copilot opens full screen.

Report the files you changed and anything you could not do. Do not deploy, do not create or rotate secrets, and do not change Giov settings yourself.
```

## Step 1: Where Copilot appears

| Setting | What to enter |
|---|---|
| Website address | Where your app runs, for example `https://app.example.com`. Put each address on its own line. Use `https`; plain `http` is accepted only for `localhost`. |
| Dashboard paths | Where Copilot appears, for example `/dashboard`. Each path covers itself and everything under it: `/dashboard` matches `/dashboard/orders`, but not `/dashboardish`. Up to 10 paths, without wildcards, queries or fragments. |
| Side of the screen | Left or right, for the docked panel. Choose the side opposite your navigation: right (the default) for a navigation on the left. |
| When docked | **Share the screen** (default): your page narrows to make room for the panel, like a built-in assistant. **Float over the page**: the panel covers the edge of your page. |
| Panel width | The docked panel's width as a percent of the screen, from 20 to 50. The default is 28. Users can still drag its edge. |
| Floating button | On by default. Turn it off if you want Copilot to open only from your own buttons. |

Everywhere outside these paths, your normal support chat stays as it is.

### How the docked panel shares the screen

With **Share the screen**, the docked panel takes its width out of your page instead of covering it, like the assistants built into most modern dashboards. On a wide screen your dashboard ends up in three columns:

| Navigation on the left (Copilot on the right) | Navigation on the right (Copilot on the left) |
|---|---|
| Navigation, then your page, then Copilot | Copilot, then your page, then navigation |

Copilot finds the element to narrow by itself: your app's root wrapper (such as `#root`, `#__next` or `#app`, or the one full-width element under `<body>`), or the page body when there is no single wrapper. Your main column needs to be able to shrink: use flex or grid with `min-width: 0`, and avoid `100vw` or fixed pixel widths. Closing or collapsing the panel puts your layout back exactly as it was.

You don't build anything for smaller screens. On phones Copilot opens full screen, with a way back to the page. On tablets and small windows, where there isn't room for both, the docked panel floats over the edge of the page instead of squeezing it.

Elements with `position: fixed` (a fixed header, a side navigation, sheets, toasts) don't follow their parent's width. Keep them clear of the panel with the CSS variables Copilot sets while it's docked:

```css title="dashboard.css"
.fixed-header { left: var(--giov-copilot-inset-left, 0px); right: var(--giov-copilot-inset-right, 0px); }
.side-navigation { left: var(--giov-copilot-inset-left, 0px); }
.toasts { right: calc(1rem + var(--giov-copilot-inset-right, 0px)); }
```

If Copilot picks the wrong element, point it at your dashboard wrapper, the element that holds your header, navigation and content, with `ChatWidget.setLayoutTarget(element)`, or set its ID under **Advanced**.

### Open Copilot from your own button

Add `data-giov-copilot` to any element. No other code is needed:

```html title="dashboard.html"
<!-- Any element with data-giov-copilot opens Copilot when clicked -->
<button data-giov-copilot>Ask AI</button>

<!-- Pick the view: docked (default), compact or fullscreen -->
<button data-giov-copilot="compact">Ask AI</button>
<button data-giov-copilot="fullscreen">Ask AI</button>
```

Clicking the element again closes Copilot. On pages where Copilot isn't active, it opens the support chat. From your own scripts, you can do the same with `ChatWidget.open({ view })`, `ChatWidget.close()` and `ChatWidget.toggle({ view })`.

## Step 2: Who is signed in

Copilot only answers for a user your server vouches for. Your server computes a `userHash` for the signed-in user, and your page passes it to the widget along with the user's ID. This is the same identity verification the support widget uses, so you may already have it in place.

Follow [Identify signed-in users](/docs/copilot/identity) for the code.

## Step 3: What Copilot can do

Copilot needs to know which requests your app makes. Use any of these three ways; you can combine them.

### Find my API docs

Copilot looks for an OpenAPI file at the usual addresses on your website and API, such as `/openapi.json`, `/swagger.json`, `/v3/api-docs` and `/.well-known/openapi.json`. You can also give it a specific address. The step lists every address it checked. If it finds a file, the file is added to your catalog.

### Learn from my dashboard

1. Choose **Start learning**. Your dashboard opens in a new tab with a "Learning your dashboard" bar. Seeing the bar also confirms that the widget and your paths are set up correctly.
2. Use your dashboard as normal: open pages, filter lists and open records.
3. Come back and choose **Stop learning**. Learning ends on its own after 30 minutes.

The **Requests seen** list shows each request with its method, a path template such as `/orders/{orderId}`, and the pages it was seen on. You can remove requests one by one or all at once.

> [!NOTE]
> Learning records structure, never values. It keeps path templates, field names and types, the page, and the label of the button that was clicked. It never keeps header values, cookies, query values or any field value. It also skips sign-in, sign-out, token and password requests.

### Import a file

Upload an OpenAPI or Postman file, paste one, or give a link.

### Generate and approve actions

1. Choose **Generate actions** to turn learned requests into suggested actions. Each one gets a name, a description, inputs, a risk level and a permission group. Endpoints that came from API docs or files are already suggested.
2. Choose **Review and approve suggested actions**. This opens the catalog, where you can choose **Approve all** or approve actions one by one.
3. To adjust levels later, or remove actions, use **Giov Copilot → Permissions**.

Nothing runs until it's approved. For the levels (View, Change, Sensitive), see [Permission levels](/docs/copilot#permission-levels).

### Learn from signed-in users (optional)

Turn on **Ask signed-in users to help improve Copilot** to let real usage suggest more actions.

- Each user is asked once, in the Copilot panel.
- It's opt-in: nothing is recorded unless the user chooses Allow.
- Users can turn it off at any time from the same panel.
- Only the structure of requests is recorded, never values.

## How actions run

When a user asks Copilot to do something, Giov plans the action on its servers. It checks the inputs and the permission level, and asks the user to confirm where needed. The widget then sends that exact request from the user's browser, with the user's existing session.

- Requests go only to the origins of your approved actions.
- Your backend sees an ordinary request from a signed-in user and applies its usual permissions.
- Redirects aren't followed, and each request times out after 20 seconds.
- A change whose result is unclear is never retried automatically.

If your API authenticates with a header token instead of cookies, register it with `setAuthHeaders`. See [API token headers](/docs/copilot/identity#api-token-headers).

> [!TIP]
> If your API is on a different origin from your dashboard, it has to accept credentialed requests from your dashboard's origin. Your own frontend already makes those same requests, so this is usually in place.

## Try it and choose shortcuts

The setup guide's **Try it** stage opens your dashboard in learning mode, so you can check that everything is connected. You also choose the default shortcuts, which are one-click buttons users see when they open Copilot:

- What can you do here?
- Summarize this page
- Find something
- Help me with a task

Turn off any you don't want. You can add your own, and review suggested shortcuts, in **Giov Copilot → Shortcuts**.

## Publish

1. Choose **Publish** at the bottom of the Overview. The review shows what will go live: the assistant, website, identity method, actions, shortcuts and learning setting.
2. Reload your website once, so the widget picks up the change.
3. Sign in to your app, open a dashboard path and open Copilot.

Publishing doesn't change your support chat. Users who are already signed in to Copilot reconnect after you publish. Unpublished edits aren't live, and pausing Copilot stops further task steps immediately.

**Giov Copilot → Activity** shows how Copilot is being used: sessions, questions, actions and handoffs.

## Server-to-server connections

By default, every action runs in the user's browser. Some calls need credentials that only your backend holds, or permissions beyond the user's own. For those, **Giov Copilot → Advanced** offers server connections: an HTTP API with stored credentials, or a remote MCP server. Server connections need the [signing-key identity](/docs/copilot/identity#signing-key-identity-advanced).

> [!NOTE]
> Public documentation for server connections is coming. Until then, see **Giov Copilot → Developer guide** in your dashboard.
