---
extension: 'semantic-prompt-language'
version: 1
model: 'gpt-6-luna'
preamble: 'Be concise.'
---
# Hello, SPL
Prose like this is commentary. Only `spl` fences and blockquotes run, top to bottom, in one shared scope.
```spl
let topics = ['recursion', 'closures', 'regular expressions']
hydratable class Card:
term: str
definition: str
let cards = object()
for topic in topics:
cards[topic] = ask(schema=Card, repairs=1) 'A one-sentence flashcard about {topic}'
```
> Pick the key of @cards whose card a beginner would find hardest. Save that exact key to @hardest
```spl
assert hardest in topics "unexpected topic '{hardest}'"
restrict './out':
write_file('./out/cards.json', json_stringify(object(cards), 2))
success object:
'cards': len(cards)
'hardest': hardest
```
- built-in
askgenerates LLM response with schema validation and one repair - natural language blockquote uses agent mode to follow instructions and uses tools to save variable, the variable is saved to global scope
schema=Carddecodes each answer and hydrates contructor-free instance of classCard, see Gradual typingassertbreaks flow in case of mimatchrestrictlimits scope's file access to particular locationsuccessreturns json
Opt-in Types#
Language is dynamic but has full support for opt-in static type checker. There are supported primitive types, structs, classes and dynamic catch-all objects. Functions are first class citizens.
---
extension: 'semantic-prompt-language'
version: 1
model: 'gpt-6-luna'
---
# Types
This sample shows how to use opt-in types.
```spl
type FloatOrInt = float | int [description = 'Either float or int']
let numbers: list[FloatOrInt] = []
for i in range(4):
let num = ask(tokens=128, schema=FloatOrInt) 'Sample number'
numbers.append(num)
for n in numbers:
if isinstance(n, int):
log('Integer: {n}')
else:
log('Float: {n}')
```
```spl
class Person:
firstName: str
lastName: str
age: int
def toString():
return '{self.firstName} {self.lastName} at age {self.age}'
let result = ask(schema=struct(Person)) 'Sample person JSON with firstName, lastName and int age fields'
let person: Person = validate(result, Person)
success person.toString()
```
Why SPL?#
- Short loops. One file, run directly.
--checkvalidates syntax without a model, and trace/replay reruns your code and guards against recorded model answers. - Exact code where it matters. Control flow, arithmetic and I/O never call a model.
askandthinkgenerate values without tools;agentexpressions and blockquotes can act. - Guards you can see.
fmt,schemaandassertcheck data;restrictchecks actions. Prompt guidance (enforce,forbid,len) is kept separate from validation. - Readable. Inputs, prompts, checks and outputs sit in one document, top to bottom.
- Optional typed contracts. Enums, structs, classes and reusable aliases describe model output. Annotations, typed functions and persistent mutable contracts enforce consistency; assertions still check whether the content makes sense.
How a run works#
- Frontmatter opts the file in. All fences are parsed first, so syntax errors fail before anything runs.
- Fences and blockquotes execute in document order in one shared scope.
- A blockquote sends its text, visible bindings and runtime tools to an agent. The model calls tools to invoke functions, read environment values, request human input and load/save shared variables. It never submits generated SPL.
ask,thinkandagentuse the official OpenAI, Anthropic and Google clients, one fresh conversation per call.successprints the result on stdout. Logs go to stderr.
Non-goals#
- Full Python, inheritance, recursive schemas or general-purpose automatic source conversion.
- Reproducible model output, transactional actions or an OS sandbox.
Where next#
- Getting started: install, sign in, run and iterate.
- Language: SPL syntax, scopes, built-ins and tools.
- Natural language & models: blockquotes,
ask,think,agentand output validation. - Guards & failures: restrictions, assertions, failures and human input.
- CLI & runtime: options, traces, stores, MCP and embedding.
- Examples: real-world workflows.
- Typing migration: breaking syntax, contracts, numeric representations and class schemas.