Skip to content

Template helpers

The stage-templates/v1 profile is the locked, target-neutral interpreter contract for declarative renderer kits. Examples use the test language pack, not a production target. Vectors marked with operators use the test operator table and a declared leaf partial that emits a Domain symbol reference for item.identifier. Outputs show JSON-quoted text, ordered segments or a safety refusal; gaps are recorded alongside text. Helper bytes, signatures and semantics are frozen once released. Change them under a new helper name or templates/v2. See Author a renderer kit for scope, symbols and caller safety obligations.

(expression, literalTable, literalLeaf, literalRole) -> parts — since v1.

Lowers supported expressions to structured parts; unsupported semantics produce a role-safe degradation.

VectorTemplateScopeExpected output
expression-leaf (operators){{ expr.lower model.expression 'operators' 'leaf' 'throwing_operation_body' }}{"model":{"expression":{"$kind":"resolved","identifier":"Customer"}}}["Reference:Domain.Customer"]
expression-gap (operators){{ expr.lower model.expression 'operators' 'leaf' 'deny_enclosing_operation' }}{"model":{"expression":{"$kind":"unknown"}}}"FAIL[DenyEnclosingOperation:STAGE-DEGRADE-001]"; gap: STAGE-DEGRADE-001

(expression, literalTable) -> bool — since v1.

Tests expression support using a declared, literal operator table.

VectorTemplateScopeExpected output
expression-support (operators){{ expr.supported model.expression 'operators' }}{"model":{"expression":{"$kind":"value","literal":{"$kind":"number","value":42}}}}"true"
no-dynamic-expression-table{{ expr.supported model.expression model.table }}{"model":{}}prepare refusal: STAGE-TPL-008

(role, intent, modelPath, code = 'STAGE-DEGRADE-002') -> placeholder and gap — since v1.

Emits a language-pack placeholder and records a semantic gap, not a safety refusal.

VectorTemplateScopeExpected output
default-gap{{ gap 'disabled_specification' 'Missing behavior' 'model.x' }}{"model":{}}"FAIL[DisabledSpecification:STAGE-DEGRADE-002]"; gap: STAGE-DEGRADE-002
gap-003{{ gap 'unregistered_consumer' 'Missing behavior' 'model.x' 'STAGE-DEGRADE-003' }}{"model":{}}"FAIL[UnregisteredConsumer:STAGE-DEGRADE-003]"; gap: STAGE-DEGRADE-003
gap-005{{ gap 'retained_signature_or_type' 'Missing behavior' 'model.x' 'STAGE-DEGRADE-005' }}{"model":{}}"FAIL[RetainedSignatureOrType:STAGE-DEGRADE-005]"; gap: STAGE-DEGRADE-005

(requirementId) -> authored body — since v1.

Emits a structured authored-body handle for an implementation requirement; the body text never enters the template output and handles cannot be converted to text or captured.

VectorTemplateScopeExpected output
authored-bodyA{{ impl.body 'r1' }}B{"model":{}}["text:A","Authored:r1","text:B"]
authored-body-text{{ (impl.body 'r1') + 'text' }}{"model":{}}render refusal: STAGE-TPL-022

(bool) -> text — since v1.

Delegates boolean spelling to the language pack.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(string) -> text — since v1.

Delegates safe comment content to the language pack.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(number) -> text — since v1.

Delegates decimal number spelling to the language pack.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(string) -> text — since v1.

Delegates safe identifier spelling to the language pack.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(int64) -> text — since v1.

Delegates signed 64-bit integer spelling to the language pack without string coercion.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"
strict-literal{{ lit.integer model.number }}{"model":{"number":"1"}}render refusal: STAGE-TPL-024

() -> text; write lit['null'] in Scriban — since v1.

Delegates null spelling to the language pack. Use lit['null'] rather than lit.null: Scriban reserves the null keyword.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(string) -> text — since v1.

Delegates string escaping to the language pack without primitive coercion.

