Skip to content

PromptPack CRD

A PromptPack is a versioned collection of prompts for AI agents, sourced from a ConfigMap containing a pack.json file in the PromptPack format. The controller validates pack.json against the PromptPack JSON Schema before activating it, using the copy built into the operator unless the Helm value operator.promptPackSchema.source is network.

A live PromptPack (source.type: live) points at an authored Arena project instead. A PromptPackSource of type project creates it, and the runtime compiles the project’s current source when a session opens.

apiVersion: omnia.altairalabs.ai/v1alpha1
kind: PromptPack

Short name: pp (e.g. kubectl get pp).

A published PromptPack version is an immutable release: the whole spec is frozen after create (CEL: self == oldSelf). To change anything, publish a new version.

Logical pack identity. Required. Versions of the same pack share a packName; an AgentRuntime’s spec.promptPackRef.name references it.

spec:
packName: customer-service

Semantic version of this pack. Required, and must match ^(\d+)\.(\d+)\.(\d+)(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?(\+[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$ (e.g. 1.0.0, 2.1.0-beta.1), or the literal live. A leading v is rejected. The deploy API and PromptPackSource strip one from the version they are given. live is required when source.type is live and rejected otherwise (CEL-validated).

An AgentRuntime pin matches version as an exact string, including build metadata, so 1.0.0+gAAAA and 1.0.0+gBBBB are two different packs. For channel ordering, though, semver gives the two versions equal precedence, so the one created later serves the channel. The other becomes Superseded, with DuplicateVersion True. To avoid the tie, give each publish a distinct MAJOR.MINOR.PATCH or prerelease.

spec:
version: "2.0.0"

Source of the compiled PromptPack content.

FieldTypeRequiredDescription
source.typeconfigmap | liveYesSource type
source.configMapRef.namestringWhen type is configmapName of the ConfigMap
source.live.sourceRefstringWhen type is liveName of the PromptPackSource that created the pack, in the same namespace
source.live.project.idstringWhen type is liveID of the Arena project whose source is the content
source.live.project.userstringWhen type is livePseudonym of the user whose working clone of the project (arena/workspaces/<id>/<user>) the agent mounts and compiles. A project has no shared copy, so a live pack always runs one user’s clone.

source.live is required for type live, where configMapRef is rejected, and is rejected for type configmap (CEL-validated). The ConfigMap must contain a pack.json key with valid PromptPack JSON content.

A live pack is dev-only. The controller does not resolve the project, validate a schema, compute contentDigest or place the pack on a channel: it sets SourceValid True with reason LiveSource and the phase to Active. An AgentRuntime may reference it only without version or track, and never from a rollout (see AgentRuntime promptPackRef).

spec:
source:
type: configmap
configMapRef:
name: my-prompts # ConfigMap must have pack.json key

Skills to expose to agents using this pack. Every entry goes through a SkillSource; inline skill content is not accepted.

FieldTypeRequiredDescription
sourcestringYesName of a SkillSource in the pack’s own namespace
includestring[]NoKeep only skills whose SKILL.md frontmatter name matches an entry. Empty keeps every skill the source synced
mountAsstringNoGroup name the skills are exposed under (pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$). Defaults to the basename of the source’s status.artifact.contentPath, which is the synced content version
FieldTypeDefaultDescription
maxActiveint32 (min 1)Unlimited if omittedCap on concurrently active skills
selectormodel-driven | tagmodel-drivenWhich skills the model is offered in the Phase-1 index. model-driven offers all of them and lets the model activate what it needs. tag offers only skills whose SKILL.md metadata tags (comma-separated) shares an entry with tags
tags[]string—Tags the tag selector matches. Required when selector is tag; ignored otherwise. A skill with no tags metadata is never offered by the tag selector

Current phase of the PromptPack.

ValueDescription
PendingNot validated
ActiveValid, and the highest version of its packName on the stable or the prerelease channel
SupersededA newer validated version has been published on its channel, or a sibling of equal semver precedence was created later (see DuplicateVersion). A superseded version still serves any AgentRuntime pinned to it
FailedSource or schema validation failed

The pack’s spec.version while it is Active; cleared when it becomes Superseded.

sha256:<hex> of the resolved pack.json, recomputed every reconcile. The operator stamps it onto agent pods, which record it on each session, so a stored result names the content that produced it.

sha256:<hex> of pack.json when the operator first saw this version. Set once and never changed. ContentDrift compares contentDigest against it.

The pack’s own metadata block, lifted out of pack.json verbatim.

The typed reading of metadata.governance (see below), with a synthesised declared list naming the fields the pack actually stated. extensions is not carried. Absent when the pack declares no governance block.

Hash of the resolved skill manifest — identifies the skill content in force. Empty when the pack declares no skills.

Timestamp of the last status update.

TypeDescription
ReadyRoll-up of SourceValid, SchemaValid and the three skill conditions; inherits the first failing one’s reason and message
SourceValidConfigMap exists and contains pack.json key. For a live pack, True with reason LiveSource when source.live is set
SchemaValidpack.json content conforms to the PromptPack schema
SkillsResolvedEvery spec.skills[].source names an existing SkillSource (True with reason NoSkills when none are declared)
SkillsValidNo skill-name collisions across sources after include
SkillToolsResolvedEvery resolved skill’s allowed-tools is declared by the pack
ContentDriftTrue is the bad state. True, with a Warning event, while contentDigest differs from publishedDigest: pack.json changed under a published version. Stays True until the content returns to the published digest. The pack keeps serving
SupersededTrue is the bad state. True when a newer version has been published on this version’s channel, or (reason DuplicateVersion) when a sibling of equal semver precedence won the publish-order tiebreak
DuplicateVersionTrue is the bad state. Set True, with a Warning event, when a sibling whose version differs only in build metadata (equal semver precedence) was created later and serves the channel instead. Absent unless a tie has occurred; False once it is resolved
AgentsNotifiedReports how many AgentRuntimes reference this pack (reason NoAgentsToNotify when none)

See PromptPack validation for how source and schema validation run, and how failures surface as Kubernetes events.

The referenced ConfigMap must contain a pack.json key with a compiled PromptPack following the PromptPack specification:

apiVersion: v1
kind: ConfigMap
metadata:
name: my-prompts
data:
pack.json: |
{
"id": "customer-service",
"name": "Customer Service Assistant",
"version": "1.0.0",
"template_engine": {
"version": "v1",
"syntax": "{{variable}}"
},
"prompts": {
"support": {
"id": "support",
"name": "General Support",
"version": "1.0.0",
"system_template": "You are a helpful customer service agent for {{company_name}}. Be professional, empathetic, and solution-oriented.",
"variables": [
{
"name": "company_name",
"type": "string",
"required": true,
"description": "Name of the company"
}
],
"parameters": {
"temperature": 0.7,
"max_tokens": 1024
},
"validators": {
"banned_words": ["competitor", "lawsuit"]
}
}
},
"metadata": {
"domain": "customer-service",
"language": "en",
"tags": ["support", "helpdesk"]
}
}
FieldTypeRequiredDescription
idstringYesUnique identifier (lowercase, hyphens allowed)
namestringYesHuman-readable name
versionstringYesSemantic version (MAJOR.MINOR.PATCH)
template_engineobjectYesTemplate configuration
promptsobjectYesMap of prompt definitions
metadataobjectNoDomain, language, tags, and the governance block (below)
toolsobjectNoTool definitions for function calling
fragmentsobjectNoReusable template fragments

Records what the agent is for and how far it may act alone (promptpack-spec RFC 0013). Values are asserted by the pack’s author: readers may use them to tighten a policy, never to relax one.

Every field is optional; an omitted field means undeclared, not a safe default. RFC 0013 forbids inferring one from absence.

FieldTypeDescription
intended_purposestringWhat the agent is for
foreseeable_misusestring[]Ways it could be misused
autonomy_levelstringHow far it acts without a human
accountable_ownerstringWho answers for it
operator_rolestringProvider or deployer
risk_classificationstringThe author’s risk position — a legal judgement, never derived
intended_deployment_contextsstring[]Where it is meant to run
capabilitiesstring[]What it can do
approved_environmentsstring[]Where it is approved to run
requires_ai_disclosurebooleanWhether a human counterparty must be told this is an AI
vocabulariesobjectVocabulary URIs the values are drawn from
extensionsobjectFirm-specific additions

Two of these have runtime behaviour:

  • requires_ai_disclosure is delivered to clients and recorded on each session. See Disclose That an Agent Is an AI.
  • The whole block is exposed to ToolPolicy CEL rules as governance, so a rule can gate on what an agent declared. governance.declared lists the fields the pack stated, distinguishing undeclared from empty.

A pack carries eval definitions in a pack-level evals array and in each prompt’s evals array, next to validators. A prompt-level eval overrides a pack-level eval with the same id. The eval worker runs the pack-level evals plus those of the prompt the runtime opens the pack at: workflow.entry, then agents.entry, then the only prompt, then default. Realtime evals run these definitions against live sessions. See Realtime evals for how.

FieldTypeRequiredDescription
idstringYesIdentifier, unique within its scope
typestringYesRegistered eval type, for example llm_judge, contains, regex or guardrail_triggered
triggerstringYesWhen the eval fires (below)
paramsobjectNoType-specific parameters
sample_percentagenumberNoPercentage of turns or sessions to run, for sample_turns and sample_sessions. Default 5
enabledbooleanNoDefault true
TriggerFires
every_turnAfter each assistant message
sample_turnsAfter a hash-sampled share of assistant messages
on_session_completeWhen the session completes
sample_sessionsOn a hash-sampled share of completed sessions

on_conversation_complete and on_workflow_step are valid values that realtime evals do not fire.

Eval typeParametersCost
llm_judgecriteria (required), rubric, model, provider (name of a spec.providers entry)One LLM call
containspatterns (all must appear, case-insensitive). content_includes is an aliasNone
regexpattern, expect_matchNone
guardrail_triggeredvalidator, should_triggerNone

For the complete specification, see promptpack.org.

apiVersion: omnia.altairalabs.ai/v1alpha1
kind: PromptPack
metadata:
name: customer-service
namespace: agents
spec:
packName: customer-service
version: "2.0.0"
source:
type: configmap
configMapRef:
name: cs-prompts-v2

Status after deployment:

status:
phase: Active
activeVersion: "2.0.0"
conditions:
- type: SourceValid
status: "True"
reason: SourceValid
message: "Source configuration is valid"
- type: SchemaValid
status: "True"
reason: SchemaValid
message: "pack.json content is valid"
- type: AgentsNotified
status: "True"
reason: AgentsNotified
message: "Notified 3 AgentRuntime(s)"

See Author and compile a PromptPack for writing PromptPacks in YAML and compiling with packc.