The PromptPack Deploy Program
Omnia is a Kubernetes-native runtime, but pack authors work in
PromptArena and do not use kubectl. The
deploy program bridges the two. It lets a PromptPack author push a pack into
an Omnia workspace without hand-writing CRDs, using the promptarena-deploy-omnia
deploy adapter.
This page explains the moving parts: the deploy-profile export, the browser-login flow, and how a deployed pack becomes a running AgentRuntime. For the step-by-step walkthrough, see Deploy a PromptPack to Omnia.
The problem it solves
Section titled “The problem it solves”A pack on its own is inert. To run it in Omnia you need:
- an API endpoint and workspace to deploy into,
- the target workspace configured with a ready service group (the session-api / memory-api backend agents persist to),
- an API credential scoped to that workspace,
- one or more Providers to back the LLM calls, and
- optionally SkillSources for retrieval and tools.
Getting each of these names right by hand is error-prone. A Provider name that
matches nothing in the workspace is reported by the deploy plan as
provider_not_found, and a Provider that is not Ready leaves the AgentRuntime
Pending with ProviderReady false. The deploy-profile export gives the author
a pre-filled config block built from what the workspace has.
How it fits together
Section titled “How it fits together”The adapter talks only to the dashboard’s address, where management-api serves
every /api path. management-api answers discovery requests itself and forwards
deploys to the operator, which owns the translation into CRDs.
flowchart LR CLI["promptarena CLI + promptarena-deploy-omnia"] subgraph MA["management-api, at the dashboard's address"] PROFILE["GET /api/workspaces/{name}/deploy-profile"] DEPLOY["POST /api/workspaces/{name}/deployments"] LOGIN["/api/cli/authorize, grant, token"] end OP["Operator deploy-intent API (:8085)"] K8S["Kubernetes API"] CLI --> LOGIN CLI --> PROFILE CLI --> DEPLOY PROFILE -->|"list Provider, SkillSource"| K8S DEPLOY -->|"DeployIntent + identity JWT"| OP OP -->|"ConfigMap, PromptPack, AgentRuntime"| K8S K8S --> REC["AgentRuntimeReconciler"] REC -->|"Deployment + Service"| K8SThe deploy profile
Section titled “The deploy profile”The deploy profile is a discovery payload for a single workspace. The
management-api serves it at GET /api/workspaces/{name}/deploy-profile. It is
discovery only, and the endpoint never returns a secret. It contains:
api_endpoint: the dashboard’s external ingress URL, derived from the forwarded host (falling back toOMNIA_DASHBOARD_EXTERNAL_URL).workspace: the target workspace name.providers: the discovery menu of Providers.skills: the discovery menu of SkillSources.
Two filters shape that menu.
The first filter lists only Providers and SkillSources whose status.phase is Ready
are listed. A Provider in phase Error or Unavailable, a SkillSource in phase
Error, and a resource that has no phase yet are all left out, because a
deployment that references one does not come up.
The second filter exports only llm-role Providers. The embedding,
tts, stt, image and inference roles are workspace-level services, consumed by
memory-api and similar subsystems, and are not per-agent extras. The rerank
role is reserved: no component consumes it, and memory retrieval does not
rerank. Bundling any of them into an agent’s spec.providers breaks the pack
at its first request, so the export drops them. A Provider with no explicit spec.role
defaults to llm.
Default-LLM picker and the token
Section titled “Default-LLM picker and the token”The raw discovery payload lists real Provider names. Two things happen on top of it when an author exports:
- The default-LLM picker: the export UI asks the author to pick one Provider
and marks it
name: defaultin the adapter config, withrefpointing at the real Provider CRD. The runtime loads the binding nameddefaultas its primary LLM. With no binding of that name, it uses the first binding by sorted name. - The workspace-scoped token: the profile itself carries no secret, so the
export mints an
omnia_sk_API token scoped to this workspace. The token deploys only to that workspace, and it acts with the author’s own role there. On re-export the dashboard offers to reuse the saved token or regenerate it (revoking the old key), so repeated exports do not pile up duplicate keys. If the deployment uses a read-only API-key store, the token is left as a placeholder for the author to mint by hand.
Browser-login autoconfigure
Section titled “Browser-login autoconfigure”When the dashboard runs in OAuth mode, the CLI can mint the whole config through
a browser-login flow (the same shape as gcloud auth login) instead of
copy-paste. The Omnia side is three endpoints.
sequenceDiagram participant CLI as promptarena CLI participant B as Browser participant M as management-api CLI->>B: open /api/cli/authorize?callback=loopback&state=nonce B->>M: GET /api/cli/authorize M-->>B: redirect to OIDC login, then the dashboard's /cli/select B->>M: POST /api/cli/grant (workspace) M-->>B: 303 to loopback callback with one-time code B->>CLI: GET callback?code=...&state=... CLI->>M: POST /api/cli/token (code) M-->>CLI: token + deploy profileGET /api/cli/authorize stashes the CLI’s loopback callback and state, and routes the browser through OIDC login to a workspace picker at /cli/select. POST /api/cli/grant re-checks the author’s editor access, mints a one-time exchange code and 303-redirects the browser to the loopback callback, so no token crosses the browser. POST /api/cli/token is the only place a token is issued: a workspace-scoped token with a default TTL of 1 hour (OMNIA_AUTH_CLI_TOKEN_TTL_SECONDS), returned with the deploy profile.
authorize and token are public so an unauthenticated CLI can start and finish
the flow. grant needs the browser session and is same-origin only. Token
creation must be enabled for the exchange to succeed. The profile that comes
back is already in the adapter’s config shape, because the CLI merges it into
spec.deploy.config unchanged: the endpoint, the workspace, and every Ready
llm Provider as a {name, ref, role} binding with one named default. It
carries no token, which the CLI stores separately, and no skills, which stay
opt-in. The precise CLI
command that drives the flow lives in the promptarena deploy tooling. See
Set up the deploy config without the export
for the steps.
The adapter config
Section titled “The adapter config”The export produces the contents of spec.deploy.config, the mapping the
promptarena-deploy-omnia adapter consumes, with no config: key of its own,
because promptarena deploy config import deep-merges the file into that
mapping. It holds the endpoint, workspace and token, plus providers bindings (alias,
Provider ref, role) and skills entries that each name a SkillSource as
source. For the shape and a worked example, see
Set up the deploy config without the export.
The deploy-intent API that the config feeds is documented in the
Deploy-intent contract.
From profile to AgentRuntime
Section titled “From profile to AgentRuntime”The adapter does not write CRDs. It sends one versioned DeployIntent to
POST /api/workspaces/{name}/deployments, authenticated with the workspace-scoped
token. management-api forwards the document opaquely to the operator’s deploy-intent
API with an identity token carrying the caller. The operator validates the intent
and creates the Kubernetes objects:
- a PromptPack and its content ConfigMap, holding the compiled pack (see
the PromptPack reference). Skills attach here:
the intent’s
pack.skillsbecomes the PromptPack’sspec.skills, each entry naming a SkillSource. - an AgentRuntime whose
promptPackRefpoints at the pack and whosespec.providerscarries the bindings, with thedefaultbinding as the primary LLM.
The AgentRuntime exposes the runtime through
spec.facades[], a list of facade entries that
each serve one protocol. A pack deployed for browser chat lands as a single
websocket facade on port 8080 (the default). An agent can expose more surfaces,
for example an additional a2a entry, by listing more facade entries. The operator
then reconciles the AgentRuntime into a Deployment and Service, and the pack is
live.
The adapter config has no field for a cloud-specific ServiceAccount name, so an
AgentRuntime created this way carries none of its own. It falls back to the
workspace’s spec.runtime.serviceAccountName
default, so a keyless provider (auth.type: workloadIdentity) still
authenticates as long as the workspace configured that default.
Why the intent, not the CRD
Section titled “Why the intent, not the CRD”The alternative is for each client to author AgentRuntime bodies itself. The
/agents and /promptpacks routes management-api serves work that way: they
apply the caller’s spec to the Kubernetes API unchanged, and the only validation
is the CRD’s own OpenAPI and CEL schema. The dashboard’s deploy wizard uses them.
That keeps management-api free of schema knowledge, but every client then owns a copy of the
AgentRuntime schema, and a client that falls behind the CRD is rejected by the
apiserver (for example 422 spec.facades: Required value).
The DeployIntent moves that ownership to the operator. The adapter sends a
description of the deploy, the operator maps it onto whatever the installed CRDs
look like, and an adapter built against an older cluster keeps working. The
contract is versioned by apiVersion: the operator serves
deploy.omnia.altairalabs.ai/v1 and answers anything else with 400. The deploy
profile lists the accepted versions in supportedDeployIntentVersions, so an
adapter can check before it posts. The cost is a second schema to maintain, in
the operator’s internal/api/deploy package, which has to grow with the CRDs.
A breaking AgentRuntime change still has to ship with the in-app deploy wizard, because the wizard authors AgentRuntime bodies directly.
Upgrading the CRDs
Section titled “Upgrading the CRDs”Upgrade the CRDs first, as their own release. They ship in a separate chart,
omnia-crds, so helm upgrade omnia-crds can apply schema changes. The app
chart’s own helm upgrade never touches them:
helm upgrade omnia-crds oci://ghcr.io/altairalabs/charts/omnia-crds \ --version <version> -n omnia-systemSkipping this leaves a new operator binary reconciling objects against an old CRD
schema. The app chart’s preflight refuses to install or upgrade against older
CRDs, so a normal helm upgrade omnia cannot skip the step unless you set
crdPreflight.enabled=false.
Related
Section titled “Related”- Deploy a PromptPack to Omnia: the walkthrough.
- Set up the deploy config without the export: browser login and manual setup.
- Deploy-intent contract: endpoints, result semantics and what a redeploy preserves.
- PromptPack reference: the resource the deploy creates.
- AgentRuntime reference:
spec.facades[]and provider binding.