Unique workflow identifier
Workflow Concepts
Overview
Workflows in Hyve are automated deployment pipelines defined as YAML files in Git repositories. They enable consistent, repeatable operations with built-in validation, secret management, and variable substitution.
Automated Pipelines
Define multi-step deployment processes
Requirements Validation
Ensure tools and secrets are available before execution
Variable Substitution
Use environment and workflow variables
Version Controlled
Workflows stored in Git with full history
Workflow Structure
Workflows follow a standard YAML structure:
apiVersion: v1kind: Workflowmetadata: name: deploy-app description: Deploy application to Kubernetestools: - name: kubectl min: "1.28.0"spec: requirements: secrets: - name: DOCKER_TOKEN provider: docker env: APP_NAME: my-app NAMESPACE: default jobs: - name: deploy steps: - name: apply-manifests command: kubectl apply -f manifests/Metadata
metadata.name string required metadata.description string Human-readable description of the workflow
Spec
spec.inputs array Variables that must be present before the workflow runs. When the workflow is executed
as a lifecycle hook (beforeCreate, onCreate, onDelete, afterDelete, preReconcile),
values are injected automatically by the reconciler. When run ad-hoc via hyve workflow run,
any missing inputs are prompted for in the TUI or must be supplied with --set KEY=VALUE on the CLI.
See Workflow Inputs for full details.
spec.preFlight.cluster string Set to "skip" to bypass the kubeconfig setup step before execution. Required for beforeCreate
workflows that need to authenticate to a cloud provider before the cluster exists.
spec.requirements object Prerequisites for workflow execution (tools and secrets)
spec.env object Environment variables available to all jobs
spec.jobs array required List of jobs to execute sequentially
Jobs and Steps
Jobs contain steps that execute commands:
jobs: - name: build steps: - name: docker-build command: docker build -t ${APP_NAME}:latest . - name: docker-push command: docker push ${APP_NAME}:latest
- name: deploy dependsOn: [build] steps: - name: kubectl-apply command: kubectl apply -f manifests/Job Fields
jobs[].name string required Job identifier
jobs[].dependsOn array List of job names that must complete before this job runs
jobs[].steps array required List of steps to execute in sequence
Step Fields
steps[].name string required Step identifier
steps[].command string Single command to execute
steps[].script string Multi-line shell script to execute
Requirements
Workflows can validate prerequisites before execution:
Tool Requirements
Declare required CLI tools under spec.requirements.tools. A version is optional — a bare
name: entry means any installed version is acceptable; version: (if set) is checked
against whatever <tool> --version/-v/version reports, matching or newer.
spec: requirements: tools: - name: kubectl version: "1.28.0" - name: helm version: "3.12.0" - name: docker # any version — just needs to be presentChecked with a plain PATH lookup (exec.LookPath) before the workflow runs — this is a
per-workflow, self-contained check. There’s no hyve.yaml-level tools list it cross-references
and no coordination across workflows; each workflow’s requirements.tools stands alone. There
is no separate hyve-level tools manifest today — whatever’s running hyve reconcile/hyve workflow run (a CI runner, your own machine, a container image you control) needs these tools
on its own PATH already.
Secret Requirements
Load secrets from the environment:
spec: requirements: secrets: - name: DOCKER_TOKEN required: true description: Docker Hub authentication - name: GITHUB_TOKEN required: false description: GitHub API token (optional)Checked with os.Getenv — if a required secret’s environment variable isn’t set, the workflow fails before running with a clear error. provider is optional and only changes the suggestion text in that error for a handful of recognized values (civo, aws, gcp, azure — e.g. suggesting aws configure); it doesn’t look anything up on its own.
Workflow Inputs
spec.inputs declares the environment variables a workflow needs at runtime. This is distinct from spec.requirements.secrets (which loads secrets from storage) — inputs are values the caller must supply.
spec: inputs: - name: HYVE_CLUSTER_NAME description: "Name of the cluster to provision infrastructure for" - name: HYVE_CLUSTER_REGION description: "Cloud region to create resources in" - name: HYVE_CLUSTER_PROVIDER description: "Cloud provider (azure, aws, gcp, civo)" jobs: - name: provision-network steps: - name: create-vnet command: | az network vnet create \ --name ${HYVE_CLUSTER_NAME}-vnet \ --location ${HYVE_CLUSTER_REGION} \ --resource-group ${HYVE_CLUSTER_NAME}-rgAutomatic injection by lifecycle hooks
There’s no fixed, hyve-defined set of provider-specific variables (no HYVE_CLUSTER_PROVIDER, HYVE_AWS_ACCOUNT, or similar) — injection is the same simple, three-part convention every module operation also gets:
| Variable | Source | Available in |
|---|---|---|
HYVE_CLUSTER_NAME | metadata.name | All hooks |
HYVE_CLUSTER_REGION | spec.region | All hooks |
HYVE_PARAM_<KEY> | Each spec.params entry, key uppercased | All hooks |
<key> (as-is) | Each spec.driverOutputs entry — whatever a prior module operation or workflow emitted, under whatever name it chose | All hooks |
onCreate, afterCreate, and onDelete hooks additionally get KUBECONFIG pointed at the cluster’s merged kubeconfig — beforeCreate and afterDelete run without a live cluster, so no kubeconfig is available.
A beforeCreate step’s HYVE_KEY=value output lines are captured and merged into spec.driverOutputs before creation proceeds — so a later step (in the same or a later workflow, or the driver module’s own create.yaml) can reference <KEY> as a plain env var, exactly like any other driverOutputs entry. There’s no separate declaration needed for a specific value to “count” — whatever a beforeCreate step outputs becomes available this way automatically.
Ad-hoc runs
When the same workflow is run outside a cluster lifecycle (e.g., to manually provision
infrastructure), missing inputs are supplied with --set:
hyve workflow run provision-network \ --set HYVE_CLUSTER_NAME=my-cluster \ --set HYVE_CLUSTER_REGION=eastusinputs[].name string required Environment variable name (e.g. HYVE_CLUSTER_NAME)
inputs[].description string Human-readable label shown in the TUI prompt and in hyve workflow show output
inputs[].default string Default value used when no value is supplied. Shown as placeholder in the TUI prompt.
Environment Variables
Define variables at workflow or job level:
Workflow-Level Variables
Available to all jobs:
spec: env: APP_NAME: my-app REGISTRY: docker.io/myuser VERSION: v1.0.0 jobs: - name: build steps: - name: build command: docker build -t ${REGISTRY}/${APP_NAME}:${VERSION} .Job-Level Variables
Available only to specific job:
jobs: - name: deploy env: NAMESPACE: production REPLICAS: "3" steps: - name: deploy command: kubectl scale deployment ${APP_NAME} --replicas=${REPLICAS} -n ${NAMESPACE}Variable Substitution
Hyve supports full shell variable substitution:
steps: - name: example command: echo "Deploying ${APP_NAME} version ${VERSION:-latest} to ${NAMESPACE}"Running Workflows
Basic Execution
# Run workflowhyve workflow run deploy-app
# Run with specific clusterhyve workflow run deploy-app --cluster productionLifecycle Workflows
Workflows can be triggered automatically during cluster lifecycle events:
In Templates
# Template definitionapiVersion: hyve.io/v1alpha1kind: Templatemetadata: name: prod-templatespec: # ... cluster config workflows: beforeCreate: - provision-vpc onCreate: - setup-monitoring - deploy-app afterCreate: - create-app-secrets onDelete: - backup-data afterDelete: - cleanup-vpcIn Cluster Definitions
# Cluster definitionapiVersion: hyve.io/v1alpha1kind: ClusterDefinitionmetadata: name: productionspec: region: NYC1 # ... cluster config workflows: beforeCreate: - provision-network onCreate: - setup-monitoring afterCreate: - create-app-secrets onDelete: - backup-data afterDelete: - cleanup-network| Hook | When It Runs | Cluster Exists? | Kubeconfig Available? | Typical Use Cases |
|---|---|---|---|---|
beforeCreate | Before cluster is created | No | No | Provision VPC, create IAM roles, allocate IP ranges |
onCreate | After cluster is ready, before spec.resources applies | Yes | Yes | Setup monitoring, deploy apps, configure services |
afterCreate | After cluster is ready, after spec.resources has applied | Yes | Yes | Create a Secret a resource-managed Deployment references, DNS pointing at a now-deployed app |
onDelete | Before cluster is deleted | Yes | Yes | Backup data, export logs, cleanup external resources |
afterDelete | After cluster is deleted | No | No | Destroy VPC, remove IAM roles, release IP ranges |
preReconcile | When param drift is detected on an ACTIVE cluster | Yes | Yes | Refresh credentials, sync config before scaling |
Remote Workflow References
Every entry above can also be a remote reference instead of a local name — a workflow pulled from another Git repository, resolved and content-hashed into hyve.lock, the same way modules are referenced via spec.driver.source:
spec: workflows: onCreate: - pre-flight-checks # local, unchanged - source: github.com/myorg/shared-workflows//setup-monitoring.yaml@v1.2.0 # remote, pinned - source: github.com/myorg/shared-workflows//setup-monitoring.yaml # remote, tracks latestThis exists so shared operational workflows — monitoring setup, backup jobs, teardown routines — can live in one repository and be referenced from many, instead of being copied into every state repository that needs them. Version is optional: omit it and Hyve resolves the latest commit once and locks the resolved SHA, exactly like an unversioned module reference.
A lifecycle hook entry must resolve to a single workflow file — a directory-form source (used for bulk-installing a whole set of workflows via hyve workflow install) is rejected if placed directly in a hook. See hyve workflow for the full source-string format, path resolution rules, and name-resolution order for hyve workflow run.
Auth-Bootstrap Workflows (preFlight.cluster: skip)
Some beforeCreate workflows need to authenticate to a cloud provider to provision
resources (e.g. create an EKS IAM role or VPC) before the cluster exists. By default
Hyve tries to set up kubeconfig before running any workflow. Set preFlight.cluster: skip
in the workflow spec to bypass the kubeconfig setup step:
apiVersion: v1kind: Workflowmetadata: name: provision-iam-rolesspec: preFlight: cluster: skip # skip EKS DescribeCluster + kubeconfig sync jobs: - name: create-roles steps: - name: create-eks-role script: | aws iam create-role --role-name eks-cluster-role \ --assume-role-policy-document file://eks-trust-policy.json echo "HYVE_EKS_ROLE_NAME=eks-cluster-role"The HYVE_EKS_ROLE_NAME=eks-cluster-role output line is captured by the reconciler as a
driver output and injected as the HYVE_EKS_ROLE_NAME environment variable into every
later hook and module operation for this cluster — for example the module’s create
operation can read it to reference the role it depends on.
Execution Flow
Load Workflow
Read workflow YAML from repository
Validate Requirements
Check tools and secrets
[INFO] Validating workflow requirements...[INFO] ✅ All requirements validated successfullySet Environment
Load environment variables and secrets
export APP_NAME=my-appexport DOCKER_TOKEN=***Execute Jobs
Run jobs in sequence
[INFO][build] Starting job 'build'[INFO][build][docker-build] Running step 'docker-build'Report Results
Show success or failure
[INFO] Workflow 'deploy-app' completed successfullyWorkflow Types
Deployment Workflow
Deploy applications to Kubernetes:
apiVersion: v1kind: Workflowmetadata: name: deploy-apptools: - name: kubectl min: "1.28.0"spec: env: APP_NAME: my-app jobs: - name: deploy steps: - name: apply command: kubectl apply -f manifests/ - name: wait command: kubectl rollout status deployment/${APP_NAME}Build Workflow
Build and push Docker images:
apiVersion: v1kind: Workflowmetadata: name: build-imagetools: - name: dockerspec: requirements: secrets: - name: DOCKER_TOKEN provider: docker env: IMAGE: myapp TAG: latest jobs: - name: build steps: - name: docker-build script: | echo "$DOCKER_TOKEN" | docker login -u myuser --password-stdin docker build -t ${IMAGE}:${TAG} . docker push ${IMAGE}:${TAG}Infrastructure Workflow
Provision infrastructure with Terraform:
apiVersion: v1kind: Workflowmetadata: name: provision-infratools: - name: terraform min: "1.5.0"spec: requirements: secrets: - name: AWS_ACCESS_KEY_ID provider: aws - name: AWS_SECRET_ACCESS_KEY provider: aws jobs: - name: provision steps: - name: init command: terraform init - name: plan command: terraform plan - name: apply command: terraform apply -auto-approveCommands vs Scripts
Single Commands
For simple operations:
steps: - name: deploy command: kubectl apply -f manifests/Multi-Line Scripts
For complex operations:
steps: - name: deploy script: | echo "Starting deployment..." kubectl apply -f manifests/ kubectl rollout status deployment/my-app echo "Deployment complete!"Job Dependencies
Control execution order with dependencies:
jobs: - name: test steps: - name: run-tests command: npm test
- name: build dependsOn: [test] steps: - name: docker-build command: docker build -t myapp .
- name: deploy dependsOn: [build] steps: - name: kubectl-apply command: kubectl apply -f manifests/Execution order: test → build → deploy
Error Handling
Workflows stop on first error:
jobs: - name: deploy steps: - name: test command: npm test # If this fails, workflow stops
- name: deploy command: kubectl apply -f manifests/ # This won't runBest Practices
1. Use Descriptive Names
Name workflows, jobs, and steps clearly:
metadata: name: deploy-api-production description: Deploy API service to production cluster
jobs: - name: run-tests steps: - name: unit-tests - name: integration-tests2. Declare Tool Requirements
Declare required tools at the top level with optional version constraints:
tools: - name: kubectl min: "1.28.0"spec: requirements: secrets: - name: DOCKER_TOKEN provider: docker required: true3. Use Environment Variables
Avoid hardcoding values:
# Goodenv: NAMESPACE: productionsteps: - name: deploy command: kubectl apply -f manifests/ -n ${NAMESPACE}
# Badsteps: - name: deploy command: kubectl apply -f manifests/ -n production4. Document Workflows
Add descriptions explaining purpose:
metadata: name: deploy-app description: | Deploy application to Kubernetes cluster - Runs tests first - Builds Docker image - Deploys to cluster - Waits for rollout5. Test in Development
Test workflows in development before production:
# Switch to developmenthyve context use development
# Test workflowhyve workflow run deploy-app --cluster dev-cluster
# If successful, run in productionhyve context use productionhyve workflow run deploy-app --cluster prod-clusterWorkflow Examples
Complete Deployment Pipeline
apiVersion: v1kind: Workflowmetadata: name: complete-pipeline description: Full CI/CD pipelinetools: - name: docker - name: kubectl min: "1.28.0" - name: helm min: "3.12.0"spec: requirements: secrets: - name: DOCKER_TOKEN provider: docker - name: DATADOG_API_KEY provider: datadog required: false
env: APP_NAME: my-app REGISTRY: docker.io/myuser VERSION: v1.0.0
jobs: - name: test steps: - name: unit-tests command: npm test - name: lint command: npm run lint
- name: build dependsOn: [test] steps: - name: docker-build script: | echo "$DOCKER_TOKEN" | docker login -u myuser --password-stdin docker build -t ${REGISTRY}/${APP_NAME}:${VERSION} . docker push ${REGISTRY}/${APP_NAME}:${VERSION}
- name: deploy dependsOn: [build] env: NAMESPACE: production steps: - name: helm-upgrade command: | helm upgrade --install ${APP_NAME} ./chart \ --set image.tag=${VERSION} \ --namespace ${NAMESPACE} - name: wait-rollout command: kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE}
- name: notify dependsOn: [deploy] steps: - name: send-notification script: | if [ -n "$DATADOG_API_KEY" ]; then echo "Sending notification to Datadog..." # Send notification fi