# Web (app.codai.ro) (/docs/apps/web)

The desktop interface in a browser tab — sign in with your codai account, chat anywhere, and run agents on a desktop that is signed in with the same account.

[app.codai.ro](https://app.codai.ro) is the **same app as codai desktop**, built for the browser. Same chat, same sessions, same settings — but a browser has no file system, no shell and no terminal, so anything that needs those runs on a **host**: one of your desktops with codai desktop open. Until a host is online the web app is *chat only*.

The same app is also served at [chat.codai.ro](https://chat.codai.ro) — an identical copy on a second address. Each address signs in **separately**: the browser keeps the key per site, so signing in on `app.codai.ro` does not sign you in on `chat.codai.ro`, and each appears as its own device.

## What works in the browser [#what-works-in-the-browser]

| Works | Needs a desktop host | Not available on the web |
| --- | --- | --- |
| Chat with `codai`, model picker, effort slider | File tools (read, edit, diff review) | Integrated terminal (PTY) |
| Shared sessions: list, live transcript, send / answer / cancel | Shell commands | Embedded browser tab |
| Settings, keybindings, skins | Tasks that dispatch to a desktop | Computer control (Windows apps) |
| Devices, cost card, memory browser | | Local models (Ollama, LM Studio) |
| Sign-in and key management | | Auto-updater (the site is always current) |

## Sign in [#sign-in]

<Steps>
<Step>

### Before you start [#before-you-start]

Accept the Terms and Privacy Policy. Consent is stored in this browser; clearing site data brings the gate back.

</Step>
<Step>

### Continue in browser [#continue-in-browser]

The page redirects **in the same tab** to [auth.codai.ro](https://auth.codai.ro) — Google or email, with PKCE. When you return to `app.codai.ro/callback` the account has issued a `codai_` key for **this browser**, labelled `OAuth · codai app` in the hub.

Prefer a key you already have? **I have an API key** accepts a `codai_…` from [hub.codai.ro](https://hub.codai.ro) → **Keys**.

</Step>
<Step>

### Where the key lives [#where-the-key-lives]

In this browser's `localStorage`, scoped to `app.codai.ro`, together with a stable **device id** for this browser profile. It is sent only as an `Authorization` header to the gateway URL in Settings (default `https://ai.codai.ro`). Nothing else on the page reads it.

</Step>
</Steps>

### Revoking the browser's key [#revoking-the-browsers-key]

Every browser profile that signed in appears as a device. Revoke it from [hub.codai.ro](https://hub.codai.ro) → **Security → Devices**, or from any signed-in client under **Devices**. **Settings → Sign out** in the web app also revokes it. If the sign-in finished at the IdP but the gateway was unreachable, the app saves nothing and tells you so — the unused key still exists in the hub and can be revoked there.

## Connect a desktop — "Run on" [#connect-a-desktop--run-on]

<Callout type="info">
**Chat only in the browser** — you will see this card until a host is online. *Install the desktop app to run agents locally, or connect a host — the browser can drive a desktop that is signed in with the same account.*
</Callout>

1. On a computer, install [codai desktop](./desktop.mdx) and sign in with the **same account**.
2. **Settings → Executor → Serve as a remote host for my phone** — the status bar shows *Relay: online*.
3. Back in the browser, the composer gains a **Run on** picker listing your online desktops (hostname, OS, last seen). Pick one.

From now on file and shell tools in this chat execute **on that desktop**, inside its approved folders, with its ask cards. The browser shows every step. If the host goes offline mid-task the tool call fails with *No host connected — install the desktop app or pick a host.*

A host must have been seen in the last **45 seconds** to be listed. Hosts are per-account: nobody else's desktops appear, and yours never appear to anyone else. The underlying relay is documented on the [hosts relay](../sessions/hosts.mdx) page.

## Limitations [#limitations]

- **No local execution.** Without a host, tool calls that touch files or a shell are refused; the model is told so and answers in chat.
- **One key per browser profile.** Incognito windows and other browsers are separate devices.
- **Sessions follow the account, settings follow the browser.** Skins, keybindings and gateway URL live in `localStorage`; sessions and memory live on the gateway.
- **Self-hosted gateways** must allow the `https://app.codai.ro` origin for `/v1/*` (CORS) and register `https://app.codai.ro/callback` as a redirect URI on the IdP.

## Troubleshooting [#troubleshooting]

<Accordions>
<Accordion title="“Signed in, but the gateway is unreachable”">
Your account issued a key, but the gateway URL in Settings did not answer, so nothing was saved. Check **Settings → Gateway URL** (default `https://ai.codai.ro`), then **Try again** — the app retries with the same key instead of minting another. The unused key can be revoked from hub → Security → Devices.
</Accordion>
<Accordion title="“Device id is registered to another account”">
The device id stored in this browser profile was first registered under a different codai account — typically because two accounts signed in from the same browser profile (two tabs share `localStorage`). The gateway refuses to re-bind a device id to a second account. **Sign out does not reset the device id.** Fix: use a separate browser profile per account, or clear site data for `app.codai.ro` (this removes the stored key, settings and the device id — the old device stays listed in the hub until you revoke it).
</Accordion>
<Accordion title="No hosts online, but the desktop is running">
On the desktop check **Settings → Executor → Serve as a remote host** is on and the status bar says *Relay: online*, not *connecting* or *retrying*. Both must be signed in with the same account. A host that has not heart-beaten for 45 s drops off; reload the picker.
</Accordion>
<Accordion title="The Before-you-start screen keeps coming back">
Consent is stored in this browser's site data for `app.codai.ro`. Extensions that clear storage on close, or strict tracking protection, wipe it every session. Allow site data for `app.codai.ro`.
</Accordion>
<Accordion title="Sign-in loops or lands on an error page">
The PKCE state lives in `sessionStorage` and is consumed on the first return. Reloading the callback page replays it and fails. Start again from `app.codai.ro`; if a corporate proxy strips cookies for `auth.codai.ro`, sign in from another network or paste a key instead.
</Accordion>
</Accordions>

<Cards>
  <Card title="Desktop" href="./desktop.mdx" description="Set up the host side." />
  <Card title="Hosts relay" href="../sessions/hosts.mdx" description="The protocol behind Run on." />
  <Card title="Connect flow" href="../auth/connect-flow.mdx" description="How the IdP mints a key for a device." />
</Cards>
