Skip to main content
Learn

Introduction to CALM Patterns

โฑ 3 min read๐ŸŸก Intermediate ยท 30-45 minutesEdit on GitHub โ†—

Overviewโ€‹

Learn how CALM Patterns enable you to define reusable architecture templates that can both generate new architectures and validate existing ones.

Learning objectivesโ€‹

By the end of this tutorial, you will:

  • Understand the dual superpower of Patterns: generation and validation
  • Know how Patterns use JSON Schema keywords (const, prefixItems, minItems/maxItems, $ref)
  • Create a Pattern for a 3-tier web application
  • Generate a new architecture from your Pattern
  • Validate both a passing and a failing architecture against the Pattern
  • Understand placeholder warnings in generated architectures

Prerequisitesโ€‹

Complete Generate Operations Documentation first.

Step-by-Step Guideโ€‹

1. Understand What Patterns Areโ€‹

The Problem Patterns Solve:

  • Teams keep building similar architectures from scratch
  • No easy way to enforce "all web apps must have these components"
  • Inconsistent structures across projects

The Solution: CALM Patterns pre-define the required structure of an architecture. They specify which nodes must exist, what relationships must connect them, and what properties they must have.

2. Understand the Dual Superpowerโ€‹

One Pattern = Two Powers:

Power 1 โ€” Generation:

calm generate -p my-pattern.json -o new-architecture.json

Power 2 โ€” Validation:

calm validate -p my-pattern.json -a existing-architecture.json

3. Understand How Patterns Workโ€‹

Patterns use JSON Schema keywords to define requirements:

KeywordPurposeExample
constRequires an exact value"unique-id": { "const": "api-gateway" }
prefixItemsDefines exact ordered items in an arrayFirst node must be X, second must be Y
minItems / maxItemsEnforces array lengthExactly 3 nodes
$refReferences other schemasPoint to a node or Standards definition

Example: requiring a specific node

{
"nodes": {
"type": "array",
"prefixItems": [
{
"properties": {
"unique-id": { "const": "api-gateway" },
"node-type": { "const": "service" },
"name": { "const": "API Gateway" }
}
}
],
"minItems": 1
}
}

4. Create Your First Patternโ€‹

Prompt:

Create a CALM pattern at patterns/web-app-pattern.json for a 3-tier web application.

The pattern should:
1. Have a unique $id (https://example.com/patterns/web-app-pattern.json)
2. Have title "Web Application Pattern" and a description
3. Require exactly 3 nodes using prefixItems:
- "web-frontend" (node-type: webclient, name: "Web Frontend")
- "api-service" (node-type: service, name: "API Service")
- "app-database" (node-type: database, name: "Application Database")
4. Require exactly 2 relationships:
- "frontend-to-api": connects web-frontend to api-service
- "api-to-database": connects api-service to app-database

Use const for unique-id, node-type, and name properties.
Set minItems and maxItems to enforce exact counts.

5. Test Generationโ€‹

calm generate -p patterns/web-app-pattern.json -o architectures/generated-webapp.json

Open architectures/generated-webapp.json and verify:

  • โœ… Has exactly 3 nodes with the correct IDs, types, and names
  • โœ… Has exactly 2 relationships connecting them

6. Visualize the Generated Architectureโ€‹

  1. Open architectures/generated-webapp.json in VSCode
  2. Open preview (Ctrl+Shift+C / Cmd+Shift+C)
  3. See the 3-tier architecture visualized

7. Test Validation โ€” Passing Case with Warningsโ€‹

calm validate -p patterns/web-app-pattern.json -a architectures/generated-webapp.json

Should pass โœ… but show warnings about placeholder strings:

{
"spectralSchemaValidationOutputs": [
{
"code": "architecture-has-no-placeholder-properties-string",
"severity": "warning",
"message": "String placeholder detected in architecture.",
"path": "/nodes/0/description"
}
],
"hasErrors": false,
"hasWarnings": true
}

String placeholders look like "[[ DESCRIPTION ]]". Numeric placeholders use -1. These warn you that the generated architecture needs to be filled in โ€” they are not errors.

8. Test Validation โ€” Failing Caseโ€‹

Create a broken architecture to see validation fail:

  1. Copy architectures/generated-webapp.json to architectures/broken-webapp.json
  2. Change the unique-id of "api-service" to "backend-api"
calm validate -p patterns/web-app-pattern.json -a architectures/broken-webapp.json

Should fail โŒ โ€” the pattern catches that "api-service" is missing. You'll also see errors for relationships referencing the now-missing node ID.

9. Enhance the Generated Architectureโ€‹

Prompt:

Update architectures/generated-webapp.json to add:
1. Descriptions for each node explaining their purpose
2. A description for each relationship
3. Interfaces on api-service (host, port for HTTPS)
4. Interfaces on app-database (host, port for PostgreSQL)

Keep the unique-ids, node-types, and names exactly as they are.

10. Validate the Enhanced Architectureโ€‹

calm validate -p patterns/web-app-pattern.json -a architectures/generated-webapp.json
{
"jsonSchemaValidationOutputs": [],
"spectralSchemaValidationOutputs": [],
"hasErrors": false,
"hasWarnings": false
}

No warnings โœ… โ€” adding extra properties doesn't break pattern compliance.

Before moving on, use git to capture the state of your work. A descriptive commit message will help future-you understand what changed and why.

Key conceptsโ€‹

Pattern Anatomyโ€‹

KeywordEnforcesAllows
constExact valueNothing else
prefixItemsSpecific ordered itemsAdditional items after them
minItems + maxItems (equal)Exact array lengthโ€”
$refSchema from another fileProperties defined there

Placeholdersโ€‹

Generated architectures use placeholders as signals:

  • String: "[[ DESCRIPTION ]]" โ€” must be replaced before production
  • Numeric: -1 for numeric fields like port numbers

Pattern vs Architectureโ€‹

A Pattern defines the shape any matching architecture must have. An architecture that satisfies the Pattern is free to add extra nodes, relationships, interfaces, and metadata โ€” Patterns only constrain what they explicitly specify.

Troubleshootingโ€‹

If your pattern won't generate a valid architecture, use this prompt with the CALM Agent:

My pattern doesn't generate a valid architecture when I run the generate command.
Look at this valid pattern for reference:
https://raw.githubusercontent.com/finos/architecture-as-code/refs/heads/main/conferences/osff-ln-2025/workshop/conference-signup.pattern.json
Identify the problem in my pattern.

Next stepsโ€‹

In the next tutorial, you'll learn how to create organizational Standards โ€” JSON Schema extensions that define required properties like cost centers, owner fields, and compliance tags!