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 — see the Server Mode guide
for the recommended way to make sure a hyve serve container actually has what it needs
(bake tools into the image at build time; an admin-triggered workflow to patch a running
container as the fallback).
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
All lifecycle hooks receive the following HYVE_* variables from the cluster definition automatically:
| Variable | Source | Available in |
|---|---|---|
HYVE_CLUSTER_NAME | metadata.name | All hooks |
HYVE_CLUSTER_REGION | metadata.region | All hooks |
HYVE_CLUSTER_PROVIDER | spec.provider | All hooks |
HYVE_CLUSTER_TYPE | spec.clusterType | All hooks |
HYVE_CLUSTER_K8S_VERSION | spec.kubernetesVersion | All hooks |
HYVE_AWS_ACCOUNT | spec.awsAccount | All hooks (AWS) |
HYVE_GCP_PROJECT | spec.gcpProject | All hooks (GCP) |
HYVE_AZURE_SUBSCRIPTION | spec.azureSubscription | All hooks (Azure) |
HYVE_CIVO_ORG | spec.civoOrganization | All hooks (Civo) |
HYVE_CLUSTER_ACCOUNT_ID | resolved AWS account ID | All hooks (AWS) |
HYVE_CLUSTER_VPC_ID | spec.awsVpcId | All hooks (AWS) |
| Provider credentials | provider-configs/*.yaml | All hooks |
Only the account variable that matches the cluster’s provider is set — the others are left unset.
onCreate, afterCreate, and onDelete hooks additionally receive live cluster data:
| Variable | Description |
|---|---|
HYVE_CLUSTER_IP_ADDRESS | Cluster API endpoint IP |
HYVE_CLUSTER_ACCESS_PORT | Cluster API port |
HYVE_CLUSTER_ID | Cloud provider cluster ID |
HYVE_CLUSTER_STATUS | Cluster status string |
HYVE_CLUSTER_KUBECONFIG | Path to cluster kubeconfig |
KUBECONFIG | Same as HYVE_CLUSTER_KUBECONFIG |
HYVE_CLUSTER_OIDC_URL | EKS OIDC provider URL (AWS only) |
beforeCreate and afterDelete hooks run without a live cluster — kubeconfig injection is skipped.
Output variables printed by a beforeCreate step in HYVE_KEY=value format are captured by the
reconciler and written back to the cluster definition before creation proceeds. Supported output
variables include:
| Output Variable | Effect |
|---|---|
HYVE_VPC_ID | Sets spec.awsVpcId |
HYVE_EKS_ROLE_NAME | Sets spec.awsEksRoleName |
HYVE_NODE_ROLE_NAME | Sets spec.awsNodeRoleName |
HYVE_EKS_ROLE_ARN | Sets spec.awsEksRoleArn |
HYVE_NODE_ROLE_ARN | Sets spec.awsNodeRoleArn |
HYVE_CLUSTER_SG_ID | Sets spec.awsClusterSgId |
HYVE_WORKER_SG_ID | Sets spec.awsWorkerSgId |
Ad-hoc runs
When the same workflow is run outside a cluster lifecycle (e.g., to manually provision infrastructure), missing inputs are handled as follows:
CLI — supply with --set:
hyve workflow run provision-network \ --set HYVE_CLUSTER_NAME=my-cluster \ --set HYVE_CLUSTER_REGION=eastus \ --set HYVE_CLUSTER_PROVIDER=azureTUI — missing inputs are prompted for interactively. Variables already present in the environment are skipped automatically.
inputs[].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: v1kind: 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: v1kind: Clustermetadata: name: production region: NYC1spec: # ... 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 and
written to spec.awsEksRoleName before the cluster is created.
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 git use development
# Test workflowhyve workflow run deploy-app --cluster dev-cluster
# If successful, run in productionhyve git 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