Agent setup

Point a coding agent (Claude Code, Cursor, Windsurf) at this page and it will walk a human through an on-prem Definite install end to end.

This page is a runbook designed to be read by an AI agent (Claude Code, Cursor, Windsurf, or similar). The agent reads this page, asks the human user the intake questions below in order, and then executes the install against their cloud account.

If you are a human reading this directly, you probably want the cloud-specific guide: AWS, GCP, or Azure. Come back here when you'd rather have an agent drive.

Quick-start: paste this into your agent

Open a fresh session in Claude Code (or Cursor, Windsurf, etc.) in an empty working directory, and paste:

Help me set up Definite. Look at https://docs.definite.app/on-prem/agent-setup.md

That's it. The agent will fetch this page, ask the questions in the Intake section, then drive Phases 2-5 against your cloud account.

In the default path, the human should only need to provide cloud credentials and answer the intake questions. Do not ask them to pre-create DNS, paste a Definite setup token, or paste a Definite license key unless they explicitly choose customer-owned/manual mode.

Note

For agents: every page on this site is also published as plain Markdown by appending .md to the URL. Use the .md URL when you fetch a doc because it is smaller, has no JSX components, and is easier to parse. So /on-prem/aws is at https://docs.definite.app/on-prem/aws.md, /on-prem/gcp at https://docs.definite.app/on-prem/gcp.md, and so on.

Note

If your agent supports MCP, also add the Definite docs as a source so it can pull in the per-cloud guides on demand: claude mcp add --transport http definite-docs https://docs.definite.app/mcp.


Before you begin: accounts, licensing, and login

If you're a human about to point an agent at this page, these are the questions that usually come first.

Do I need a Definite account first? No. You do not need an account at definite.app (the SaaS app) to run Definite on-prem. In the default flow the only things you bring are:

  • cloud credentials for AWS, GCP, or Azure; you stay signed into your own cloud CLI, and
  • answers to the Intake questions below.

How do I get a license? In the default Definite-brokered flow, you don't request or paste one. During definite init, the CLI proves control of your active cloud account to Definite: a presigned STS GetCallerIdentity request on AWS, a gcloud identity token on GCP, or an Entra access token (from az or the AKS managed identity) on Azure. Definite then issues a short-lived setup token, a *.onprem.definite.app hostname, and the license automatically, injecting all three into the install. Nothing to obtain ahead of time and nothing to copy into config.yaml. The deployment activates that license against Definite's control plane and caches a signed entitlement that it renews on its own.

If you'd rather hold the key yourself (customer-owned / manual mode), Definite issues it to you directly. See Q9. Without a license the deployment still boots, but every product API route returns 403 until it activates.

How do I log in once it's up? Your login to your instance is the initial admin you set in config.yaml (auth.initial_admin_email + auth.initial_admin_password). See Bootstrap the initial admin. That admin user is created inside your own deployment on first boot; it is not a definite.app account. From there you add more users locally or wire up Google SSO.

Who do I talk to at Definite? The brokered self-serve path above needs nothing but cloud credentials and an agent. If you'd instead like Definite to scope or operate the deployment, or you need a manual license key, email hello@definite.app.


For the agent: how to use this page