VectorTemplateScopeExpected output
literal-seam{{ lit.string 'safe' }}|{{ lit.integer model.integer }}|{{ lit.decimal model.fraction }}|{{ lit.boolean false }}|{{ lit['null'] }}|{{ lit.comment 'a*/b' }}|{{ lit.identifier 'class' }}{"model":{"integer":9223372036854775807,"fraction":1.25}}"\u0022safe\u0022|9223372036854775807|1.25|no|nil|a* /b|@class"

(nameWords) -> text — since v1.

Lowercases the entire first word and capitalizes subsequent words’ first Unicode scalar invariantly.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"

(nameWords) -> text — since v1.

Joins invariant uppercase words with underscores.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"

(nameWords) -> text — since v1.

Joins invariant lowercase words with hyphens.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"

(nameWords) -> text — since v1.

Capitalizes each word’s first Unicode scalar invariantly, preserving the remaining characters.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"
unicode-scalar{{ name.pascal model.words }}|{{ name.snake model.words }}{"model":{"words":["𐐨tail","I"]}}"\uD801\uDC00tailI|\uD801\uDC28tail_i"
strict-name{{ name.pascal model.name }}{"model":{"name":"raw text"}}render refusal: STAGE-TPL-024

(nameWords) -> text — since v1.

Joins invariant lowercase words with underscores.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"
unicode-scalar{{ name.pascal model.words }}|{{ name.snake model.words }}{"model":{"words":["𐐨tail","I"]}}"\uD801\uDC00tailI|\uD801\uDC28tail_i"

(nameWords) -> text — since v1.

Joins nonempty name words with spaces using invariant lowercase.

VectorTemplateScopeExpected output
word-arrays{{ name.words model.words }}|{{ name.pascal model.words }}|{{ name.camel model.words }}|{{ name.snake model.words }}|{{ name.kebab model.words }}|{{ name.constant model.words }}{"model":{"words":["order","iD","eMail"]}}"order id email|OrderIDEMail|orderIDEMail|order_id_email|order-id-email|ORDER_ID_EMAIL"

(literalCategory, message) -> whole-plan refusal — since v1.

Latches a safety refusal for a literal trust, integrity or budget category. The caller must discard all plan outputs.

VectorTemplateScopeExpected output
refuse-trust{{ refuse 'trust' 'unsafe' }}{"model":{}}render refusal: STAGE-TPL-040
no-unknown-refusal{{ refuse 'anything' 'unsafe' }}{"model":{}}prepare refusal: STAGE-TPL-008
no-clock{{ date.now }}{"model":{}}prepare refusal: STAGE-TPL-005

(literalPartial, arg = null) -> partial output — since v1.

Renders a declared, literal partial with an isolated item argument.

VectorTemplateScopeExpected output
render-partial (operators){{ render 'leaf' model }}{"model":{"identifier":"Customer"}}["Reference:Domain.Customer"]
no-dynamic-partial{{ render model.partial }}{"model":{}}prepare refusal: STAGE-TPL-006
ordinary-texthello {{ model.name }}{"model":{"name":"World"}}"hello World"

wrap section 'name' ... end -> inline body — since v1.

Renders an inline section body unless a validated override replaces it. Sections cannot be nested.

VectorTemplateScopeExpected output
default-sectiona{{ wrap section 'body' }}{{ model.name }}{{ end }}b{"model":{"name":"x"}}"axb"
no-nested-section{{ wrap section 'body' }}{{ wrap section 'inner' }}x{{ end }}{{ end }}{"model":{}}prepare refusal: STAGE-TPL-008

(namespace, name) -> declaration — since v1.

Emits a structured declaration handle; handles cannot be converted to text or captured.

VectorTemplateScopeExpected output
symbolsA{{ sym.decl 'Domain' 'Customer' }}{{ sym.ref 'Other' 'Customer' }}{{ sym.imports }}B{"model":{}}["text:A","Declaration:Domain.Customer","Reference:Other.Customer","Imports:","text:B"]

() -> imports insertion point — since v1.

Emits a structured imports insertion point for the language pack.

