Skip to content

9. Fields and Labels

A .arch file is mostly structural: declare a module, declare an interface, declare a process. The non-structural part — owners, versions, URLs, classification axes — lives in two related but distinct constructs: fields and labels.

This chapter is about both. The short version up front:

  • Fields describe what a thing is: its team, its repo URL, its CMDB ID, its base path.
  • Labels classify a thing along an axis: its domain, its network segment, its security zone, its criticality.

Fields are first-class values. Labels are tags used for projections (views, checks, groupings). Many things could plausibly be either; the rule of thumb is: if you’d ever want to group by it or focus a view on it, make it a label.

Fields

Fields live directly in a body, no surrounding block:

module Orders {
team: Commerce
version: v2
repo.url: "https://github.com/acme/orders"
ext.cmdb.ci: "CI28304858"
base: "/orders"
"Order management service"
}

Each field is key: value where:

  • Key is an identifier or a dotted path (repo.url, ext.cmdb.ci). Dotted keys are equivalent to a nested object structure; tooling treats them uniformly.
  • Value is one of four scalar types:
    • identifierCommerce, v2
    • quoted string"any text", multi-line allowed
    • number42, 3.14
    • booleantrue, false

That’s the complete value language. There are no nested objects, no per-field type system, no generics, no user-defined value shapes. Tooling may interpret values by convention (URLs become clickable, dotted IDs become copy-able) but the parser treats them all as scalars.

Mindset shift. If you’re coming from configuration languages like HCL, JSON, or YAML, the absence of nested objects can feel limiting. It’s deliberate. Architecture descriptions don’t need configuration’s expressivity; what they need is a flat key-value layer that’s trivial to query and group. The dotted-key form (repo.url) covers what nested objects would.

Bare-string descriptions

A bare string is a field with a reserved meaning — it’s the description:

module Payments {
"Core payment processing service for the platform."
}

A body may have multiple bare-string descriptions; they concatenate with \n in declaration order. This lets you write multi-paragraph descriptions without one huge multi-line string. Descriptions render as markdown plus two extensions — see Chapter 10.

Labels

Labels go inside a labels { } block:

module Payments {
team: Payments
labels {
domain: Payments
security.zone: PCI
network.segment: Internal
criticality: High
}
}

Each key: value inside labels { } is one label. Keys can be dotted (security.zone, network.segment); values use the same scalar types as fields.

Labels:

  • Cascade. A label declared on a parent module is visible on every nested module, facet, and interface — unless they declare the same label themselves. This is how a domain: Payments on the top-level module reaches every operation inside without repetition. See Chapter 18.
  • Drive views. focus domain: Payments works because domain is a label. group by team works too — views accept field paths in addition to label paths, and team is a cascade field.
  • Drive checks. Validators read labels: every PCI service must have a recorded security.contact, no service in network.segment: DMZ may call a service in network.segment: Internal.

Field or label?

The rule of thumb again, with examples:

Use a label whenUse a field when
You’d ever group by itThe value is a single fact unique to this thing
You’d focus a view on itThe value is a URL, ID, version, or count
It’s a classification axisIt’s an identifier or pointer
Examples: domain, security.zone, criticalityExamples: team, repo.url, version, ext.cmdb.ci, base

team sits squarely on the field side — the stdlib defines it as required cascade team, a plain cascade field. The reason it gets used in group by team is that views accept field paths as well as label paths; the choice between “field for team” and “label for team” was made once in the stdlib so every project shares the same convention.

Note one practical detail: labels are always cascade-override in propagation behavior. You can’t have an “append” label. If you need accumulation (a list of tags that grows from parent to child), use a field with the append modifier — see Chapter 18.

Multi-line strings

Quoted string values can span multiple lines. The lexer auto-dedents:

module Payments {
"
Core payment processing.
Owns authorization, capture, and refund.
Publishes events to the order pipeline.
"
}

A leading whitespace-only line is dropped; the minimum indent shared by remaining lines is stripped. The above produces the value "Core payment processing.\nOwns authorization, capture, and refund.\nPublishes events to the order pipeline.".

The only recognized escape is \".

Triple-quoted strings

For values that contain double quotes (HTML, JSON snippets, regex), use triple-quoted strings. Backslashes are not escape sequences inside them:

module Cart {
widget: """
<div class="card" data-name="{{name}}">
<span class="label">{{team}}</span>
</div>
"""
}

Triple-quoted strings are raw. They don’t support ${expr}-style interpolation (so future template-literal features can be added later without conflicting).

No props { } block

Earlier Archlang had a props { } block to hold “extra metadata.” That’s gone. The role is fully covered by fields with dotted keys: ext.cmdb.ci: "...", repo.url: "...". If you’re reading old files with props { }, run the formatter — it’ll lift them out.

Summary

  • Fields describe what a thing is. They live directly in the body, no surrounding block.
  • Labels classify a thing along an axis. They live inside labels { }.
  • Values are scalars: identifier, quoted string, number, boolean. No nested objects.
  • Bare-string descriptions are reserved; multiple bare strings concatenate.
  • Labels drive views and cascade through nesting; if you need accumulation, use a field with append.
  • The choice “field or label?” is usually: would you group by or focus on it?

What’s next

Chapter 10: Descriptions → — the markdown subset and cross-reference syntax inside description strings.