> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qredence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Fleet Pi configuration reference

> Reference for every Fleet Pi environment variable — LLM provider keys, Pi runtime, logging, auth, and the Neon Postgres chat session mirror.

Fleet Pi loads configuration from `.env` at the repo root, then `.env.local` (`.env.local` takes precedence). The dev server is responsible for loading these files into the server-side routes; values are accessed through `process.env` at runtime. Credentials saved from the in-app Configurations panel are written to `.env.local`.

The canonical example lives in [`.env.example`](https://github.com/Qredence/fleet-pi/blob/main/.env.example). This page is the authoritative reference for every variable Fleet Pi reads, grouped by concern.

## LLM providers

Fleet Pi picks the default model by surface:

* **Local dev and anonymous chat** default to Google Gemini (`gemini-3.5-flash`). Set `GEMINI_API_KEY` to use it, or pick another provider from the in-app config panel.
* **Deployed authenticated chat** defaults to the [Neon AI Gateway](#neon-ai-gateway-default-authenticated-chat) with `qwen35-122b-a10b` as the primary model and `gpt-oss-120b` also enabled. A user's OpenAI-Chat-Completions (OCC) BYOK setting always takes precedence when configured.

Pi settings store the active provider and model, and you can change both from the in-app config panel. The same panel manages provider API keys and writes them to `.env.local`.

| Provider       | Provider ID      | API key variable                  |
| -------------- | ---------------- | --------------------------------- |
| Google Gemini  | `google-genai`   | `GEMINI_API_KEY`                  |
| Amazon Bedrock | `amazon-bedrock` | `AWS_ACCESS_KEY_ID` (+ AWS chain) |
| OpenAI         | `openai`         | `OPENAI_API_KEY`                  |
| Anthropic      | `anthropic`      | `ANTHROPIC_API_KEY`               |
| Google Vertex  | `google-vertex`  | `GOOGLE_APPLICATION_CREDENTIALS`  |
| Mistral        | `mistral`        | `MISTRAL_API_KEY`                 |
| Groq           | `groq`           | `GROQ_API_KEY`                    |
| Ollama         | `ollama`         | `OLLAMA_BASE_URL`                 |

### Amazon Bedrock

When using Bedrock, Fleet Pi uses the standard AWS credential chain — environment variables, profile, or IAM role.

Fleet Pi defaults to **Google Gemini** (`gemini-3.5-flash`). The default provider and model are set in `.pi/settings.json`:

```json theme={null}
{
  "defaultProvider": "google",
  "defaultModel": "gemini-3.5-flash"
}
```

Change those fields to switch the default provider; set the matching API key in `.env` (or via the in-app config panel). Every provider supported by Pi is available — pick whichever credentials you already have.

| Provider         | `defaultProvider` value | Credential variable                                               |
| ---------------- | ----------------------- | ----------------------------------------------------------------- |
| Google Gemini    | `google`                | `GEMINI_API_KEY`                                                  |
| Google Vertex AI | `google-vertex`         | `GOOGLE_APPLICATION_CREDENTIALS` (path to a service account)      |
| OpenAI           | `openai`                | `OPENAI_API_KEY`                                                  |
| Anthropic        | `anthropic`             | `ANTHROPIC_API_KEY`                                               |
| Amazon Bedrock   | `amazon-bedrock`        | Standard AWS credential chain (`AWS_PROFILE`, env vars, IAM role) |
| Mistral          | `mistral`               | `MISTRAL_API_KEY`                                                 |
| Groq             | `groq`                  | `GROQ_API_KEY`                                                    |
| Ollama           | `ollama`                | `OLLAMA_BASE_URL`                                                 |

### Amazon Bedrock (opt-in)

When `defaultProvider` is `amazon-bedrock`, Fleet Pi uses the standard AWS credential chain:

| Variable                   | Required | Default     | Purpose                                                               |
| -------------------------- | -------- | ----------- | --------------------------------------------------------------------- |
| `AWS_REGION`               | No       | `us-east-1` | Region for every Bedrock call. Models must be enabled in this region. |
| `AWS_PROFILE`              | No       | —           | Use a named AWS profile from `~/.aws/credentials`.                    |
| `AWS_BEARER_TOKEN_BEDROCK` | No       | —           | Set only if your Bedrock setup uses bearer-token authentication.      |

You can also provide `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` directly. Bedrock model IDs use region prefixes such as `us.anthropic.claude-sonnet-4-6`.

## Pi runtime

| Variable                  | Required | Default    | Purpose                                                                                       |
| ------------------------- | -------- | ---------- | --------------------------------------------------------------------------------------------- |
| `PI_AGENT_DIR`            | No       | Pi default | Override the Pi agent resource directory. Read in `server-runtime.ts` and `server-shared.ts`. |
| `FLEET_PI_RUNTIME_TTL_MS` | No       | `600000`   | How long a Pi runtime stays warm between chat turns (10 minutes by default).                  |
| `FLEET_PI_REPO_ROOT`      | No       | `cwd`      | Override the project root that the workspace server treats as canonical.                      |

## Logging

| Variable    | Required | Default | Purpose                                                               |
| ----------- | -------- | ------- | --------------------------------------------------------------------- |
| `LOG_LEVEL` | No       | `info`  | Pino log level. Logs are pretty-printed unless `NODE_ENV=production`. |
| `NODE_ENV`  | No       | —       | Controls pretty-printing and a few Vite behaviors.                    |

The logger lives in [`apps/web/src/lib/logger.ts`](https://github.com/Qredence/fleet-pi/blob/main/apps/web/src/lib/logger.ts). It includes PII redaction and emits a `requestId` correlation ID for every chat request, which lines up with provider circuit-breaker events for incident review.

## Authentication (Better Auth)

Auth is **disabled** until you set `BETTER_AUTH_SECRET`. When the secret is present, Better Auth is mounted at `/api/auth/*`. The auth store can be local SQLite (default) or Neon Postgres.

| Variable                               | Required when auth enabled | Default                 | Purpose                                                                    |
| -------------------------------------- | -------------------------- | ----------------------- | -------------------------------------------------------------------------- |
| `BETTER_AUTH_SECRET`                   | Yes                        | —                       | Signing secret. Generate with `openssl rand -base64 32`.                   |
| `BETTER_AUTH_URL`                      | No                         | `http://localhost:3000` | Base URL used for OAuth callback URLs.                                     |
| `BETTER_AUTH_TRUSTED_ORIGINS`          | No                         | `BETTER_AUTH_URL`       | Comma-separated list of trusted origins for the auth router.               |
| `AUTH_DATABASE_PATH`                   | No                         | `.fleet/auth.sqlite`    | SQLite database path used when Neon auth is not configured.                |
| `FLEET_PI_AUTH_DATABASE_URL`           | No                         | —                       | Neon Postgres connection string (app role — DML only) for the auth DB.     |
| `FLEET_PI_AUTH_MIGRATION_DATABASE_URL` | For migrations             | —                       | Direct `neondb_owner` connection used by `pnpm --filter web auth:migrate`. |
| `GOOGLE_CLIENT_ID`                     | No                         | —                       | Enables Google OAuth when paired with `GOOGLE_CLIENT_SECRET`.              |
| `GOOGLE_CLIENT_SECRET`                 | No                         | —                       | Required with `GOOGLE_CLIENT_ID`.                                          |

The Google login button is hidden in the UI when either Google variable is missing. When `FLEET_PI_AUTH_DATABASE_URL` is set, Better Auth uses Neon instead of local SQLite — apply schema once per environment with `pnpm --filter web auth:migrate`.

## Neon Managed Auth (optional)

Fleet Pi runs Better Auth by default. Set `NEON_AUTH_BASE_URL` (or the `NEON_AUTH_URL` value that the Vercel↔Neon integration injects) to proxy sign-in, session, and account routes to [Neon Managed Auth](https://neon.tech) instead. Leaving both URLs unset keeps the Better Auth + SQLite fallback, so local anonymous chat still works. Use Managed Auth when you want Neon to own user identity across the app and the dual-host chat runtime.

| Variable                  | Required when Managed Auth is on | Default              | Purpose                                                                                                                                                                         |
| ------------------------- | -------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEON_AUTH_BASE_URL`      | Yes (server-side)                | —                    | Server-side base URL of your Neon Managed Auth endpoint. Falls back to `NEON_AUTH_URL` from the Vercel↔Neon integration.                                                        |
| `VITE_NEON_AUTH_URL`      | Yes (browser)                    | —                    | Browser-visible Neon Managed Auth URL. Required so the client can obtain and refresh JWTs.                                                                                      |
| `NEON_AUTH_JWKS_URL`      | Yes                              | derived              | JWKS endpoint used to verify bearer JWTs on the server. Defaults to `${NEON_AUTH_BASE_URL}/.well-known/jwks.json`.                                                              |
| `NEON_AUTH_ISSUER`        | Yes                              | —                    | Expected `iss` claim on bearer JWTs. Required whenever Neon Managed Auth is configured (and whenever `VITE_FLEET_PI_CHAT_RUNTIME_URL` is set) so JWT verification fails closed. |
| `NEON_AUTH_COOKIE_SECRET` | No                               | `BETTER_AUTH_SECRET` | Cookie signing secret (≥32 chars). Falls back to `BETTER_AUTH_SECRET` when unset.                                                                                               |
| `NEON_DATA_API_URL`       | No                               | —                    | Optional Neon Data API base URL. Not required for the chat runtime or Pi mirror.                                                                                                |

<Warning>
  Neon Managed Auth currently allows open sign-up. Until Neon ships restricted signups, treat any production deployment as an **invite-only closed beta** — share the URL only with intended testers, and keep the Neon Data API disabled in both `neon.ts` (`dataApi: false`) and the Neon console. Fleet Pi enforces tenant isolation through the private `fleet_pi_app` role plus FORCE RLS on `pi_*` tables; granting Data API access to `authenticated` or `anonymous` roles bypasses that. `pnpm verify-deployment-readiness` fails when those grants are still present.
</Warning>

## Neon AI Gateway (default authenticated chat)

On deployed environments, authenticated chat routes through the **Neon AI Gateway** as the platform OpenAI-Chat-Completions (OCC) backend. This gives every signed-in user a working model out of the box — no BYOK required — while a user who has saved their own OCC provider settings still takes precedence.

Fleet Pi enables two Gateway models by default:

* `qwen35-122b-a10b` — primary
* `gpt-oss-120b`

Use the Gateway when you want authenticated users to have working chat immediately after login without asking each user to bring an API key. Anonymous and local dev surfaces still fall back to Google Gemini (`gemini-3.5-flash`) — the Gateway only activates when the user is signed in and the two env vars below are set.

| Variable                   | Required for Gateway | Default | Purpose                                                                                                                       |
| -------------------------- | -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `NEON_AI_GATEWAY_BASE_URL` | Yes                  | —       | Neon AI Gateway host injected by `neon deploy` when `preview.aiGateway` is enabled in `neon.ts`. Must be under `*.neon.tech`. |
| `NEON_AI_GATEWAY_TOKEN`    | Yes                  | —       | Neon-issued gateway token (`nt_live_…`) used as the OCC bearer credential. Scoped to the deployment branch.                   |

Both values are captured into process memory once at boot and then deleted from `process.env` so agent shell tools cannot read them with `printenv`. This means you should not rely on `NEON_AI_GATEWAY_*` being visible to your own code past startup.

### URL shape

Fleet Pi enforces a single `/v1` suffix on the Gateway base URL. All of these normalize to the same value:

```bash theme={null}
NEON_AI_GATEWAY_BASE_URL=https://<branch-id>-api.ai.<region>.aws.neon.tech
NEON_AI_GATEWAY_BASE_URL=https://<branch-id>-api.ai.<region>.aws.neon.tech/v1
NEON_AI_GATEWAY_BASE_URL=https://<branch-id>-api.ai.<region>.aws.neon.tech/v1/v1
```

The host must resolve to `*.neon.tech`. Any other host is rejected at boot and the Gateway is skipped rather than serving requests to an untrusted origin.

### BYOK precedence

When a user saves an OpenAI-Chat-Completions provider in the config panel, their BYOK settings win over the platform Gateway. Legacy OCC records are only migrated to the platform Gateway shape when the Gateway is active and the user has not brought their own OCC credentials.

### Named OpenAI-compatible instances

Each user can save **multiple** OpenAI-compatible Chat Completions endpoints side by side — for example one instance for OpenCode Zen and another for Nebius — instead of overwriting a single BYOK slot. Every named instance keeps its own display name, base URL, model ID, and API key, and each one appears in the model picker as a separate provider row. Named instances work on both deployed chat (signed-in users) and local anonymous chat.

Use named instances when you want to:

* Route different chats through different OpenAI-compatible backends without editing settings between turns.
* Keep a per-vendor label in the config panel so it's obvious which endpoint you're about to use.
* Add a new OpenAI-compatible provider without disturbing your existing default OCC configuration.

Add an instance from the in-app config panel under **OpenAI Chat Completions → Add instance**. Fleet Pi requires four fields per instance:

| Field        | Notes                                                                                                                                                                                                        |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Display name | User-facing label (e.g. `Nebius`). Fleet Pi normalizes it into a stable slug used internally as `openai-chat-completions+<slug>`.                                                                            |
| Base URL     | HTTPS root of the OpenAI-compatible API (e.g. `https://api.studio.nebius.com/v1`). Fleet Pi strips any trailing `/chat/completions` before saving.                                                           |
| Model ID     | Model name to register when the endpoint doesn't list one via `/models` (e.g. `meta-llama/Llama-3.1-70B-Instruct`).                                                                                          |
| API key      | Encrypted at rest under `BETTER_AUTH_SECRET` when stored in Postgres (deployed chat); stored in plaintext in `.fleet/providers.json` for local anonymous chat. Only key metadata is returned to the browser. |

Fleet Pi picks the storage backend for named instances based on the surface:

| Surface                                                       | Storage                                                        | Encryption                                   |
| ------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------- |
| Deployed chat (signed-in user + `FLEET_PI_CHAT_DATABASE_URL`) | Neon Postgres `pi_user_providers` table                        | Encrypted at rest under `BETTER_AUTH_SECRET` |
| Local anonymous / non-DB chat                                 | Gitignored file store at `<projectRoot>/.fleet/providers.json` | Plaintext                                    |

The file store is written atomically (temp file + rename) with a per-process mutation lock, so concurrent creates get distinct slugs. A malformed or future-version store falls back to an empty list with a diagnostic instead of breaking chat session creation. The `.fleet/` directory is gitignored, but treat `.fleet/providers.json` as sensitive — it contains plaintext API keys.

<Note>
  Named instances must use an `https://` base URL by default. On local dev surfaces, OCC-family instances can also point at `http://localhost` (useful for pointing at an Ollama or LM Studio process). Deployed chat still requires `https://` at both save time and runtime registration, so a legacy `http://` value can never sneak through.
</Note>

The default OCC slot (`openai-chat-completions`) still exists alongside named instances and continues to take precedence over the platform Neon AI Gateway. Named instances give you additional endpoints without replacing that default.

Fleet Pi also validates each instance every time the runtime registers it. If the stored API key can't be decrypted or the base URL fails the safety checks, the instance is **skipped** with a warning diagnostic and shows up in the Settings providers list as **Not configured** instead of a misleading healthy row — so the model picker never advertises an endpoint that would fail at request time.

### Readiness gate

`pnpm verify-deployment-readiness` validates that `NEON_AI_GATEWAY_BASE_URL` is a well-formed allowed Gateway URL — not just present. Deploys fail closed when the URL is malformed or points off the `*.neon.tech` allowlist, so a broken Gateway variable cannot silently ship.

## Dual-host chat runtime (optional)

Fleet Pi normally serves the chat streaming API from the same Vercel app that hosts settings, providers, and the workspace. Setting `VITE_FLEET_PI_CHAT_RUNTIME_URL` splits chat onto a separate host (typically a Neon Function) while settings, providers, and workspace stay on Vercel. The browser attaches a Neon Managed Auth bearer JWT to every chat request, and the runtime verifies it against `NEON_AUTH_JWKS_URL` and `NEON_AUTH_ISSUER`. Use this when you want chat to scale independently or when your Neon Function should own session object storage.

| Variable                             | Required when dual-host is on | Default | Purpose                                                                                                                     |
| ------------------------------------ | ----------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
| `VITE_FLEET_PI_CHAT_RUNTIME_URL`     | Yes                           | —       | Base URL of the Neon Function that hosts the chat runtime. When unset, chat runs on the same Vercel app as everything else. |
| `FLEET_PI_CHAT_RUNTIME_CORS_ORIGINS` | Yes                           | —       | Comma-separated allowlist of browser origins permitted to call the chat runtime. Required for CORS preflight to succeed.    |
| `FLEET_PI_CHAT_RUNTIME_REQUIRE_AUTH` | No                            | —       | Set to `1` to force bearer-JWT auth on the chat runtime even without Vercel or Managed Auth environment markers.            |

Example Vercel environment for a dual-host deployment:

```bash theme={null}
# Neon Managed Auth
NEON_AUTH_BASE_URL=https://<neon-endpoint>/neondb/auth
VITE_NEON_AUTH_URL=https://<neon-endpoint>/neondb/auth
NEON_AUTH_ISSUER=https://<neon-endpoint>/neondb/auth

# Chat runtime on a Neon Function
VITE_FLEET_PI_CHAT_RUNTIME_URL=https://<neon-function-host>
FLEET_PI_CHAT_RUNTIME_CORS_ORIGINS=https://fleet-pi-web.vercel.app,http://localhost:3000
```

## Sessions and workspace paths

Pi session files are persisted under `.fleet/sessions/` inside the repo. The session manager rejects paths outside the repo-scoped directory via `isUsableSessionFile`, so a stale `sessionFile` in `localStorage` silently falls back to a fresh session — see [runbooks](/fleet-pi/runbooks#ir-2-chat-session-corruption-or-data-loss) for recovery.

Canonical durable state lives under `agent-workspace/`. The workspace server reads canonical files directly and uses `agent-workspace/indexes/` only as projection storage.

## Chat session mirror (Neon Postgres)

Pi session JSONL files under `.fleet/sessions/` are always the source of truth. When `FLEET_PI_CHAT_DATABASE_URL` is set, Fleet Pi additionally mirrors full Pi session entries, run events, tool executions, and file mutations into Neon Postgres tables prefixed with `pi_`. Use this when you want SQL search across conversations, cross-surface history, analytics, or long-term debugging.

Mirror failures are caught and logged — they never break chat streaming.

| Variable                               | Required       | Default | Purpose                                                                                         |
| -------------------------------------- | -------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `FLEET_PI_CHAT_DATABASE_URL`           | No             | —       | Enables the mirror. Pooled Neon connection string for the runtime app role (DML only).          |
| `FLEET_PI_CHAT_MIGRATION_DATABASE_URL` | For migrations | —       | Direct `neondb_owner` connection string used by `pnpm chat:migrate` to apply schema migrations. |

Use two separate roles in Neon:

| Role           | Privileges                                      | Used by             |
| -------------- | ----------------------------------------------- | ------------------- |
| `neondb_owner` | Full DDL + DML (CREATE, ALTER, DROP, etc.)      | Migration CLI only  |
| `fleet_pi_app` | SELECT, INSERT, UPDATE, DELETE on `pi_*` tables | Running application |

Apply migrations once per environment before starting the app:

```bash theme={null}
pnpm --filter web chat:migrate
```

See [runbooks](/fleet-pi/runbooks#chat-session-mirror-neon-postgres) for the full table list and operational guidance.

## Daytona-backed user sandboxes

Authenticated users can be assigned an isolated Daytona sandbox that runs Pi tool calls in a container instead of on the host. Each user gets one sandbox in **their** Daytona account via BYOK (bring your own key), keyed by their Better Auth `userId`. Sandbox routes require Better Auth — unauthenticated requests return `401`.

### How Daytona is enabled per user

Fleet Pi enables Daytona for a user only when:

1. The user is authenticated through Better Auth.
2. A Daytona API key is resolved for that user.

Fleet Pi resolves the Daytona API key from the user's stored provider secrets first (Settings → Providers → **Daytona**). If none is found, it falls back to the `DAYTONA_API_KEY` environment variable **only in local development**. On Vercel, env `DAYTONA_API_KEY` alone does not enable Daytona — each logged-in user must save their own Daytona API key as the `daytona` provider secret.

When Daytona is not enabled for the calling user, `GET /api/sandbox/preview` returns `503` and tool calls run against the host workspace (unless the request is expected to have a sandbox, in which case the request fails closed).

### Environment variables

| Variable                  | Required                | Default                                    | Purpose                                                                                                                                         |
| ------------------------- | ----------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `DAYTONA_API_KEY`         | Local/dev fallback only | —                                          | Fallback Daytona API key for local development. On Vercel this is ignored as a sole key source — users must BYOK the `daytona` provider secret. |
| `DAYTONA_API_URL`         | No                      | Daytona SDK default                        | Override the Daytona API base URL (for example, self-hosted Daytona).                                                                           |
| `DAYTONA_TARGET`          | No                      | —                                          | Optional Daytona target region or runner identifier (for example, `us` or `eu`).                                                                |
| `DAYTONA_WEBHOOK_SECRET`  | No                      | —                                          | Shared secret expected in the `x-daytona-signature` header for `POST /api/webhooks/daytona`. Without it, webhook side effects are ignored.      |
| `FLEET_PI_REPOSITORY_URL` | No                      | `https://github.com/Qredence/fleet-pi.git` | HTTPS repository URL used to sparse-seed `agent-workspace/` into an empty Daytona volume on first launch.                                       |

### Persistence and mount paths

Each user's sandbox has one persistent volume that survives sandbox restarts and archival:

| Resource         | Naming convention        | Mount path                      | Lifecycle                                            |
| ---------------- | ------------------------ | ------------------------------- | ---------------------------------------------------- |
| Sandbox          | `fleet-pi-user-{userId}` | —                               | Auto-stops after 30 minutes idle; resumed on demand. |
| Workspace volume | `fleet-pi-ws-{userId}`   | `/home/daytona/agent-workspace` | Persists across sandbox restarts and deletions.      |

There is **no** full-repo clone in the sandbox and **no** sandbox-side Pi session store — Pi sessions stay on the host (or Neon mirror). The sandbox mounts only `agent-workspace/`. On first launch (empty volume), Fleet Pi sparse-seeds the volume from `FLEET_PI_REPOSITORY_URL` using a non-clobber copy. Do not delete the workspace volume unless you intend to reset that user's workspace.

### Legacy sandbox migration

Sandboxes provisioned before this release mounted the workspace at `/home/daytona/fleet-pi`. Fleet Pi now expects `/home/daytona/agent-workspace`. On the next warm-up, legacy sandboxes are **recreated automatically** — the durable `fleet-pi-ws-*` volume is preserved and remounted at the new path. No action is required.

### Provider credentials in the sandbox

When Daytona is active, Fleet Pi tries to sync each configured LLM provider key into the user's Daytona organization as a Secret named `fleet_pi_<providerId>`. The sandbox then sees only opaque placeholders (`dtn_secret_*`); Daytona substitutes the real value on egress to the provider's allowlisted HTTPS host.

Providers eligible for Secrets sync (known HTTPS API hosts):

| Provider                | Provider ID                 | Egress host                         |
| ----------------------- | --------------------------- | ----------------------------------- |
| Google Gemini           | `google`                    | `generativelanguage.googleapis.com` |
| OpenAI                  | `openai`                    | `api.openai.com`                    |
| Anthropic               | `anthropic`                 | `api.anthropic.com`                 |
| Mistral                 | `mistral`                   | `api.mistral.ai`                    |
| Groq                    | `groq`                      | `api.groq.com`                      |
| OpenRouter / AI Gateway | `openrouter` / `ai-gateway` | provider public host                |
| OpenAI Chat Completions | any HTTPS `baseURL`         | derived from the base URL           |

The following credentials are still injected as plaintext inside the sandbox (they cannot use Secrets-based egress substitution): GitHub Copilot OAuth tokens, Google Vertex ADC (`GOOGLE_APPLICATION_CREDENTIALS`), Bedrock signing keys, `OLLAMA_BASE_URL`, and OCC base URL / model ID.

<Note>
  Daytona sandbox credential sync covers only the reserved default OpenAI Chat Completions slot (`openai-chat-completions`). Additional [named OpenAI-compatible instances](#named-openai-compatible-instances) live in the chat runtime's encrypted store and are never injected into the sandbox — sandbox tool calls that need one of those endpoints must go through the chat runtime, not directly from the container.
</Note>

When a Secrets-backed credential changes for an active sandbox, Fleet Pi recreates the sandbox (volume preserved) so the new Secret placeholder is mounted at create time. If the Daytona Secrets API is not available for the user's org (for example, `Access denied` on the Secrets endpoint), Fleet Pi falls back to plaintext injection instead of failing sandbox provisioning.

See the [API reference](/fleet-pi/api-reference#sandbox) for the sandbox preview and webhook contracts.

## Vercel deployment (trust zones)

Fleet Pi hardens Vercel/Neon deployments with three trust zones — `local`, `vercel-production`, and `vercel-preview` — enforced at boot. Vercel builds call `assertDeploymentReadyOnBoot()` before Better Auth mounts, so missing secrets or misconfigured Preview environments fail fast instead of accepting cross-zone traffic. Local development is unaffected and stays anonymous.

Set these variables in the Vercel project (in addition to the [auth](/fleet-pi/configuration#authentication-better-auth) and [chat mirror](/fleet-pi/configuration#chat-session-mirror-neon-postgres) variables above):

| Variable                              | Required         | Purpose                                                                                                      |
| ------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ |
| `BETTER_AUTH_URL`                     | Yes (Production) | Explicit production origin used for OAuth callback URLs.                                                     |
| `BETTER_AUTH_TRUSTED_ORIGINS`         | Yes (Preview)    | Comma-separated allowlist. No `*.vercel.app` wildcard — list each preview alias explicitly.                  |
| `FLEET_PI_DEPLOYMENT_TRUST_ZONE`      | Yes (Preview)    | Set to `preview` on Preview deployments. Production leaves this unset.                                       |
| `FLEET_PI_PRODUCTION_DATABASE_MARKER` | Yes (Preview)    | Substring that identifies the production Neon branch. Preview URLs must not contain it.                      |
| `FLEET_PI_PREVIEW_DATABASE_MARKER`    | Yes (Preview)    | Substring that must appear in both `FLEET_PI_AUTH_DATABASE_URL` and `FLEET_PI_CHAT_DATABASE_URL` on Preview. |

Preview deployments must point at a Neon branch that is distinct from production. The readiness check confirms the preview marker is present in both database URLs and the production marker is absent.

Verify readiness locally before promoting:

```bash theme={null}
pnpm --filter web verify-deployment-readiness
```

The CI `vercel-release-gate` job runs `build:vercel` plus this check against production-shaped and preview-shaped env. See [runbooks](/fleet-pi/runbooks#deployment-release-gate-vercel--neon) for the pre-promotion checklist and break-glass procedure.

## Generated configuration files

| File                            | Purpose                                                                                                                |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `apps/web/src/routeTree.gen.ts` | Generated by TanStack Router. **Do not edit by hand.**                                                                 |
| `openapi.json`                  | Generated from zod schemas, drives the [API reference](/fleet-pi/api-reference). Regenerate with `pnpm generate:docs`. |
| `agent-workspace/manifest.json` | Describes the canonical workspace shape and the contract version.                                                      |

## Related

<CardGroup cols={2}>
  <Card title="Quickstart" icon="bolt" href="/fleet-pi/quickstart">
    Apply this configuration end to end.
  </Card>

  <Card title="Runbooks" icon="life-ring" href="/fleet-pi/runbooks">
    Troubleshoot provider errors, sessions, and circuit-breaker state.
  </Card>
</CardGroup>