VectorTemplateScopeExpected output
symbolsA{{ sym.decl 'Domain' 'Customer' }}{{ sym.ref 'Other' 'Customer' }}{{ sym.imports }}B{"model":{}}["text:A","Declaration:Domain.Customer","Reference:Other.Customer","Imports:","text:B"]

(namespace, name) -> reference — since v1.

Emits a structured reference handle, preserving namespace and name separately.

VectorTemplateScopeExpected output
symbolsA{{ sym.decl 'Domain' 'Customer' }}{{ sym.ref 'Other' 'Customer' }}{{ sym.imports }}B{"model":{}}["text:A","Declaration:Domain.Customer","Reference:Other.Customer","Imports:","text:B"]
symbol-null-test{{ x = sym.ref 'Domain' 'Customer'; if x != null; x; end }}{"model":{}}["Reference:Domain.Customer"]
symbol-text{{ (sym.ref 'Domain' 'Customer') + 'text' }}{"model":{}}render refusal: STAGE-TPL-022

(RenderTypeRef) -> type parts — since v1.

Resolves semantic identities and delegates primitive, collection and optional spelling to the language pack.

VectorTemplateScopeExpected output
type-text{{ type.ref model.type }}{"model":{"type":{"kind":"primitive","primitive":"text","isCollection":false,"isOptional":false}}}"string"
type-symbol{{ type.ref model.type }}{"model":{"type":{"kind":"primitive","primitive":"uuid","isCollection":true,"isOptional":true}}}["Reference:System.Guid","text:[]?"]
type-identity{{ type.ref model.type }}{"model":{"type":{"kind":"concept","target":"customer","isCollection":false,"isOptional":false}}}["Reference:Domain.Customer"]
unknown-type{{ type.ref model.type }}{"model":{"type":{"kind":"concept","target":"missing","isCollection":false,"isOptional":false}}}render refusal: STAGE-TPL-024

All STAGE-TPL codes are whole-plan safety refusals. Discard every output of a refused plan, including earlier artifacts.

CodeTemplateCodes constant
STAGE-TPL-001MissingContract
STAGE-TPL-002TemplateSize
STAGE-TPL-003Nesting
STAGE-TPL-004Parse
STAGE-TPL-005Allowlist
STAGE-TPL-006Partial
STAGE-TPL-007TemplatePrivateUse
STAGE-TPL-008Helper
STAGE-TPL-009OperatorTable
STAGE-TPL-010Override
STAGE-TPL-020HostValue
STAGE-TPL-021Mutation
STAGE-TPL-022Symbol
STAGE-TPL-023JsonPrivateUse
STAGE-TPL-024Input
STAGE-TPL-030Steps
STAGE-TPL-031Output
STAGE-TPL-032Artifacts
STAGE-TPL-033FanOut
STAGE-TPL-034StringLength
STAGE-TPL-035Recursion
STAGE-TPL-036Deadline
STAGE-TPL-040Refuse
STAGE-TPL-041AlreadyRefused
  • array: add, add_range, any, compact, concat, contains, cycle, each, filter, first, join, last, limit, map, offset, remove_at, reverse, size, sort, uniq.
  • math: abs, ceil, divided_by, floor, is_number, minus, modulo, plus, round, times.
  • object: default, has_key, has_value, keys, kind, size, typeof, values.
  • string: append, capitalize, capitalizewords, contains, downcase, empty, ends_with, equals_ignore_case, escape, handleize, index_of, literal, lstrip, pad_left, pad_right, pluralize, prepend, remove, remove_first, remove_last, replace, replace_first, rstrip, size, slice, slice1, split, starts_with, strip, to_double, to_float, to_int, to_long, truncate, upcase, whitespace.

Everything else is unavailable, including date/time, random, environment, regex, dynamic evaluation and JSON parsing.

Limits are aggregate across a plan session; all budget values must be positive.

LimitDefault
Template UTF-8 bytes (pre-scan)65536
Template nesting (pre-scan)32
Aggregate steps2000000
Aggregate output UTF-8 bytes8388608
Artifacts2000
Fan-out2000
String length262144
Recursion64
Deadline (seconds)10

The caller owns the process-level CPU and memory sandbox; interpreter budgets are not a replacement.