Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Custom Runtime Apps

A deployed agent serves Amodal's shared chat shell unless its repository ships its own single-page app. Enable a custom app in amodal.json:

{
  "name": "investor-relations",
  "version": "0.1.0",
  "runtimeApp": {
    "custom": true,
    "build": "npm run build",
    "dist": "dist"
  }
}
FieldDefaultDescription
customrequiredtrue builds and serves the repository's app. false uses the shared shell.
buildnpm run buildBuild command, run from the app folder after dependencies install.
distdistBuild output directory that Amodal serves.

The app lives in the folder holding amodal.json, which is the repository root unless deploy settings set a root directory. It sits beside package.json and the amodal/ agent directories.

Build

Dependencies install with npm: npm ci when a package-lock.json is present, otherwise npm install. Commit a package-lock.json for pinned installs. A pnpm-lock.yaml is discarded, together with any package-lock.json beside it. The build command runs with a five-minute timeout and with VITE_RUNTIME_URL set to an empty string.

The deploy fails when the build command fails or the dist directory is missing. Read the build logs with GET /api/builds/:id/logs, fix the source, and redeploy. See Deployment API.

Amodal serves the deployed app from the agent's URL. Browser routes return index.html, and asset routes return the requested file.

Runtime URL

Make same-origin API calls. Derive the runtime URL from window.location.origin in browser code, and use VITE_RUNTIME_URL only for local development against a remote runtime. Requests such as /chat/stream and /api/stores/investors then reach the agent's own origin.

A runtime URL that is undefined when a request is built produces undefined/chat/stream, which the agent origin answers with the app's HTML. @amodalai/react rejects that response, and any stream response that is not text/event-stream, with an SSEStreamError naming the URL, status, and content type.

Minimal Wiring

npm install @amodalai/react react react-dom
// src/App.tsx
import '@amodalai/react/style.css';
import { AmodalProvider, AmodalChat } from '@amodalai/react';
 
const runtimeUrl = window.location.origin;
 
export function App() {
  return (
    <AmodalProvider runtimeUrl={runtimeUrl}>
      <AmodalChat />
    </AmodalProvider>
  );
}

AmodalChat uses the provider's runtimeUrl but not its getToken. When you authenticate with getToken, pass it to both components.

Chat requires runtime authentication even when the app is public:

  • Hosted team login: make same-origin calls and omit getToken. The edge authenticates requests with the session cookie.
  • Product login: point the SDK at an application proxy that holds runtime credentials and authorizes each scope, session, and operation. Return your application token from getToken.
  • Public app: keep persistent keys on a backend. Public app access does not authorize chat or mint a token.

See Authentication, Embedding, and the React SDK.

Default chat uses the deployed agent definition. To limit its skills, connections, stores, and tools, declare agents/default/. See Agents.