You are an AI coding agent helping a human install on-prem Definite into their own cloud account. Read this entire page before asking your first question. Follow these rules:

  1. Ask one question at a time. Do not batch the intake questions. Wait for the human's answer before moving on.
  2. Offer a default the human can accept with a quick confirmation. Most questions below have a recommended choice. State it explicitly and accept any short affirmation as "use the default": "yes", "ok", "sounds good", "go with that", and so on. Some chat-based agents (for example Claude's CLI) cannot send an empty turn, so do not rely on the human pressing Enter. When the human answers a question that has a default with anything affirmative or non-specific, take the default and move on. Only the questions with no safe default (region, admin email, credentials) require a specific answer.
  3. Present a plan, then ask a yes/no before you apply it. Before any apply step (provisioning that costs money, writing or overwriting config.yaml, terraform apply, definite init/definite upgrade), summarize what you're about to do, then ask a yes/no question where "yes" proceeds and "no" means "not yet". Always invite changes on "no", for example: "Here's the plan: [short summary]. Ready for me to apply it? Reply "yes" to proceed, or "no" and tell me what to change." Treat anything that isn't a clear "yes" as "no": don't apply, fold in their comments, and re-confirm.
  4. Verify all prerequisites before you start, especially on a clean slate. For a greenfield install (no cluster, DB, or bucket to reuse), confirm every dependency is satisfied before provisioning anything: your own tooling and versions (Phase 0), the cloud CLI installed and authenticated, the IAM permissions to create the resources, and LLM model access enabled in the chosen region. Surface anything missing and resolve it with the human up front rather than failing halfway through a 30-minute provision.
  5. Run real commands against the human's cloud account. Do not just print them. Use your shell tool. Confirm before any destructive operation (delete, drop, force-destroy).
  6. Never invent values. If the human hasn't given you a region, project ID, hostname, password, or credential, ask. Placeholders like <your-region> must be replaced before any command runs.
  7. Capture every value into a single config.yaml as you go. Don't ask the human to write the file; you write it, show it to them, and confirm before definite init.
  8. Run definite doctor before definite init. Do not pass --skip-preflight unless doctor failed only on the Postgres reachability check from a laptop outside the VPC (private RDS / Cloud SQL / Postgres Flexible Server) and the per-cloud guide says that is expected. Never use --skip-preflight to mask Kubernetes, object-store, license, or LLM failures.
  9. Hand off to the per-cloud guide for the long shell sequences. Phase 2 below tells you which page to fetch.
  10. Stop and escalate to a human at Definite (hello@definite.app) if: the cloud lacks a permission you need, an LLM provider rejects the model, definite doctor fails for a reason you can't fix in three tries, the broker rejects cloud-attested setup-token acquisition, or the human asks for production support beyond install.
Warning

Agent note: Do not stop the install to ask the user to configure customer DNS unless they explicitly selected customer-owned DNS mode. In the default flow, use Definite-brokered DNS. After provisioning the load balancer, call the Definite setup broker, use the returned *.onprem.definite.app URL, wait for DNS/TLS readiness, and continue the install. Customer-owned DNS can be configured after the system is healthy.

Note

Agent note: do not ask the user for a Definite setup token in the default flow on any cloud, including Azure. If DEFINITE_ONPREM_SETUP_TOKEN is not already present, the released definite CLI proves control of the user's cloud account to Definite and obtains a short-lived setup token automatically: a presigned STS GetCallerIdentity request on AWS, a gcloud identity token on GCP, and an Entra access token on Azure (minted from the user's az login session, or the AKS workload's managed identity via IMDS when run in-cluster). The raw token is not printed and expires quickly.

The human only needs to supply a DEFINITE_ONPREM_SETUP_TOKEN if they explicitly opt out of automatic attestation; in that case they get one from Definite (hello@definite.app) and reference it in config.yaml under broker.setupToken.env: DEFINITE_ONPREM_SETUP_TOKEN. See Azure guide → Set or skip the setup token.


Phase 0: Confirm prerequisites and the agent's environment

Before asking the human anything, verify your own tooling. Run, in parallel:

which kubectl helm
kubectl version --client 2>/dev/null
helm version --short 2>/dev/null

You need kubectl 1.28+ and helm 3.12+. If either is missing, install them before continuing. The cloud CLI (aws, gcloud, or az) is checked in Phase 2 once you know which cloud.

Clean-slate (greenfield) installs: confirm every prerequisite up front. When the human has no existing cluster, database, or bucket to reuse (the common case, see Q7), a provision takes 20-40 minutes, so verify the full dependency chain before you start, not halfway through. Walk this checklist and report each result to the human, resolving any gap before Phase 2:

  • Agent tooling: kubectl 1.28+ and helm 3.12+ on PATH (above).
  • Cloud CLI installed and authenticated: aws sts get-caller-identity / gcloud config list account / az account show returns the expected account. If the human isn't logged in, ask them to authenticate; never authenticate as them.
  • Permissions to create resources: the authenticated principal can create the cluster, managed Postgres, object store, and IAM bindings for the chosen cloud. If you can't verify a permission, say so and let the human confirm with their cloud admin rather than discovering it on a failed apply.
  • LLM model access: the chosen provider has the selected model enabled in the target region (Bedrock model access request, Vertex Model Garden enablement, or an Azure OpenAI deployment). On Azure, default to gpt-5.6-terra version 2026-07-09, but treat the 5.6 family as a Preview, phased rollout. Verify both catalog presence and nonzero GlobalStandard quota on the new subscription before provisioning. See Q5 and Q6.
  • definite CLI + cluster prereqs: installed in Phase 4; definite bootstrap then installs ingress, cert-manager, and the agent-sandbox CRDs, and definite doctor re-checks the whole chain before install.

If any prerequisite is unmet, surface it now and resolve it with the human before provisioning anything.


Phase 1: Intake

Ask the human these questions in order. Capture each answer into a working scratchpad you can refer back to in later phases.

Q1. Which cloud?

"Which cloud are you installing on: AWS, GCP, or Azure?"

Record as CLOUD. This drives every subsequent decision.

If CLOUD =Per-cloud guide to fetch in Phase 2ClusterPostgresObject storeDefault LLM
AWS/on-prem/awsEKSRDS Postgres 15S3Bedrock
GCP/on-prem/gcpGKE (Autopilot)Cloud SQL Postgres 15GCS (HMAC)Vertex AI
Azure/on-prem/azureAKSPostgres Flexible Server 15Blob StorageAzure OpenAI
Warning

Azure is currently a preliminary guide. A clean-room public demo deployment validated AKS, Postgres Flexible Server, Blob Storage, local auth, brokered DNS and TLS, and Azure OpenAI, but it exposed release blockers in the generated lakehouse URI and runtime CA bundle path. Do not install v0.1.86 unmodified. Contact hello@definite.app and require a newer release that includes both fixes before proceeding. Private networking, customer-owned DNS, production high availability, and Entra SSO were not validated. AKS remains the only supported Azure compute platform; Azure Container Apps and Azure Container Instances do not expose the Kubernetes API access Definite requires. Setup-token acquisition works like the other clouds: the CLI attests the Azure tenant with an Entra access token from az or the AKS managed identity.

Q2. Environment

"Is this a demo / pilot install (you'll throw it away in a few weeks), or a production install (real users, real data)?"

Record as ENV ∈ {demo, prod}. This changes a handful of defaults:

SettingDemoProduction
HA databasessingle-AZmulti-AZ / regional
Deletion protectionoffon
HostnameDefinite-brokered https://<slug>.onprem.definite.appDefinite-brokered https://<slug>.onprem.definite.app by default; customer-owned DNS is an advanced option after the system is healthy
TLSDefinite-brokered TLSDefinite-brokered TLS by default; private/internal production may need customer certs or a private CA
Backupsnonedaily snapshots
Lakehouse PVC size50Gisize to expected data + 2x

Do not ask for DNS before first install unless the human explicitly chooses customer-owned DNS mode. The default first-run URL comes from Definite.

Q3. DNS mode

"Should I use the default Definite-brokered DNS for the first install? Definite will provide a URL like https://<slug>.onprem.definite.app. Just say "yes" to accept, or choose customer-owned DNS only if you already need a private/internal hostname or custom certificate."

Record as DNS_MODE ∈ {definite-brokered, customer-owned}. Default to definite-brokered if the human accepts or doesn't choose customer-owned.

If DNS_MODE = definite-brokered, do not ask for a hostname yet. After the load balancer exists, call the Definite setup broker through the definite CLI, record the returned URL as PUBLIC_URL, and set HOSTNAME to the host portion, for example <slug>.onprem.definite.app.

If DNS_MODE = customer-owned, ask:

"What customer-owned hostname should Definite be reachable at, like definite.acme.com?"

Record as HOSTNAME, then follow the per-cloud guide's customer-owned DNS notes. Use the released CLI's customer-owned mode when it is available; the expected flag shape is --dns-mode customer-owned --hostname <HOSTNAME>.

Warning

Private/internal production deployments may require customer-owned DNS and a customer certificate or private CA. That is a custom production path, not the default first-run path.

Q4. Authentication

"How should users sign in: local auth (email + password, recommended for the first install), or Google Workspace SSO (OIDC)?"

Record as AUTH ∈ {local, oidc}. Google Workspace is the only OIDC provider supported today; Entra ID and other providers are on the roadmap. If the human is Entra-first, recommend local auth for now and switching to SSO when Entra support lands.

If AUTH = oidc, confirm that the provider is Google Workspace and follow /on-prem/sso. Generic OIDC providers such as Microsoft Entra ID and Okta are not supported by the current release. Do not accept an issuer URL for one of those providers or imply that an Azure deployment supports Entra SSO.

If they choose Google Workspace, ask for the OAuth client details required by the SSO guide. For Azure, recommend local auth for the first install and configure Google SSO only after the local-auth deployment is healthy.

"What are the Google OAuth client ID, client secret reference, and allowed Workspace domain?"

Q5. LLM provider

Always lead with the cloud's native LLM and offer it as the default. Bedrock uses IRSA on AWS, and Vertex uses Workload Identity on GCP, so those paths do not require static API keys. The current Azure OpenAI path uses an Azure OpenAI API key stored through a secret reference. Phrase the recommendation so the human can accept it with a quick "yes", for example on AWS:

"For AWS I recommend Bedrock, which authenticates with the cluster's IAM role (IRSA), so there are no API keys to manage. Want me to use Bedrock? Just say "yes", or pick Anthropic direct, Azure OpenAI, or Vertex."

For Azure, recommend:

"For Azure I recommend Azure OpenAI gpt-5.6-terra version 2026-07-09 as Fi's default model, deployed as GlobalStandard with initial capacity 10. Availability is phased, so I'll verify the model catalog and quota in this subscription first. Want me to use that default?"

CLOUDRecommended default (offer this)Alternatives
AWSBedrock (IRSA, no static creds)Anthropic direct, Azure OpenAI, Vertex
GCPVertex AI (Workload Identity, no static creds)Anthropic direct, Bedrock, Azure OpenAI
AzureAzure OpenAI gpt-5.6-terra (Preview/phased; API key in the current release)gpt-5.6-luna for lower-cost latency-sensitive work; gpt-5.6-sol for the hardest workloads; Anthropic direct, Bedrock, or Vertex

Record as LLM_PROVIDER. For Bedrock or Vertex, confirm the human has model access enabled in their account for the Claude model they want. For Azure OpenAI, default to gpt-5.6-terra version 2026-07-09, GlobalStandard, capacity 10. Use gpt-5.6-luna for lower-cost, latency-sensitive workloads, and use gpt-5.6-sol only for the hardest workloads. Because 5.6 access is Preview and phased, list the account's models and regional quota and require both the exact catalog entry and nonzero quota before deployment. Capture the Azure OpenAI API key as a secret reference. If they pick another provider that uses a key, capture that key reference for config.yaml.

Q6. Region

"Which region? Pick whatever is closest to your users / source data. If you're not sure, [recommend their cloud's most-popular region]."

Record as REGION. Cross-check that the chosen LLM model is available in this region. Bedrock and Vertex availability varies, and Azure OpenAI 5.6 catalog and quota rollout is phased by subscription and region.

Q7. Existing infrastructure to reuse

"Are you starting fresh, or do you have existing infrastructure you want me to reuse: an existing Kubernetes cluster, an existing Postgres database, or an existing object-store bucket?"

Most installs are greenfield. If the human says they want to reuse something, capture the connection details and note them for Phase 2: you'll skip provisioning that resource but still need it in config.yaml.

Q8. Naming

"What name prefix should I use for the resources I create? Default is definite; just say "yes" to accept, or give me another."

Record as NAME_PREFIX. This becomes part of cluster name, bucket name, DB name, etc. If the human confirms or doesn't give a specific prefix, use definite; don't make them type the word "default".

Q9. Optional customer-owned license

Do not ask for a manual license key in the default Definite-brokered flow. definite init requests a broker-issued license during setup and injects it for the install.

Only ask this question if the human explicitly selected customer-owned/manual mode:

"On-prem Definite needs a license key, issued to you by Definite. Do you have it? It looks like onprem_ followed by a long hex string."

Record as LICENSE_KEY only for that manual path. If the human does not have a key for manual mode, stop and have them email hello@definite.app.


Phase 2: Provision cloud infrastructure

You now have enough information to provision. Fetch the per-cloud guide for CLOUD and execute Phase 1 ("Provision …") of that guide, substituting the answers from Intake.

CLOUDFetch (use the .md URL) and follow
AWS/on-prem/aws.md - Phase 1 (first supported black-box path, Terraform module)
GCP/on-prem/gcp.md - Phase 1 (gcloud sequence)
Azure/on-prem/azure.md - Phase 1 (az sequence; preliminary, fixed release required)

A few rules that apply across all three:

  • Confirm the cloud CLI is authenticated before running anything. aws sts get-caller-identity / gcloud config list account / az account show. If the human isn't logged in, ask them to authenticate; do not try to authenticate as them.
  • Capture every output you'll need for config.yaml as you go (cluster name, DB connection string, bucket name, access keys, service-account emails). Don't make the human re-run commands to find them.
  • Get a yes/no before any command that costs money (cluster create, RDS create, Cloud SQL create) or that writes IAM bindings. Summarize what will be created and its rough cost, then ask "Ready to apply? Reply "yes" to proceed, or "no" and tell me what to change." Anything that isn't a clear "yes" means stop and adjust.
  • Do not create customer DNS in the default flow. For DNS_MODE = definite-brokered, continue until the load balancer exists, then use the definite CLI to call the setup broker. The backend contract is POST /onprem/v1/setup-sessions, but the agent should not ask the human to run a direct curl by default.
  • Provisioning takes 20-40 minutes, mostly the managed Kubernetes cluster. Tell the human that up front. Run independent commands in parallel where possible.

When Phase 1 of the per-cloud guide is done, return here for Phase 3.


Phase 3: Assemble config.yaml

Open a new file config.yaml in the human's working directory and fill it in from your scratchpad. The shape is the same across clouds; only object_store, lakehouse.storage.storage_class_name, and llm change.

A canonical template (replace every <...> with a real value from Intake or Phase 2):

deployment:
  name: <NAME_PREFIX>
  namespace: <NAME_PREFIX>
  dns_mode: definite-brokered          # default first-run mode

# broker:
  # Omit this block on all clouds in the default flow. definite init acquires a
  # short-lived setup token by proving control of the active cloud credentials
  # (AWS STS presign, GCP identity token, or Azure Entra access token via az /
  # the AKS managed identity). Add it only for the manual token override:
  # setupToken:
  #   env: DEFINITE_ONPREM_SETUP_TOKEN

# Omit the license block in the default brokered flow. definite init injects
# the broker-issued license for this install. Add license.key only for
# customer-owned/manual mode.

postgres:
  url: postgres://<user>:${POSTGRES_PASSWORD}@<host>:5432/<db>

object_store:
  # `credentials` is REQUIRED on every cloud. If you omit it, definite doctor
  # fails with a bare `missing field 'credentials'` and no section pointer.
  # Uncomment the block for CLOUD:
  #
  # AWS (S3): HMAC access-key pair:
  # type: s3
  # bucket: <bucket>
  # region: <REGION>
  # credentials:
  #   key_id: { env: S3_ACCESS_KEY_ID }
  #   secret: { env: S3_SECRET_ACCESS_KEY }
  #
  # GCP (GCS): HMAC interoperability pair:
  # type: gcs
  # bucket: <bucket>
  # credentials:
  #   key_id: { env: GCS_HMAC_KEY_ID }
  #   secret: { env: GCS_HMAC_SECRET }
  #
  # Azure (Blob): single shared storage-account key, NOT an HMAC pair:
  # type: azure
  # account: <storage-account>
  # container: <container>
  # credentials:
  #   env: AZURE_STORAGE_KEY

lakehouse:
  prefix: lake/
  storage:
    size: 50Gi
    storage_class_name: <gp3 | premium-rwo | managed-csi-premium>

auth:
  mode: <local | oidc>
  initial_admin_email: <admin@your-domain>
  initial_admin_password:
    env: INITIAL_ADMIN_PASSWORD
  # If oidc: configure Google Workspace using /on-prem/sso. Generic OIDC is not supported.

llm:
  provider: <bedrock | vertex | anthropic | azure_openai>
  # Provider-specific fields per the per-cloud guide.

resources:
  api:        { replicas: 2, cpu: "1",  memory: 2Gi }
  lakehouse:  { replicas: 1, cpu: "4",  memory: 16Gi }
  frontend:   { replicas: 2, cpu: 500m, memory: 512Mi }
  job_runner: { replicas: 1, cpu: 500m, memory: 1Gi }

Then show the filled-in config.yaml to the human and ask a yes/no before you proceed. Diff it against their answers and flag anything you had to guess, then ask, for example: "This is the config I'll install with. Ready to apply? Reply "yes" to proceed, or "no" and tell me what to change." Treat anything that isn't a clear "yes" as "no": edit the file per their comments and re-confirm.

Export the secrets the file references:

export POSTGRES_PASSWORD="..."
export INITIAL_ADMIN_PASSWORD="$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 24)"
# Object-store credentials (S3 access key, GCS HMAC pair, or Azure storage key)
# OIDC_CLIENT_SECRET if using Google Workspace SSO

Pull these values from Phase 2's outputs. Never echo secrets back into the chat transcript; reference them by env var name only. On all clouds, the default brokered flow has no LICENSE_KEY env var and no DEFINITE_ONPREM_SETUP_TOKEN env var; the CLI acquires both broker authorization and license during definite init, attesting the active cloud credentials (including Azure via az / the AKS managed identity). Only export DEFINITE_ONPREM_SETUP_TOKEN if the human opts into the manual token override.

Warning

Do not commit config.yaml to a public repo while the secret env vars are exported in your shell. For prod installs, recommend sourcing secrets from a secret manager (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, 1Password).


Phase 4: Install Definite

The CLI install is identical across clouds. Run, in order:

# 1. Install the CLI
curl -fsSL https://storage.googleapis.com/definite-public/definite-onprem/install.sh | sh
definite version

# 2. Bootstrap cluster-level prereqs (ingress, cert-manager, agent-sandbox CRDs)
definite bootstrap

# 3. Preflight
definite doctor --config config.yaml

# 4. Deploy. In the default mode, init discovers the ingress load balancer,
# calls the Definite setup broker, waits for brokered DNS readiness, injects
# the returned hostname/license into this install, and prints the final URL.
# On all clouds, if no setup token is configured the CLI acquires one
# automatically from the active cloud credentials (Azure mints an Entra access
# token via az / the AKS managed identity).
definite init --config config.yaml --dns-mode definite-brokered

On Azure, definite doctor performs a real PUT and DELETE of lake/.preflight in Blob Storage, but it does not exercise DuckDB's Azure extension or make an Azure OpenAI inference request in the current release. Before init, run the Azure guide's direct model request. After deployment, require the persistent-table and physical-Blob checks in Phase 5. Do not interpret a passing .preflight probe or SELECT 1 as proof that lakehouse data reaches Blob Storage.

If DNS_MODE = customer-owned, use definite init --config config.yaml --dns-mode customer-owned --hostname <HOSTNAME> instead. Do this only when the human explicitly selected customer-owned DNS; otherwise use Definite-brokered DNS.

If definite doctor fails, fix the failure before running definite init. The most common failures and fixes are in the Troubleshooting section of each per-cloud guide.

The one documented exception is the Postgres reachability check against a private DB endpoint from a laptop (RDS, Cloud SQL with private IP, Postgres Flexible Server). The in-cluster API pods may reach the DB fine while the laptop has no route. If doctor fails only on Postgres for this reason, follow the per-cloud guide's private-network workaround. Do not use --skip-preflight to mask any other failure.

Warning

In the default Definite-brokered flow, config.yaml should not have a static license block. If definite init or post-install smoke tests still report UNLICENSED, brokered license acquisition or injection failed. Capture the CLI output and API logs, retry once after confirming cloud attestation still works, then escalate to Definite. For customer-owned/manual mode only, verify the provided license.key and re-run.

Bootstrap the initial admin

For local auth, include auth.initial_admin_email and auth.initial_admin_password.env in config.yaml before running definite init. The CLI passes those values into the Helm install, and the API creates the initial admin on first startup.

Print the admin password back to the human and tell them to save it in a password manager. It is not recoverable.

Do not manually patch INITIAL_ADMIN_EMAIL or INITIAL_ADMIN_PASSWORD onto the API Deployment after install unless you are repairing an older deployment. Do not restart the lakehouse unless logs show an unrelated lakehouse-specific failure.

AWS Bedrock follow-up

If CLOUD = AWS and LLM_PROVIDER = bedrock, confirm the definite ServiceAccount has the Bedrock IRSA role ARN. If it is not already present, annotate it after install:

BEDROCK_ROLE_ARN=$(terraform output -raw bedrock_irsa_role_arn)
kubectl annotate serviceaccount definite -n <NAME_PREFIX> \
  eks.amazonaws.com/role-arn="$BEDROCK_ROLE_ARN" --overwrite
kubectl rollout restart deploy/definite-api -n <NAME_PREFIX>
kubectl rollout status  deploy/definite-api -n <NAME_PREFIX>

Without this annotation Fi can't call Bedrock and every Fi conversation fails. See AWS guide → Bedrock IRSA.

If REGION is not a US region, expect extra Bedrock work. Fi runs in per-run sandbox pods (the agent-sandbox CRDs from definite bootstrap), not in definite-api, and the sandbox client only normalizes us./anthropic. model prefixes correctly. The module and chart also default to us.-prefixed inference profiles and a model that may be Legacy outside the US. Before declaring Fi healthy in a non-US region, work through AWS guide → Choosing a Bedrock model and the Non-US LiteLLM proxy path. The failures you'll hit and their fixes:

  • ResourceNotFoundException: ... marked by provider as Legacy → pick a current model ID for the region.
  • AccessDenied at invoke time → the cross-region profile (e.g. au.*) dispatches to a sibling region; add those region ARNs to the Bedrock IAM policy.
  • The provided model identifier is invalid / No API key found for amazon-bedrock → route Fi through the definite-litellm proxy with the region's profile IDs.

These are advanced, manual steps the released CLI doesn't yet automate. If you hit them, tell the human and escalate to hello@definite.app rather than guessing; treat them as the kind of failure that warrants stopping per the escalation rules.


Phase 5: Verify

  1. definite status --config config.yaml: all pods Running, ingress has an address.
  2. Open https://<HOSTNAME> in a browser. In the default flow this is the Definite-brokered https://<slug>.onprem.definite.app URL; wait until the broker reports DNS/TLS ready before debugging the app.
  3. Log in with the admin email + password from Phase 4.
  4. Confirm core auth routes return 200 after login (/login, /auth/me, and the main app shell).
  5. Run a simple query smoke, for example SELECT 1 AS ok.
  6. Record the object count under the configured lakehouse prefix with the cloud CLI. Then create a uniquely named persistent table with at least 1,500 distinctive rows through the authenticated query API or query editor, read it back, and verify the exact row count and marker values.
  7. List the object store again and identify the newly created .parquet object with a size greater than zero. SQL success is not proof of this check. On Azure, follow Verify the Azure deployment exactly and include the Blob object path and byte size in the handoff.
  8. Drop the logical smoke-test table. DuckLake can retain its Parquet file for snapshot history, so do not delete physical objects by hand.
  9. Open the authenticated data apps page and confirm it loads.
  10. If Fi is configured, create a new Fi thread, send a unique test prompt, and follow the event stream to a terminal success state. On Azure OpenAI this is the post-install proof that the configured model works through Fi, not only through a direct provider request.

If any of these fail, capture logs (definite logs api --tail 200) before debugging.


Hand-off to the human

When Phase 5 is green, summarize for the human:

  • The URL they sign in at
  • The admin email + a reminder where the password is saved
  • The path to config.yaml (they'll need it for definite upgrade)
  • The per-cloud guide's Day-2 section (/on-prem/<cloud>#day-2-operations)
  • Next steps: Connect a data source, set up the MCP server, add SSO if they started with local auth
  • For teardown later: the per-cloud guide's Phase 3. On AWS in particular, the ingress-nginx NLB must be deleted before terraform destroy or the destroy hangs on subnet DependencyViolation.

When to escalate

Stop and tell the human to email hello@definite.app if:

  • The cloud account is missing a permission you can't grant yourself, and the human can't grant it either.
  • The LLM provider rejects model access and the human's admin doesn't respond within an hour.
  • definite doctor fails three times for distinct reasons.
  • definite init succeeds but pods crash-loop with errors that aren't in the per-cloud Troubleshooting table.
  • The human asks for anything beyond install (capacity planning, custom registry mirrors, air-gapped install, FIPS compliance, custom sandbox network policies).

Email hello@definite.app with reproducible bugs.