angl-cli
v0.1.12
Published
Contract-checked code regeneration from Angl behavior chapters
Readme
Angl
Angl is a small experiment in contract-checked code regeneration.
You commit a readable chapter of English behavior plus executable expectation examples. A configured compiler agent turns that chapter into ordinary code. A black-box judge accepts the generated edition only if the examples pass.
The semantic model is:
contract pins, intent guidesEnglish helps the compiler choose an implementation. It never decides correctness. Only executable examples do.
Why
Generated code is often the least interesting part of a system. The behavior you meant to preserve is usually the interface plus the observable cases that must keep passing.
Angl tests that idea directly:
- commit the intent and executable examples
- generate code from the spec
- regenerate when the ecosystem changes
- accept the new artifact only if the same contract still passes
One proof harness in this repo uses a real pydantic v1 to v2 break:
- old generated code imports
BaseSettingsfrompydantic - pydantic v2 moves it to
pydantic-settings - the old artifact fails under the newer dependency set
- the unchanged
.anglspec is recompiled - the new artifact passes the same contract cases
The composed demo goes one step further: provision_service calls
validate_config. When validate_config fails under the newer dependency set,
provision_service fails too. Regenerating only validate_config makes both
units pass again, and
provision_service.py stays byte-for-byte identical.
dependency changed
one generated file was replaced
downstream generated code stayed byte-identicalExample
# Fetch Price
> Boundary: `fetch_price(url: string) -> number`
> Runs as: `python`
## Purpose
Provide the price value from a JSON HTTP response.
## Behavior
Fetch JSON from the given URL and return the `price` field as a number. If the
field is missing, fail with an error that mentions `price`.
## Examples
### The service returns a price
When the URL serves a price, the chapter returns that price.
Fixture `http_fixture`:
```json
{
"price": 19.99
}Returns:
19.99The service omits the price
When the URL serves JSON without a price field, the chapter rejects it.
Fixture http_fixture:
{}Fails with error containing: price
The required source surface is small: title, boundary, behavior, and at least
one executable example. Purpose, target, and uses are optional. Legacy `name`,
`interface`, `target`, `uses`, `INTENT`, and `CONTRACT` syntax is still accepted
only for migration.
Angl is meant for contract boundaries, not every private helper function. Write
cases for public behavior you care about preserving. Generated code can have
whatever internal helpers it wants; untested behavior is unspecified.
## Repo Shape
This repo is the Angl language/toolchain repo. It should stay small enough that
someone can inspect the compiler, read real chapters, run tests, and understand
the contract model without digging through launch assets.
What belongs here:
- `angl/`: the parser, compiler adapter, verifier, project tools, and CLI
- `specs/`: sample `.angl` chapters used by tests and examples
- `tests/`: regression tests for the Angl toolchain itself
- `docs/`: design and usage docs
- `demo/`: small reproducible proof harnesses only
What does not belong here:
- generated build outputs
- rendered launch videos, GIFs, and frame dumps
- full product demos like FreshOps, which should live in their own repos
- local model, Tailscale, or machine-specific ops details
GitHub may still show Python prominently because the current Angl compiler is
implemented in Python and GitHub Linguist does not know the Angl language yet.
The `.gitattributes` file marks support material out of language stats and
uses Markdown highlighting for `.angl` chapters until Angl has first-class
Linguist support.
## Trickle-Down Coding
The intended workflow is:
1. Write chapters for the stable product boundaries.
2. Add expectation examples for behavior that must not drift.
3. Let the compiler agent generate ordinary code for each chapter.
4. Verify every chapter black-box.
5. Compile dependents after dependencies, so verified behavior flows upward.
Conceptually, this feels like building a feature tree. Mechanically, Angl uses a
topological order: dependencies compile first, then the chapters that use them.
That is the part that keeps downstream code from silently diverging.
## Where Tests Go
There are two different kinds of tests:
- Product behavior tests live inside each `.angl` chapter as executable
examples. These are the examples the judge runs against generated editions.
- Toolchain tests live in `tests/`. These test Angl itself: parsing,
compiling, verifying, book rendering, and regression bugs.
Generated editions do not get committed with their own hand-written tests. They
are disposable build outputs. If behavior matters, put it in the chapter as an
example.
## How File Types Are Chosen
Today, each chapter has one compile target. The target is chosen by the source
sentence:
```angl
Compile this chapter as `python`.Supported targets are python, node, ruby, go, rust, typescript,
bundle, and assembly. A composed app can still be polyglot because
different chapters can choose different targets:
picnic_normalize.angl -> Python
picnic_menu.angl -> Node
picnic_pack.angl -> Ruby
picnic_plan.angl -> Pythonpicnic_plan calls the other chapters through uses; it does not contain all
those languages itself. One chapter generating multiple files is a future
design direction, not what the current compiler guarantees.
bundle is the generic path for multi-file or native outputs. A bundle can
include generated assembly, a generated adapter, and build commands, but the
compiler does not know the app's domain or ABI.
assembly is a stricter bundle target. It requires generated .s source, a
local clang build into a shared library, and a Python host adapter that calls
the native library through ctypes.
Pipeline
specs/x.angl
-> parse
-> compile with the configured model provider
-> write build/<func>.<target> plus generated adapters
-> run each expectation through the judge adapter
-> accept only if every expectation passesThe verifier never imports the generated edition directly. It runs the judge adapter as a subprocess and compares JSON input/output. That is the core language-neutrality boundary.
Install
Install the CLI:
npm install -g angl-cli
angl try --provider claude-codeThe npm package is a thin distribution shim. On first run, it creates a private
Python venv under ~/.angl/npm/<version>, installs the bundled Angl Python
toolchain into that venv, then delegates to the real angl CLI. The compiler
is still the same Angl toolchain; npm is just the delivery path.
Yarn 4 blocks packages published in the last 24 hours by default. The
YARN_NPM_MINIMAL_AGE_GATE=0 prefix is only needed while a fresh Angl release
is inside that window.
Shell bootstrapper:
curl -fsSL https://raw.githubusercontent.com/ddavidgao/angl/main/install.sh | shThis installs angl into an isolated venv at ~/.angl/venv and links the CLI
at ~/.local/bin/angl.
For a reproducible install, pin the installer and the package source to the same tag or commit:
curl -fsSL https://raw.githubusercontent.com/ddavidgao/angl/<tag-or-commit>/install.sh | ANGL_INSTALL_REF=<tag-or-commit> shFor launch, replace <tag-or-commit> with the release tag. For a private audit,
replace it with an exact commit SHA.
If you already use pipx:
pipx install 'git+https://github.com/ddavidgao/angl.git@<tag-or-commit>'For local development inside this repo:
python3 -m venv .venv
.venv/bin/python -m pip install -e .Check the version:
angl --versionProve the compiler path works:
angl try --provider claude-codeCreate a starter project when the proof passes:
angl new hello-angl --provider claude-code
cd hello-angl
angl check
angl doctor --provider-smoke
angl buildSee docs/GETTING_STARTED.md for the full first-run path.
Run
Create the local venv:
python3 -m venv .venv
.venv/bin/python -m pip install -e .Save a compiler provider once:
angl setup claude-code
angl doctor --provider-smokeOr use Codex from a normal terminal:
angl setup codex
angl doctor --provider-smokeOr use a local Ollama model:
angl setup ollama --model qwen2.5-coder:14b --url http://127.0.0.1:11434
angl doctor --provider-smokeEnvironment variables still work as one-off overrides. Provider choice is not
part of the .angl language.
Check your setup:
.venv/bin/angl doctor --spec specs/provision_service.anglRun a composed spec:
.venv/bin/angl build specs/provision_service.anglVerify existing generated output without recompiling:
.venv/bin/angl verify specs/provision_service.anglRead a composed spec as a project book:
.venv/bin/angl preview specs/build_escalation_packet.anglRender the book as a static source-reader artifact:
python3 -m angl.book specs/build_escalation_packet.angl \
--results build/.eval/build_escalation_qwen_after_hardening.json \
--build-dir build/.eval/qwen2.5-coder_14b/build_escalation_packet \
--html build/book/incident-escalation.htmlThe HTML reader is generated from real .angl files. It shows the source tree,
dependency graph, prose intent, scenario table, exact source, generated edition,
latest pass/fail evidence, and whether the generated artifact is older than the
current source file.
For a more Markdown-like reading mode, render the same program as chapters:
python3 -m angl.book specs/picnic_plan.angl \
--results build/.eval/picnic_qwen.json \
--build-dir build/.eval/qwen2.5-coder_14b/picnic_plan \
--view chapter \
--html build/book/picnic-chapter-view.htmlThis mode turns compiler fields like name, interface, target, and uses
into prose while keeping the exact stored .angl source collapsible.
You can also write the same prose-first view as Markdown:
python3 -m angl.book specs/picnic_plan.angl \
--results build/.eval/picnic_qwen.json \
--build-dir build/.eval/qwen2.5-coder_14b/picnic_plan \
--markdown build/book/picnic-chapter-view.mdOr serve a live local reader that rebuilds from the current .angl files on
each request:
python3 -m angl.book specs/picnic_plan.angl \
--results build/.eval/picnic_qwen.json \
--build-dir build/.eval/qwen2.5-coder_14b/picnic_plan \
--serve \
--port 8783Routes:
/chapter prose-first chapter view
/reader IDE-style source reader
/markdown generated Markdown
/api/book JSON payload with exact source and generated artifact textRun the tangible incident-console app:
PORT=8770 python3 demo/incident_console/server.pyThen open:
http://127.0.0.1:8770Additional concept views:
http://127.0.0.1:8770/library.html # repo folders as shelves
http://127.0.0.1:8770/reader.html # one unit as a readable chapterThis local web app posts an event to a stdlib Python API. The API calls the
generated Angl escalation pipeline in build/.eval/qwen2.5-coder_14b/, which
in turn crosses Python, Node, Ruby, Go, Rust, and TypeScript generated
artifacts through the same proxies the judge uses.
Run the simpler phone-friendly picnic planner:
.venv/bin/python3 demo/picnic_planner/server.pyThen open:
http://127.0.0.1:8780This app is intentionally small and UI-friendly. It is compiled from four Angl chapters: normalize a picnic request, choose a menu, build a packing list, and compose the final plan.
Run the demos:
python3 demo/heal.py
python3 demo/heal_composed.pyThe generated artifacts land in build/ and are intentionally gitignored.
Tests
The tests are stdlib-runnable and do not require a model:
python3 tests/test_parse.py
python3 tests/test_verify.py
python3 tests/test_compile.py
python3 tests/test_run.py
python3 tests/test_book.pyCurrent limits
- No sandboxing. Generated code runs as a normal subprocess with your user
privileges. Do not run untrusted
.anglfiles. - Contract completeness is the ceiling. Untested behavior is unspecified.
- Case authoring is still real work. Angl makes the checked cases the source of truth; it does not remove the need to state important examples.
- Regeneration is not a proof of correctness. It is a way to ask a model for a new artifact, then reject it unless the checked contract still passes.
- Python, Node, Ruby, Go, Rust, TypeScript, bundle, and assembly targets exist, but non-Python targets are still prototype-grade and currently use subprocess, Docker, or generated adapter plumbing.
- Fixture coverage is small.
http_fixtureexists; richer systems need richer fixtures.
Read DESIGN.md before changing engine internals.
