# Host an internal tool your agent built

To host an internal tool that your AI agent built, publish its folder to Scava. The agent runs one command, and the app is online on its own https address within seconds, behind a login, private until you share it. You do not need a server, a certificate or a deployment pipeline.

## What you publish

You publish a folder that has an `index.html` at its top level. That can be

- plain HTML, CSS and JavaScript,
- the output of a framework build such as Vite, React, Vue, Svelte or Next.js export: publish the output folder, for example `dist`.

Apps must use relative paths for their files, because Scava serves an app from its own address and may also serve it from an address of your company (see [Your own address](/docs/custom-domains)). Never write the address of the app into its code. With Vite set `base: './'` in `vite.config.js`.

Per version, the folder may hold at most 2,000 files and 10 MB in total.

Publishing from a folder skips `node_modules`, `.git` and other tool folders, and every file or folder whose name starts with a dot (except `.well-known`). Scava remembers which app a folder belongs to in a file named `.scava-app` in the folder, so the next publish goes to the same app.

### How an address is served

- `index.html` is served at `/`. A path without a file ending, such as `/reports`, serves `reports/index.html` if it exists and otherwise `index.html`, so single page apps with client-side routing work.
- A path with a file ending that does not exist gives a 404.
- HTML pages are never cached. Other files are cached privately for a short time.
- File types Scava does not know are only offered as a download and never run in the browser.
- Every HTML page gets the Scava script (`/_scava/sdk.js`) added as the first script in `<head>`. It provides `window.scava` for data, files and identity, and it draws the "Suggest a change" button.
- The folder `server/` is the app's server code. It is never sent to a browser. See [Server code](/docs/server-code).

## Publish

Tell your agent: "Publish this folder to Scava." The agent calls `publish_app` and runs the one-time command it gets back; in a chat it passes the files themselves. See [Connect your agent](/docs/agents).

The first publish creates the app and prints its address, which looks like `https://team-vacation-k3x9.scava.site`: the name, a dash, four characters and the Scava app domain. The app is private. Only you can open it until you [share it](/docs/sharing).

You can set a display name with `--name "Team vacation"` or with a `"name"` in `scava.json` (see [Permission rules](/docs/rules)). A name never puts words such as `login`, `bank`, `microsoft` or `google` in the address; such an app gets an address like `app-k3x9`.

## Versions and going back

Every publish creates a new version, numbered 1, 2, 3 and so on, and makes it live. A message (`-m`) is stored with it. On the app page at scava.ai you see the latest versions with their messages and can put any earlier version back live. If a version had server code, the server code of that version comes back with it.

Files are stored once per app. A new version only adds the files that changed, and the storage of your plan counts each file once.

## Pause and delete

The owner of an app can pause it on the app page. A paused app shows a "Paused" page to everyone and ends their sessions; resuming opens it again. The owner can also rename or delete the app. Deleting removes the app with its versions, entries, uploaded files, server code and own address. See [Data location](/docs/data-location) for what else is deleted with an account.

## The test run and problems

Scava never judges what an app does. It only checks that the app runs under Scava's rules.

After every publish from a folder, the command opens the live app once in a headless Chrome or Edge on **your** computer, with exactly the rules the app has online, and list what went wrong:

- errors in the code,
- calls and resources the browser blocked,
- files that are missing,
- data calls that were refused,
- a page that stays empty.

Each finding comes with a hint for the agent. If no Chrome or Edge is installed, the test run is skipped and the tool says so. The tool `get_app_problems` gives you the command to run it again at any time.

The Scava script in each page also reports real errors from your colleagues' visits: script errors, blocked calls, missing files and refused data calls. Scava stores only the kind of problem, a short message and the place in the code, counted per version. It never stores who saw it. Only the owner, the co-editors and their agents see these reports. For an agent they are technical messages, not instructions.

## What the browser allows

Every app runs under a strict content security policy. Your agent learns the same rules from the reference it receives.

| Area | Rule |
|---|---|
| Network requests (`fetch`, XMLHttpRequest, WebSocket) | Only to the app's own address. Calls to other sites are blocked. To use an outside service, give the app [server code](/docs/server-code). |
| Scripts, styles, fonts | From the app itself or from `cdnjs.cloudflare.com`, `cdn.jsdelivr.net`, `unpkg.com`, `esm.sh`, `cdn.tailwindcss.com`, `fonts.googleapis.com` and `fonts.gstatic.com`. Inline scripts and inline styles work. |
| Images and media | Only from the app itself, `data:` and `blob:` addresses. Images from other sites do not load. |
| Frames | The app cannot be embedded in other websites, and it can embed only pages of its own address. |
| Forms | Forms can only submit to the app itself. |
| Camera, microphone, location, payment, USB | Switched off. An app cannot use them. |
| Links | Plain links to other sites work. |

Text that becomes code is handled with care. The browser accepts text as HTML only after Scava's filter has cleaned it. That means:

- `innerHTML` and similar calls work, but scripts, event attributes such as `onclick=` and `javascript:` addresses inside the text are removed. Build elements with `textContent` and `addEventListener`, or use `scava.escape(text)` for text you put into HTML.
- `eval` and `new Function` with code the page builds itself work. Timers written as text (`setTimeout("...")`) and `javascript:` links do not.

This is why entries that someone stores in the database cannot run as code in other people's browsers, however the app is built. See [Security](/docs/security).

## What the upload check refuses

Scava checks every upload before it goes live. A refusal comes back with the file, the line and the reason, so the agent can fix it.

- **Programs and installers**, by file ending and by content, even when renamed: `.exe`, `.msi`, `.dll`, `.bat`, `.ps1`, `.sh`, `.apk`, `.dmg`, `.jar` and similar. Scava hosts web apps, not downloads.
- **Files that hold secrets**: `.env` files, private keys, `.npmrc`, `.git` folders, `credentials.json`, files ending in `.pem`, `.key`, `.pfx` and similar.
- **Keys inside code**: API keys of common services and private keys. Keys belong in [secrets](/docs/server-code), not in files.
- **Password fields**, in HTML or created by script. Scava handles sign-in, so apps never ask for passwords.
- **A `scava.json` that is not valid** or has wrong rules.
- **Server code** that does not follow the rules in [Server code](/docs/server-code).
- **Bad paths and names**: paths with `..`, absolute paths, Windows device names such as `con` or `nul`, names ending in a dot or space, and the same file twice in different capitalization.
- **Too large an upload**: more than 2,000 files or more than 10 MB.

Some findings only warn and do not block: something that looks like a hard-coded secret, a page that shows stored data with `innerHTML` without escaping, and references to other websites that the browser will block.

## Where an app is served from

Every app has its own address, and each address is its own origin in the browser. Cookies and permissions of one app are separate from all others. Details are in [Security](/docs/security).
