Skip to content

Syntax Reference

Lines starting with # are comments:

# This is a comment
system "MySystem": # inline comment
version = "1.0.0"

SODL uses 2-space indentation. Blocks are introduced with a colon (:).

system "MySystem":
stack:
language = "TypeScript"

All string values are double-quoted:

primary = "Marketing website for my product"

Arrays use bracket syntax with double-quoted items:

outcomes = [
"Hero section with CTA",
"Feature grid",
"Contact form"
]

Simple assignments use =:

version = "1.0.0"
language = "TypeScript"

Blocks use a name followed by colon on the same line:

stack:
language = "TypeScript"
framework = "Astro"

Named blocks (like policy, module, pipeline, step) include an identifier:

policy Security:
rule "Validate all inputs" severity=high
module AuthModule:
owns = ["Authentication logic"]

A policy groups rules under a named concern. Each rule has a severity:

policy Security:
rule "All API endpoints require JWT validation" severity=critical
rule "Rate limit authentication endpoints" severity=high
rule "Log all authentication attempts" severity=medium
policy CodeQuality:
rule "All public functions have docstrings" severity=medium
rule "Variable names are descriptive" severity=low
LevelMeaning
criticalMust not be violated — blocks generation
highRequired constraint
mediumStrong recommendation
lowSuggestion

Inheritance uses the extends keyword:

template "Base":
stack:
language = "TypeScript"
system "MySystem" extends "Base":
...
interface MyComponent extends AstroComponent:
...

Module dependencies use implements, requires, and exports:

module UIComponents:
implements = [HeroComponent, FeatureCard]
exports = [HeroComponent, FeatureCard]
requires = [ThemeConfig]

Interfaces declare methods with typed parameters:

interface HeroComponent:
method render(tagline: str, subtitle: str) -> str

Primitive types: str, int, float, bool, bytes, UUID, datetime

Generic types — both bracket and angle-bracket syntax are accepted:

method get_all(page: int) -> List[Post]
method find(id: UUID) -> Optional[User]
method get_stats() -> Result<Success, Error>

API response types (used in endpoint declarations):

endpoint "GET /posts" -> List[PostCard]
endpoint "GET /post/{id}" -> HTML
endpoint "POST /action" -> Redirect
endpoint "GET /stream" -> SSE
endpoint "DELETE /item/{id}" -> Empty (204)
ElementConventionExample
Systems, TemplatesPascalCase string"MySystem"
Interfaces, Modules, PoliciesPascalCaseUserRepository
Pipelinesstring"Production"
StepsPascalCaseStepName
Methods, fieldssnake_caseget_by_id
EndpointsHTTP verb + path"GET /api/path"

Invariants are string assertions that must hold:

invariants:
invariant "Logo links to home /"
invariant "All images have alt text"

The output field in a step block is an identifier that declares what the step produces. The conventional values are:

ValueWhat it produces
designArchitecture decisions, diagrams, data models
codeApplication source code
testsTest files and test suites
diffCode changes for review
docsDocumentation files
pipeline "Development":
step Design:
output = design
require = "Define architecture and data models"
step Implement:
modules = ["AuthModule", "UserModule"]
output = code
gate = "Unit tests pass"
step Test:
output = tests
gate = "Coverage >= 85%"

The artifacts key lists file system paths that a module owns:

module UIComponents:
artifacts = ["src/components/", "src/layouts/"]