Write a deploy adapter
Deploy a pack from your own tooling (a CI step, a plugin, a CLI in another repository) by posting a deploy-intent document to the dashboard.
To publish a pack with the existing promptarena-deploy-omnia adapter, follow Deploy a PromptPack to Omnia. For why the API takes an intent instead of CRDs, see The PromptPack Deploy Program.
Prerequisites
Section titled “Prerequisites”- A workspace, and an
omnia_sk_API key with theeditorrole on it. See API keys. - The dashboard’s external URL, as
OMNIA_ENDPOINT. - A pack to deploy: the
pack.jsoncontent, a name and a version.
The commands below use OMNIA_TOKEN for the key, OMNIA_ENDPOINT for the URL and WORKSPACE for the workspace name.
1. Read the deploy profile
Section titled “1. Read the deploy profile”Fetch the profile before every deploy. It needs the viewer role.
curl -sS \ -H "Authorization: Bearer $OMNIA_TOKEN" \ "$OMNIA_ENDPOINT/api/workspaces/$WORKSPACE/deploy-profile"The response looks like this (illustrative values):
{ "api_endpoint": "https://omnia.example.com", "workspace": "acme", "providers": [ { "name": "openai-gpt4", "role": "llm", "type": "openai", "model": "gpt-4o" } ], "skills": [ { "name": "runbooks", "type": "git" } ], "supportedDeployIntentVersions": ["deploy.omnia.altairalabs.ai/v1"]}Use it as follows:
- Check that
supportedDeployIntentVersionscontains theapiVersionyou send. An unknownapiVersionreturns 400. - Set each provider binding’s
refto aproviders[].namevalue. These are Provider names. A deploy never creates a Provider. The profile lists onlyReadyProviders with thellmrole. - Use
skills[].namefor any pack skills you reference.
The profile never contains a secret.
2. Build the intent
Section titled “2. Build the intent”A minimal single-agent deploy:
{ "apiVersion": "deploy.omnia.altairalabs.ai/v1", "pack": { "name": "support-pack", "version": "1.4.0", "content": "{\"prompts\": [...]}" }, "agents": [ { "name": "support-bot", "promptName": "triage", "providers": [ { "name": "default", "ref": "openai-gpt4", "role": "llm" } ] } ]}pack.content is the raw pack.json as a string. The operator stores it as opaque bytes in a ConfigMap.
For a pack with three prompts and an agent per prompt, send three entries in agents[], each with its own promptName and its own DNS-safe name.
Every field is listed in api/openapi/openapi.yaml.
Add tools
Section titled “Add tools”To use a registry that already exists, reference it:
{ "tools": { "ref": "shared-http-tools" } }To have the deploy create a registry, send handlers:
{ "tools": { "handlers": [ { "name": "search", "type": "http", "httpConfig": { "url": "https://..." } } ] }}ref and handlers are mutually exclusive, and sending both returns 400. Set useTools: true on each agent that should get the registry.
Add credentials
Section titled “Add credentials”If your handlers need secrets, send the values, keyed by the environment variable names the pack references:
{ "credentials": { "data": { "GITHUB_TOKEN": "ghp_..." } }}The operator writes a Secret it owns and repoints your handlers at it. credentials requires tools.handlers. With tools.ref the request returns 400.
Read the credentials section of the reference before shipping this. A registry that already exists keeps its old Secret references.
3. Post the intent
Section titled “3. Post the intent”Save the document as intent.json and post it:
curl -sS -X POST \ -H "Authorization: Bearer $OMNIA_TOKEN" \ -H "Content-Type: application/json" \ --data @intent.json \ "$OMNIA_ENDPOINT/api/workspaces/$WORKSPACE/deployments"4. Handle the response
Section titled “4. Handle the response”A 200 and a 207 both carry a results array. A 207 means some resources failed while others applied. Read the body before you read the status code:
body = post_deployment(intent).json() # your HTTP call; 200 or 207
for r in body["results"]: if r["action"] == "failed": log.error("%s/%s: %s", r["kind"], r["name"], r["error"]) elif r.get("error"): # Applied, with a caveat worth showing to the user. log.warning("%s/%s: %s", r["kind"], r["name"], r["error"])
if not body["succeeded"]: raise DeployFailed(...)succeededis the verdict. A result can carry anerrorand still have applied, for example an ownership warning or credentials skipped on an existing registry. Do not roll back onerroralone.action: "unchanged"is a success. Packs and their content are create-only, so redeploying the same version changes nothing. Publish a new version to change content.- Show
urlonly when it is present. The dashboard sets it onAgentRuntimeresults as a console link. When it is absent, show no link.
A 409 or 503 also carries results. A 409 means the deploy refused to take over an existing object, such as an agent with create: true whose name is taken. A 503 includes a Retry-After header. See Reading the response.
5. Redeploy
Section titled “5. Redeploy”Posting the same intent again is safe. A redeploy follows these rules:
- Packs and their content are never rewritten. Bump
pack.versionto publish new content. - AgentRuntimes are field-merged. Fields the intent cannot express keep the values whoever set them left, such as node selectors, tolerations, pod overrides, service group, facade ports and async settings.
- The intent owns the fields it can express. Omitting
memory,evalsorexternalAuthturns them off. SetpreserveUnset: trueon the agent to keep the live values instead. - For agents under a version-triggered rollout, read Rollout interaction. Whether your deploy takes the pack pin back depends on whether it leaves the agent in trigger mode.
Verify
Section titled “Verify”Check that every entry in results has an action of created, updated or unchanged and that succeeded is true. Then check the agent:
kubectl get agentruntime support-bot -n <workspace-namespace>The Phase column reaches Running once the agent is serving.
Troubleshooting
Section titled “Troubleshooting”400 on the post
Section titled “400 on the post”The body names the failing rule, for example an unsupported apiVersion, a missing pack.name, an empty providers list, or ref together with handlers. See Rules that live only in validation.
The agent is Failed with reason ProviderNotFound
Section titled “The agent is Failed with reason ProviderNotFound”The Provider named by ref does not exist. Pick a name from the deploy profile.
The agent stays Pending
Section titled “The agent stays Pending”The Provider named by ref exists but is not Ready. Check its status with kubectl get provider.
Related pages
Section titled “Related pages”- Deploy-intent contract: endpoints, result semantics and what a redeploy preserves.
- The PromptPack Deploy Program: how the adapter, the dashboard and the operator fit together.
- Set up the deploy config without the export: browser login and manual adapter setup.