Red Hat Field CTO engineering tool. Converts Red Hat AI Quickstarts into Validated Patterns — production-ready, GitOps-driven OpenShift deployments. Two authoring paths:
quickpat create— analyzes an existing Quickstart Helm chart and generates a VP automaticallyquickpat compose— compiles a declarativeApplicationSpecinto either a VP or a Quickstart Helm chart
- Analyze — parse the upstream Helm chart: extract resource types, detect operator indicators, classify secrets as prompt/generate/skip, identify GPU requirements, flag stale deps and local forks
- Generate — produce the VP directory:
values-prod.yaml(namespaces, subscriptions, ArgoCD apps),values-secret.yaml.template(Vault secret groups), infra charts (DSC, NFD, ClusterPolicy), ExternalSecret templates, platform overrides, Makefile,pattern.sh - Validate — check the generated output against Patternizer conventions; auto-fix common issues up to N iterations
The upstream chart remains the ArgoCD application source (remote strategy). The VP adds the operator lifecycle, secrets framework, and GitOps layer around it.
- Parse — load
ApplicationSpecYAML: 8 block types, custom components, wiring, device modes, upstream overrides - Compile — collect operators from blocks, resolve DSC component states (auto-injecting
llamastackoperatorwhen a llama-stack block is present, etc.), detect existing hand-written charts in the application repo, build configuration - Generate VP — same generator as Path 1, but config-driven from blocks; infra charts (DSC, ClusterPolicy) use block-specific config; platform overrides carry storage provider hints; device overrides (values-gpu.yaml) hold GPU operators when
devices: [cpu, gpu]is declared - Generate QS — separate generator produces a self-contained Helm chart: provider-conditional object storage templates (minio/odf/s3), inline Tekton Pipeline + Task for data ingestion, LlamaStack Deployment + Service, model-serving InferenceService + ServingRuntime, NOTES.txt prerequisites,
values.yamlwith Helm references,scripts/create-secrets.sh
The application repo (e.g. github.com/atyronesmith/lemonade-stand) contains spec.yaml + hand-written custom component charts. Both vp-out/ and qs-out/ are committed alongside the source. One spec, two deployment targets.
Requires Python 3.10+ and uv.
git clone git@github.com:atyronesmith/quickpat.git
cd quickpat
uv sync
uv run quickpat --helpquickpat create RAG --non-interactive# VP output — writes to vp-out/ next to spec.yaml
quickpat compose my-app/spec.yaml
# QS Helm chart — writes to qs-out/ next to spec.yaml
quickpat compose my-app/spec.yaml --format qs
# Skip RBAC for ODF setup Job (strict RBAC environments)
quickpat compose my-app/spec.yaml --format qs --no-create-service-accountSee docs/compose-tutorial.md for a complete walkthrough. Reference implementations:
- lemonade-stand — TrustyAI guardrails demo, 6 blocks + 5 custom components
- rag-chatbot — RAG + LlamaStack agents, 6 blocks + 1 custom component
quickpat [--patterns-dir DIR] <command> [options]
Generate a VP from a quickstart source (interactive or --non-interactive).
quickpat create RAG
quickpat create https://github.com/rh-ai-quickstart/RAG
quickpat create /path/to/local/chart --non-interactiveCompile an ApplicationSpec into a VP or QS Helm chart.
| Option | Description |
|---|---|
--format vp|qs |
Output format: vp (Validated Pattern, default) or qs (Helm chart) |
--output, -o DIR |
Output directory (default: vp-out/ or qs-out/ next to spec.yaml) |
--name NAME |
Pattern name override |
--no-fix |
Skip auto-fix validation pass (VP only) |
--create-service-account / --no-create-service-account |
Generate RBAC for ODF setup Job (default: true) |
Publish a committed vp-out/ tree to an immutable, versioned tag (vp-v1, vp-v2, ...)
whose content sits at the tag's own root. Required for the VP path's ongoing GitOps
reconciliation to work: the Validated Patterns Operator's Pattern CRD has no field for a
subdirectory path — it always clones the whole repo and expects values-global.yaml,
values-prod.yaml, Makefile, pattern.sh, and charts/ at the repo root. Any repo
layout that nests vp-out/ under something else (e.g. alongside qs-out/, spec.yaml,
docs/) will pass a local ./pattern.sh make install but fail a live Pattern CR's
reconciliation with required values file not found: values-prod.yaml until its content
is published this way.
# commit vp-out/ first — publish-vp refuses a dirty tree by default
quickpat publish-vp # defaults to ./vp-out
quickpat publish-vp --dry-run # preview the next tag without writing anything| Option | Description |
|---|---|
vp_out_dir (positional) |
Path to the vp-out directory (default: vp-out) |
--remote NAME |
Git remote to query/push (default: origin) |
--repo-url URL |
Override remote URL instead of resolving --remote |
--tag-prefix PREFIX |
Version tag prefix (default: vp-v) |
-m, --message MSG |
Commit/tag message override |
--pattern-name NAME |
Pattern name for the printed oc patch hint (default: from pattern-metadata.yaml) |
--namespace NS |
Namespace for the oc patch hint (default: patterns-operator) |
--allow-dirty |
Publish on-disk content even with uncommitted changes |
--dry-run |
Show what would be published without creating or pushing anything |
Each publish is tagged vp-v{N}, with N derived from the remote's existing tags (never
stored locally, since pattern-metadata.yaml is regenerated every compose run) and
chained to the previous tag's commit — so any two published versions can be diffed
directly (git diff vp-v3 vp-v7) and a live environment's Pattern CR can stay pinned to
a known-good version until someone deliberately repoints it. An unchanged republish is a
no-op. Repointing a live Pattern CR is intentionally not automated — the command
only prints the oc patch command to run.
Analyze a quickstart — detect operators, dependencies, secrets, features.
Validate a generated pattern for Patternizer conformance. --fix runs auto-repair.
List available quickstarts from the ai-quickstart-pub registry.
A composition spec declares the application in terms of building blocks. The compiler handles operator subscriptions, DSC configuration, infra chart generation, and secrets wiring.
apiVersion: supplychain/v1alpha1
kind: ApplicationSpec
metadata:
name: my-app
description: My AI application
tier: sandbox # sandbox | tested | maintained
# devices: supported deployment modes — generates per-device override files.
# GPU operators move to values-gpu.yaml instead of values-prod.yaml.
devices: [cpu, gpu]
upstream:
repo: https://github.com/rh-ai-quickstart/RAG.git
path: deploy/helm/rag
branch: main
# extraValues: written to overrides/<app-name>.yaml, passed to upstream
# chart via extraValueFiles in the ArgoCD app entry.
extraValues:
llm-service:
secret:
enabled: false
# ignoreDifferences: resources ArgoCD should not reconcile.
ignoreDifferences:
- group: route.openshift.io
kind: Route
jsonPointers: [/spec/host]
blocks:
platform:
type: ai-platform-foundation
config:
dsc:
kserve: Managed
dashboard: Managed
datasciencepipelines: Managed
gpu:
type: gpu-compute
config:
mig_strategy: none
dcgm: true
llm:
type: model-serving
config:
model: meta-llama/Llama-3.2-3B-Instruct
runtime: vllm
gpu: true
storage:
type: oci
uri: oci://quay.io/redhat-ai-services/modelcar-catalog:llama-3.2-3b-instruct
db:
type: vector-store
config:
database: ragdb
store:
type: object-storage
config:
provider: minio # minio | odf | s3
bucket: documents
ingest:
type: data-pipeline
config:
sources:
- name: docs
type: s3
schedule: manual
chunk_size: 512
inputs:
vector_store: db
object_storage: store
llm-server:
type: llama-stack
config:
port: 8321
inputs:
llm: llm
vector_store: db
wiring:
- from: store
to: ingest
via: document-staging
- from: llm
to: llm-server
via: inference-backend
custom:
my-ui:
description: Custom chat UI
source:
image: quay.io/myorg/my-ui:latest
replicas: 1
ports:
- name: http
port: 8080
route: true
tls: { termination: edge }| Block | Coverage | What it provides |
|---|---|---|
ai-platform-foundation |
85% of QSs | OpenShift AI + Serverless + Service Mesh; DataScienceCluster CR |
gpu-compute |
66% | NFD + NVIDIA GPU Operator; ClusterPolicy CR |
model-serving |
33%+ | KServe ServingRuntime + InferenceService (vLLM or custom runtime) |
vector-store |
47% | pgvector Deployment + Service + credentials |
object-storage |
66% | MinIO / ODF / S3 — provider-conditional templates |
data-pipeline |
9% (growing) | Tekton Pipeline + Task; input resolution from vector_store + object_storage |
guardrails-orchestrator |
9% | TrustyAI GuardrailsOrchestrator CR + ConfigMap |
llama-stack |
— | LlamaStack server; auto-injects llamastackoperator: Managed into DSC |
sso-auth |
14% | Keycloak CR + Realm |
| File | minio | odf | s3 |
|---|---|---|---|
| PVC + Deployment (MinIO) | ✅ | — | — |
| Bucket-init container | ✅ | — | — |
| ObjectBucketClaim | — | ✅ | — |
| ODF setup Job + RBAC | — | ✅ | — |
data-connection Secret |
✅ always | ✅ (written by Job) | ✅ always |
my-app/
├── spec.yaml ← source of truth (edit this)
├── charts/ ← hand-written custom component charts
│ └── <component>/
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
├── vp-out/ ← generated VP (ArgoCD target, committed)
│ ├── values-prod.yaml ← namespaces, subscriptions, ArgoCD apps
│ ├── values-global.yaml
│ ├── values-secret.yaml.template
│ ├── charts/
│ │ ├── dsc/ ← DataScienceCluster CR
│ │ ├── nfd/ ← NodeFeatureDiscovery CR
│ │ ├── nvidia-config/ ← ClusterPolicy CR
│ │ └── <app>-secrets/ ← ExternalSecret templates
│ ├── overrides/
│ │ ├── values-AWS.yaml ← storage provider hints per platform
│ │ ├── values-gpu.yaml ← GPU operators (when devices declared)
│ │ ├── values-cpu.yaml
│ │ └── <app-name>.yaml ← upstream.extraValues or custom.extraValues /
│ │ copied from source overrides/ via extraValueFiles
│ ├── Makefile, Makefile-common, pattern.sh, pattern-metadata.yaml
│ └── ansible.cfg, .gitignore, LICENSE
└── qs-out/ ← generated QS Helm chart (helm install target, committed)
├── chart/
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
│ ├── NOTES.txt
│ ├── <block>/ ← inline Kubernetes manifests per block
│ └── <component>/ ← copied from charts/ (custom components)
├── scripts/
│ └── create-secrets.sh
└── README.md
Generated VP output is validated against Patternizer v1.3.1+ conventions:
- Map-form namespaces (
vault: {}not- vault) - ESO backtick escaping in ExternalSecret templates
TARGET_VARIANTinpattern.shansible-playbook env block- Local chart paths at
charts/<name>/ values-secret.yaml.templateversion 2.0 withvaultPrefixes
quickpat/
├── quickpat/
│ ├── cli.py — CLI entry point (compose, create, analyze, validate, ...)
│ ├── generator.py — VP file generator (values-prod, infra charts, overrides, secrets)
│ ├── analyzer.py — Helm chart parser + operator/secret/feature detection
│ ├── validator.py — Pattern validation + auto-fix loop
│ ├── pipeline.py — Orchestration: parse → compile → generate → validate
│ ├── operators.py — Operator registry + INFRA_CHARTS (DSC, NFD, ClusterPolicy)
│ └── compose/
│ ├── parser.py — ApplicationSpec + BlockInstance dataclasses
│ ├── blocks.py — Block type registry (9 types → operators)
│ ├── compiler.py — Spec → (analysis, config) for PatternGenerator
│ ├── block_templates.py — QS inline manifest generators per block type
│ ├── qs_generator.py — QS chart directory writer
│ └── renderer.py — Jinja2 context builder for block template refs
├── tests/ — 439 tests
├── examples/
│ ├── sample-spec.yaml
│ └── lemonade-stand-compose.yaml
└── docs/
├── compose-tutorial.md — Full ApplicationSpec walkthrough
└── decision-points.md
Apache License 2.0. See LICENSE for details.