Architectural Models

The Iteration Pattern

Explains the origin_resource for-each loop, file anatomy, rule blocks, and data-driven iteration patterns.

The Iteration Pattern

The origin_resource For-Each Loop and Anatomy of a Configuration File

The most important concept for writing model files is rescile’s implicit iteration pattern. Think of each .toml configuration file as a module that contains a loop.

The Golden Rule: A configuration file with origin_resource = "application" is a for-each loop. It tells rescile to run the rules in that file once for every application in your graph.

You don’t write imperative loops — you declare a set of rules that operate on a collection of resources. rescile handles the iteration automatically.

Declarative vs. Imperative

The declarative model file below is equivalent to the imperative pseudo-code that follows it.

# data/models/server.toml
origin_resource = "application"

[[create_resource]]
resource_type = "server"
relation_type = "HOSTED_ON"
name = "{{ origin_resource.name }}_server"

[[create_resource]]
match_on = [{ property = "environment", value = "prod" }]
resource_type = "monitoring_agent"
name = "agent_for_{{ origin_resource.name }}"
all_applications = graph.find_resources(type="application")

for current_application in all_applications:
    create_server_for(current_application)

    if current_application.environment == "prod":
        create_monitoring_agent_for(current_application)

Data-Driven Iteration with create_from

As an alternative to iterating over graph resources, rescile supports a data-driven iteration model using the create_from directive. This lets you generate resources from an abstract list defined in the file header.

# data/models/providers.toml
# No origin_resource is defined.

providers = { "json!" = "shared/providers.json" }
provider_list = { "template!" = '''{{ providers | map(attribute="name") | safe }}''' }

[[create_resource]]
create_from = { list = "provider_list", as = "provider" }
name = "ext-{{ value }}"

In this mode the origin_resource variable is unavailable; instead the special value variable holds the current item from the list.

Anatomy of a Configuration File

Every rescile .toml file has two sections: a Header and one or more Rule Blocks.

# ── HEADER ──────────────────────────────────────────────────────────────
origin_resource = "application"   # The for-each subject

# File-scoped data available to all Rule Blocks
server_specs    = { standard_cpu = 4, premium_cpu = 8 }
ip_ranges       = { "json!" = "shared/ip_ranges.json" }

# ── RULE BLOCK 1 ─────────────────────────────────────────────────────────
[[create_resource]]
resource_type = "server"
relation_type = "HOSTS"
name = "server_{{ origin_resource.name }}"

[create_resource.properties]
cpu_cores = "{{ server_specs.standard_cpu }}"
status    = "provisioning"

# ── RULE BLOCK 2 ─────────────────────────────────────────────────────────
[[create_resource]]
match_on = [{ property = "environment", value = "prod" }]
resource_type = "monitoring_agent"
name = "agent_{{ origin_resource.name }}"

Header (Module Scope)

Key Description
origin_resource Optional. The resource type this file iterates over. If omitted, rules run once in a global context (useful for singletons or create_from generation).
Any other key File-scoped data available as template variables. May be an inline TOML table, a { "json!" = "..." } reference, or a { "template!" = "..." } or { "function!" = "..." } snippet.

When origin_resource is omitted, rules are processed exactly once unless create_from with a list is used. The origin_resource variable is not available in templates.

Rule Blocks and Directives

A Rule Block is a TOML array-of-tables entry such as [[create_resource]] or [[link_resources]]. Think of each block as a single executable function that rescile evaluates for every iteration of the loop.

Inside a Rule Block, Directives are the key-value pairs that configure the function — for example resource_type, name, relation_type, and match_on.

Global Context: Module Parameters

In addition to the file-scoped data defined in the header, any module parameters passed via --module-params on the command line are available as global variables in every template across all files in the module.

rescile-ce --module ./my-module --module-params "region=eu-central-1;env=prod" serve

Inside any template: {{ region }} renders "eu-central-1" and {{ env }} renders "prod".

For the complete reference on all available template data and functions, see Tera Essentials.