DSL Specification

Complete specification for the function-hcl DSL.

Input Format

The function accepts its HCL program in txtar format via the input field of the Composition pipeline step. All files are treated as one unit.

External Variables

Created automatically from the RunFunctionRequest. Accessed as req.<field>.

VariableTypeDescription
req.compositeobjectObserved composite resource (XR)
req.composite_connectionmap(string, bytes)Observed connection details of the composite
req.resourcemap(string, object)Observed resource bodies, keyed by crossplane name
req.connectionmap(string, map(string, bytes))Observed connection details, keyed by resource name
req.resourcesmap(string, list(object))Observed resource collections, keyed by base name
req.connectionsmap(string, list(map(string, bytes)))Connection details of collections
req.contextmap(string, any)Pipeline context
req.extra_resourcesmap(string, list(object))Extra resources from requirement blocks

Top-Level Blocks

locals

locals {
  <name> = <expression>
}
  • Accessed by name directly (no local. prefix).
  • Ordering does not matter; locals with incomplete values are evaluated lazily.
  • Circular references are an error.
  • Cannot shadow names from parent scopes.
  • Can be defined at: top level, resource, resources template, group, requirement, function.

resource

resource <crossplane-name> {
  condition = <bool>            # optional
  locals { ... }                # optional
  body = { <k8s-manifest> }    # required
  composite status { body = { ... } }      # optional, repeatable
  composite connection { body = { ... } }  # optional, repeatable
  ready { value = <string> }   # optional
}

Special variables: self.name, self.resource, self.connection

resources

resources <base-name> {
  condition = <bool>            # optional
  locals { ... }                # optional
  for_each = <collection>       # required (list, set, or map)
  name = <expression>           # optional, default: "${self.basename}-${each.key}"
  template {
    locals { ... }              # optional
    body = { <k8s-manifest> }  # required
    composite status { ... }    # optional
    composite connection { ... } # optional
    ready { ... }               # optional
  }
}

Special variables: self.basename, self.name (in template), self.resources, self.connections, each.key, each.value

group

group {
  condition = <bool>            # optional
  locals { ... }                # optional
  resource <name> { ... }       # any number
  resources <name> { ... }      # any number
}

composite status

composite status {
  body = { <status-fields> }
}

Can appear at top level or inside resource/resources template. Multiple blocks are merged; conflicting non-object leaf values are an error.

composite connection

composite connection {
  body = { <connection-details> }
}

All values must be base64-encoded strings. Same merging/conflict rules as status.

context

context {
  key   = <string>
  value = <any>
}

Same merging/conflict rules as status. Can appear at top level or inside resource blocks.

requirement

requirement <name> {
  condition = <bool>            # optional
  locals { ... }                # optional
  select {
    apiVersion  = <string>
    kind        = <string>
    matchName   = <string>      # XOR
    matchLabels = <map(string)> # XOR
  }
}

Must specify exactly one of matchName or matchLabels.

function

function <name> {
  arg <name> {
    default     = <value>       # optional
    description = <string>      # optional
  }
  locals { ... }                # optional
  body = <return-value>         # required
}
  • Must be defined at top level.
  • No access to external state (req, self, etc.).
  • Invoked with invoke("name", { arg: value }).
  • Call stack limit: 100.

ready

ready {
  value = <string>  # "READY_UNSPECIFIED" | "READY_TRUE" | "READY_FALSE"
}

Auto-Discard Rules

  1. If any expression in a block is incomplete, the entire block is skipped.
  2. If a resource already has an observed value but now has an incomplete value, return a fatal error.
  3. Incomplete condition values are treated as false.

Status Conditions

ConditionTrue whenFalse when
FullyResolvedNo incomplete values encounteredOne or more blocks deferred
HclDiagnosticsNo HCL warningsWarnings present (details in message)
Last modified March 12, 2026: clean up docs, mostly (1ee88e8)