GitOps & Terraform
Technical reference. This page is for integrations, advanced configuration, or platform operations. For portal tasks, start with the user guide.
Orqestra supports declarative delivery two ways. GitOps sync via the CLI is the primary, fully supported mechanism: it manages the full declarative package — workloads, assets, flows, releases, and bindings — with validation, diff/preview, idempotent apply, and reconcile. A Terraform provider is also available as a secondary option for teams standardizing on Terraform; it now covers the launch Orqestra resource model, while guardrail configuration and underlying infrastructure modules remain separate work. When in doubt, use GitOps sync for first deployments and migrations.
GitOps Sync
apply and reconcile submit the complete mutation plan to the control plane
once before the first writer. Any denial or unavailable/malformed response
fails closed with zero domain writes. The result is not a reservation or token:
writers re-check current authorization, so a post-allow change can still leave
the existing resumable partial apply.
orqestractl sync reads a bundle of YAML resource definitions from a
directory and applies the desired current state to the Orqestra control plane.
Resources that already exist are updated when their mutable metadata changes;
immutable asset and flow versions are reused by content hash or created when
the declared content changes.
Directory Structure
Organize each workload bundle in a Git repository:
orqestra-resources/
workload.yaml
release.dev.yaml
resources/
qa-prompt.prompt-template.yaml
gpt4-standard.model-config.yaml
docs.knowledge-base.yaml
restricted-runtime.policy-bundle.yaml
pii-filter.guardrail.yaml
knowledge-api.connection.yaml
flows/
knowledge-qa.flow.yamlFor reviewable packages that should carry the full desired state in one
document, orqestractl sync also accepts orqestra.package.yaml at the bundle
root. The package schema lives at
packages/contracts/schemas/declarative_package.schema.json and validates the
known sections before sync performs any live API lookups. When a package file is
present, split files in resources/, flows/, and release.*.yaml are not
read. The current sync apply path handles workloads, assets, connection
instances, flows, releases, asset release bindings, Hermes runtime release
bindings, and supplier proposal submissions; apps, policies,
tool_permissions, and knowledge_configs are validated and shown as skipped
until the follow-up reconciliation slices apply them.
# orqestra.package.yaml
api_version: orqestra.ai/v1alpha1
kind: DeclarativePackage
metadata:
name: knowledge-assistant-package
owner_ref: team:ai-platform
environment_metadata:
default_environment: dev
environments:
- name: dev
approval_required: false
workloads:
- slug: knowledge-assistant
display_name: Knowledge Assistant
owner_ref: team:ai-platform
flows:
- slug: knowledge-qa
display_name: Knowledge Q&A
steps: []
assets:
- kind: prompt_template
slug: qa-prompt
owner_ref: team:ai-platform
content:
system_message: "You are a helpful assistant..."
policies: []
tool_permissions: []
knowledge_configs: []
releases:
- slug: dev
workload_slug: knowledge-assistant
environment: dev
target_lane: all
bindings:
orchestration_flow: knowledge-qa
prompt_template: qa-prompt
runtime_bindings:
- runtime_profile_id: 90c14a9e-4c33-4c6b-a11a-f78ad4b7d55d
adapter_config_ref: adapter-config:knowledge-assistant-dev
tool_profile_ref: knowledge-readonlyThe same package schema also accepts supplier requirement and claim proposals
with explicit provider IDs and revision/generation counters. A requirement
proposal must be reviewed separately by an authorized human before a claim can
be proposed. Claim proposals keep a fixed finite valid_until; sync retries
never refresh it. See
Governed Providers
for the YAML examples and separate human-review steps. Proposals do not set
outcomes or establish certification.
Resource Definition Format
The bundle root defines the workload and releases. resources/ contains one
file per governed resource. flows/ contains one file per orchestration flow.
The file name is for humans; the slug field is authoritative.
# workload.yaml
slug: knowledge-assistant
display_name: Knowledge Assistant
description: Retrieval-grounded assistant for governed workspace knowledge
owner_ref: team:ai-platform
status: registered
invocation_mode: chat
interface_config:
flow_slug: knowledge-qa
domain: knowledge
system_of_record: docs
service_lane: standard
human_decision_required: false
pii_classification: internal
source_repo: knowledge-assistant
release_environment_intent: pilot
default_workload_profile_version_id: knowledge-workload-profile
default_sandbox_profile_version_id:
asset_slug: knowledge-sandbox-profile
version: v3
default_workload_harness_version_id: knowledge-harness
access:
service_lane: standard
service_lane_reason: Standard governed assistant lane
principal_bindings:
- actor_ref: user:alice@orqestra.dev
access_mode: interactive
- actor_ref: user:ops@orqestra.dev
access_mode: interactiveWorkload readiness fields
A workload only becomes dispatchable once six fields are set, and all six are
declarable here: invocation_mode, interface_config.pii_classification,
service_lane, release_environment_intent
(pilot | staged | production), and the three default asset versions
below.
The three default_*_version_id fields take an asset reference, not an
asset-version UUID — a UUID is environment-specific and would make the package
non-portable. Either form works:
# bare slug -- resolves to the asset's latest live version
default_workload_harness_version_id: knowledge-harness
# pinned to one published version label
default_sandbox_profile_version_id:
asset_slug: knowledge-sandbox-profile
version: v3Both resolve against live state at plan time, so the referenced asset
version must already exist when the workload is created — a package that
declares the profile asset and the workload together resolves them on the
apply after the asset version is written. An unresolvable reference is a
sync conflict, not a silently dropped field.
Binding a sandbox profile on the release does not satisfy
sandbox_profile_unset: readiness reads the workload’s own
default_sandbox_profile_version_id.
# resources/qa-prompt.prompt-template.yaml
kind: prompt_template
slug: qa-prompt
display_name: QA Prompt
owner_ref: team:ai-platform
content:
system_message: "You are a helpful assistant..."
user_template: "Context: {{ context }}\n\nQuestion: {{ query }}"# flows/knowledge-qa.flow.yaml
slug: knowledge-qa
display_name: Knowledge Q&A
owner_ref: team:ai-platform
name: Knowledge Q&A
description: RAG-based question answering
trigger:
type: api_request
entry_step: retrieve
steps:
- id: retrieve
type: task
config:
plugin: knowledge_query
next: generate
- id: generate
type: llm_call
config:
prompt_template_ref: qa-prompt# resources/knowledge-api.connection.yaml
kind: connector_definition
slug: knowledge-api
owner_ref: team:ai-platform
definition:
service_type: https
config_fields:
- key: base_url
label: Base URL
required: true
secret_slots:
- slot: api_key
label: API key
is_required: true
inject_hosts:
- knowledge-api.example.com
instance:
display_name: Knowledge API
config:
base_url: https://knowledge-api.example.com
secret_bindings:
api_key: knowledge-api-key# release.dev.yaml
workload: knowledge-assistant
environment: dev
bindings:
orchestration_flow: knowledge-qa
model_policy: gpt4-standard
policy_bundle: restricted-runtime-policy
guardrail_config: pii-filterConnection sync creates or updates the connection definition asset and the local connection instance from the same manifest. Secret bindings point to secret names, not secret values; operators store the secret values in Vault or the configured secret manager.
Release sync binds by slug only. orqestractl sync resolves each binding to the
version created or reused earlier in the same sync run. If live Orqestra already
has an identical version, sync reuses it. If the content changed, sync creates a
new immutable version and lets the control plane assign the next internal label.
Use model_policy for provider-routed release bindings.
Flow sync uses the same content-hash model as governed assets. Source manifests do not carry version labels; Git records authoring history, and Orqestra records immutable runtime history.
Workload access sync creates service-lane and principal bindings from the
optional access block in workload.yaml. access.service_lane is the
runtime authorization lane; interface_config.service_lane remains workload
metadata for portal display and operator context. If no access.service_lane
is present, sync falls back to the legacy top-level service_lane and then
interface_config.service_lane. access.principal_bindings accepts either a
list of actor refs or objects with actor_ref, optional actor_type,
access_mode, and optional scope_ref.
Running Sync
orqestractl sync is a command group with four verbs that form a clear
progression from local check to live convergence:
# Validate the package locally, no API calls (full schema for the package
# layout; structural parse checks for the split-file layout)
orqestractl sync validate --dir ./orqestra-resources
# Preview the diff against live state without mutating anything
orqestractl sync preview --dir ./orqestra-resources
# Apply the diff to reach the desired state
orqestractl sync apply --dir ./orqestra-resources
# Converge to the desired state, reporting drift (idempotent CI/CD entrypoint)
orqestractl sync reconcile --dir ./orqestra-resourcesThe API target and credentials come from ORQESTRA_API_URL / ORQESTRA_API_KEY
(or the CLI config). validate never touches the API; preview reads live
state but never mutates; apply and reconcile are fail-closed — they change
nothing while the diff still contains an unresolved conflict.
Declarative sync prepares resources through review_ready. Approval and
activation stay governed CLI/portal actions. Package reconciliation, a pending
release candidate, and the release currently selected for execution are
distinct: a matching draft or review_ready candidate is not evidence that
execution serves those bindings. Unqualified “no drift” / “up to date” is
printed only when desired resources are reconciled and the observed
effective bindings match, with a point-in-time qualifier. A serving gap,
absent active release, or unverified serving read is printed even when the
mutation plan is empty. validate remains local and makes no serving claim.
CI/CD Integration
Add sync to your CI/CD pipeline:
# .github/workflows/deploy.yml
name: Deploy Orqestra Resources
on:
push:
branches: [main]
paths: ["orqestra-resources/**"]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- run: pip install orqestra-cli
- run: orqestractl sync reconcile --dir ./orqestra-resources
env:
ORQESTRA_API_URL: ${{ secrets.ORQESTRA_API_URL }}
ORQESTRA_API_KEY: ${{ secrets.ORQESTRA_API_KEY }}Terraform Provider
The Orqestra Terraform provider is a secondary delivery option for teams standardizing on Terraform. It covers the launch Orqestra resource model, but GitOps sync remains the recommended path for first deployments and migration work because it converges the full workload package from source-controlled YAML.
Coverage today: The provider supports workloads, assets, asset versions, flows, releases, release bindings, and environment-scoped connection instances. Orqestra records without API delete endpoints use state-only destroy; this includes workloads, assets, asset versions, flows, releases, and release bindings. Update support is per-resource: workloads, flows, and connection instances support provider-managed updates; asset versions require replacement for
asset_idorcontentchanges; asset slug,asset_kind, orowner_refchanges require replacement; flowcontentchanges create a new immutable version, while flow slug orowner_refchanges require replacement; release binding changes return an immutable-update diagnostic; releases do not expose mutable fields.orqestra_connection_instancesupports API delete.orqestra_guardrail_configis not implemented yet; Terraform operations return a not-yet-implemented diagnostic. Terraform infrastructure modules for PostgreSQL, Redis, object storage, ingress, or cloud networking are not part of this provider.
Provider Configuration
terraform {
required_providers {
orqestra = {
source = "orqestra/orqestra"
}
}
}
provider "orqestra" {
api_url = "https://api.orqestra.example.com" # or ORQESTRA_API_URL
api_key = var.orqestra_api_key # or ORQESTRA_API_KEY
workspace_id = var.orqestra_workspace_id # or ORQESTRA_WORKSPACE_ID
}Available Resources
| Resource | Description | Status |
|---|---|---|
orqestra_workload | Manage workloads | Create, read/import, update, state-only destroy |
orqestra_asset | Manage governed assets | Create, read/import, slug, asset_kind, or owner_ref changes require replacement, state-only destroy |
orqestra_asset_version | Manage asset versions with content | Create, read/import, asset_id or content changes require replacement, state-only destroy |
orqestra_flow | Manage orchestration flows | Create, read/import, content update creates a new immutable version; slug or owner_ref changes require replacement, state-only destroy |
orqestra_release | Manage releases | Create, read/import, update not supported, state-only destroy |
orqestra_release_binding | Bind asset/flow versions to releases | Create, read/import, immutable update error, state-only destroy |
orqestra_connection_instance | Manage environment-scoped connections | Create, read/import, update, API delete |
orqestra_guardrail_config | Guardrail configuration schema | Not implemented; Terraform operations return a not-yet-implemented diagnostic |
Lookup data sources are available for stable authoring references:
orqestra_workload_by_slug, orqestra_asset_by_slug,
orqestra_flow_by_slug, and orqestra_release_by_environment.
Example Configuration
The example below creates a workload, prompt asset version, flow, release, and release bindings without manually authoring internal version labels.
resource "orqestra_workload" "knowledge_assistant" {
slug = "knowledge-assistant"
display_name = "Knowledge Assistant"
description = "Retrieval-grounded assistant for governed workspace knowledge."
owner_ref = "team:ai-platform"
status = "registered"
invocation_mode = "chat"
}
resource "orqestra_asset" "qa_prompt" {
slug = "qa-prompt"
asset_kind = "prompt_template"
owner_ref = "team:ai-platform"
}
resource "orqestra_asset_version" "qa_prompt_v1" {
asset_id = orqestra_asset.qa_prompt.id
content = jsonencode({
system_message = "You are a helpful assistant..."
user_template = "Context: {{ context }}\n\nQuestion: {{ query }}"
})
}
resource "orqestra_flow" "knowledge_qa" {
slug = "knowledge-qa"
owner_ref = "team:ai-platform"
content = jsonencode({
name = "Knowledge Q&A"
entry_step = "retrieve"
steps = []
})
}
resource "orqestra_release" "production" {
workload_id = orqestra_workload.knowledge_assistant.id
environment = "production"
target_lane = "all"
}
resource "orqestra_release_binding" "prompt" {
release_id = orqestra_release.production.id
asset_version_id = orqestra_asset_version.qa_prompt_v1.id
role = "prompt_template"
}
# Release bindings use asset_version_id for both asset versions and flow
# version IDs; this flow binding references the provider-managed latest version.
resource "orqestra_release_binding" "flow" {
release_id = orqestra_release.production.id
asset_version_id = orqestra_flow.knowledge_qa.latest_version_id
role = "orchestration_flow"
}Terraform Workflow
# Initialize and plan
terraform init
terraform plan
# Create resources
terraform apply
# Remove Terraform state for records without API delete endpoints; connection
# instances use API delete
terraform destroyUse terraform import for existing Orqestra objects when adopting Terraform
state. For append-only or immutable records, terraform destroy forgets the
remote object instead of deleting historical Orqestra evidence. Terraform marks
immutable fields as replacement at plan time. If a provider operation is not
implemented, such as orqestra_guardrail_config, Terraform operations return a
not-yet-implemented diagnostic. Use GitOps sync for package-level
reconciliation from one directory when you need update behavior outside the
provider’s launch coverage.
Choosing Between GitOps and Terraform
| Factor | GitOps Sync | Terraform |
|---|---|---|
| Coverage | Full declarative package | Core launch resources; guardrail config excluded |
| Best for | First deployments and migrations | Teams standardizing on Terraform state |
| State management | Stateless idempotent sync | State file tracks resource lifecycle |
| Dependency ordering | Automatic sync ordering | Explicit Terraform graph |
| Dry run | sync preview | terraform plan |
| Learning curve | Low, YAML bundle oriented | Medium, HCL and state concepts |
| Deletion | API behavior per resource | API delete for connections; state-only destroy for append-only records |
GitOps sync is the recommended path for full, governed delivery. The Terraform provider is a supported secondary option for Terraform-standardized teams; use GitOps sync for package-level convergence and for guardrail configuration or update paths that the provider does not yet cover.