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.
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" }}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.
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."}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:
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.