Source schema
The exact machine anchors an .angl file may use. Everything else is prose.
An .angl file is a structured Markdown document. Markdown is the carrier
format; Angl only treats a few lines as schema. Only these anchors are machine
schema:
> Boundary:
> Runs as:
> Uses:
## Behavior
## Examples
Input ...:
Fixture ...:
Returns:
Fails with error containing:Normal Markdown prose is not schema.
Required
- A chapter title:
# Normalize Event - A typed boundary:
> Boundary: `normalize_event(raw: object) -> object` - Behavior prose under
## Behavior. Guides generation, never decides correctness. - At least one executable example under
## Examples. These decide correctness.
Optional
- Purpose under
## Purpose. Human documentation only. - Target:
> Runs as: `go`. Defaults topython. See Targets. - Dependencies:
> Uses: `normalize_event`, `classify_severity`. See Composition.
Rail rules
- Schema rails must appear before the first section.
- The boundary function name must be a valid identifier.
- Dependencies must refer to existing chapter names.
- Unknown
>rails are parse errors. These are not valid:
> Function: `checkout`
> Files: `checkout.py`, `helpers.py`
> Algorithm: `dijkstra`Use natural language in Behavior for product semantics, and generated
manifests for generated files.
Example rules
Inputs are positional. Two Input blocks produce two function arguments in
order:
Input `event`:
```json
{"fingerprint": "pay-500"}
```
Input `open_incidents`:
```json
[]
```Return examples define exact expected values and must contain JSON that parses:
Returns:
```json
{"ok": true}
```Error examples use substring matching:
Fails with error containing: serviceRules:
- Every JSON block must parse.
- Input block names should match boundary argument names.
- Return blocks define exact expected values.
- Error examples define exact required error substrings.
- One-line JSON is allowed by the parser but is expanded by the formatter.
The type boundary
Values that cross the judge shim are JSON: number, string, bool, null, array,
object, plus the error channel {"ok": false, "error": msg}. The
expressiveness ceiling of Angl is what can cross this boundary plus what
fixtures exist. Extending either extends the language.
Generated manifest
Every compiled chapter emits a manifest reporting what the compiler actually made:
{
"chapter": "checkout",
"boundary": "checkout(cart: object) -> object",
"target": "typescript",
"implementation": "checkout.ts",
"host_adapter": "checkout.py",
"judge_adapter": "checkout_shim.py",
"generated_files": ["checkout.ts", "checkout.py", "checkout_shim.py"],
"public_files": ["checkout.ts", "checkout.py"],
"private_files": ["checkout_shim.py"]
}The manifest is evidence. It is not source truth. Adapters are build plumbing and should stay hidden unless you ask to inspect generated output.
Legacy forms
Older specs using name, interface, target, uses, INTENT, and
CONTRACT are still accepted, for migration only. The compact case form also
still parses:
name add
interface add(a: number, b: number) -> number
INTENT
Add two numbers.
CONTRACT
case: 1, 2 -> 3
case: 1, "x" -> !error contains "number"The formatter rewrites accepted aliases into canonical v0.2 form.