| title | Dialect declarations |
|---|---|
| description | Complete reference for Dialect identity, provider envelopes, Concepts, Contexts, and Relations. |
A Dialect is one named and versioned interpretation unit. Its Rules add architecture meaning to observed plan or state instances.
Definitions and Rules are top-level siblings of the dialect block. Only
provider blocks are nested inside dialect.
dialect "example" {
version = "0.1.0"
provider "hashicorp/example" {
version = ">= 1.0.0, < 2.0.0"
}
}
concept "application" {
description = "A deployable application service."
}
context "runtime" {
description = "The runtime selected for an application."
}
relation "calls" {
description = "A declared application dependency."
}
A source root may split these blocks across any number of .rf.hcl and
.rf.json files.
| Property | Contract |
|---|---|
| Placement | Top level of a Dialect source root |
| Cardinality | Exactly one per source root |
| Labels | Exactly one required Dialect owner |
| Attributes | version |
| Nested blocks | provider only |
| Name | Type | Required | Default | Constraints |
|---|---|---|---|---|
| Label | Identifier | Yes | None | Lowercase kebab case, 1-64 bytes; rf forbidden |
version |
Static string | Yes | None | Exact MAJOR.MINOR.PATCH |
Canonical unit identity combines label and version, for example
example@0.1.0.
A Dialect has no authored dependency list. It may reference its own symbols and
rf.* only. Compiler derives RF Vocabulary dependency when used.
dialect "example" {
version = "0.1.0"
provider "hashicorp/example" {
version = ">= 1.4.0, < 2.0.0"
}
provider "registry.example.com/acme/platform" {
version = "~> 3.2.0"
}
}
| Property | Contract |
|---|---|
| Placement | Inside dialect |
| Cardinality | Zero or more; at least one when source root declares any Rule |
| Labels | Exactly one required provider source |
| Attributes | version |
| Nested blocks | None |
| Name | Type | Required | Default | Constraints |
|---|---|---|---|---|
| Label | Provider source | Yes | None | namespace/type or host/namespace/type |
version |
Static string | Yes | None | One or more comma-separated clauses |
Accepted clause operators are =, !=, >, >=, <, <=,
and ~>. Every clause must include an operator and an exact three-component
version:
provider-constraint = clause, { ",", clause } ;
clause = operator, version ;
operator = "=" | "!=" | ">" | ">=" | "<" | "<=" | "~>" ;All clauses combine with logical AND against one known exact provider version.
| Operator | Version test |
|---|---|
= 3.2.0 |
Equal to 3.2.0 |
!= 3.2.0 |
Not equal to 3.2.0 |
> 3.2.0 |
Greater than 3.2.0 |
>= 3.2.0 |
Greater than or equal to 3.2.0 |
< 3.2.0 |
Less than 3.2.0 |
<= 3.2.0 |
Less than or equal to 3.2.0 |
~> 3.2.0 |
Greater than or equal to 3.2.0 and less than 3.3.0 |
Whitespace around clauses is normalized. Duplicate clauses are removed and
remaining clauses are sorted in compiled output. A bare version such as
"1.4.0" is invalid.
Two-part provider sources bind the equivalent Terraform and OpenTofu public
registry addresses for that namespace and type.
Three-part sources require exact host, namespace, and type. Duplicate normalized
provider sources produce DUPLICATE_ID.
Provider source binding participates in Rule eligibility; plan/state selection does not compare an observed exact provider version to the declared envelope:
Every Rule in the Dialect uses this shared provider list. Rules do not declare their own provider selector.
- a fully qualified provider address binds that exact registry host;
- a public-registry shorthand binds equivalent Terraform and OpenTofu public registry addresses for the same namespace and type;
- an observed provider without a selected binding produces
PROVIDER_UNBOUNDand leaves interpretation unsettled; - an unavailable provider alias is uncertain, not proof of a different provider.
concept, top-level context, and top-level relation share one shape:
concept "database" {
description = "A database service."
}
context "runtime" {
description = "The runtime selected for a service."
}
relation "reads-from" {
description = "A declared read dependency."
}
| Property | Contract |
|---|---|
| Placement | Top level of a Dialect source root |
| Cardinality | Zero or more of each kind |
| Labels | Exactly one required name |
| Attributes | Optional description |
| Nested blocks | None |
| Name | Type | Required | Default | Constraints |
|---|---|---|---|---|
| Label | Identifier | Yes | None | Lowercase kebab case, 1-64 bytes; unique within symbol kind |
description |
Static string | No | Empty | Valid UTF-8, at most 1,024 bytes; empty allowed |
| Block | Defines | Does not define |
|---|---|---|
concept |
Optional nominal classification | Shape, inheritance, properties, or structural coverage |
context |
Named directed placement dimension | A fact by itself |
relation |
Named directed relation predicate | A fact by itself |
Rules emit concrete Contexts, Relations, and Contributions. Concepts classify a
representation only when a Rule uses as. A Concept is optional and never
inferred from a Rule name or source type.
Descriptions are editorial metadata. They affect exact content identity but are excluded from Dialect semantic digest.
Labeled Rule emissions may introduce a local Context or Relation without a separate top-level definition. Top-level definition remains useful for a description. Concepts always require explicit definition.
A Dialect may resolve:
| Reference syntax | Scope |
|---|---|
concept.name, context.name, relation.name, rule.name |
Current Dialect |
owner.kind.name where owner equals current Dialect |
Current Dialect |
Supported rf.* ID |
Embedded RF Vocabulary |
Foreign Dialect references are invalid. File location never changes scope. See Symbols and references for complete resolution rules.
dialect "example" {
version = "0.1.0"
provider "example" {
version = "1.4.0"
}
}
Provider source has too few slash-separated segments and version clause has no
operator. Compiler reports PROVIDER_INVALID.
A requires block, nested concept, unknown attribute, or second
dialect block also fails closed.