ilo is a token-optimised programming language for AI agents.
- GitHub: https://github.com/ilo-lang/ilo
- Language spec: SPEC.md
- Current version: 0.11.6 (installed at
~/.cargo/bin/iloviacargo install)
Prefix-notation, strongly-typed, AI-agent-first language. Programs are small, verified before execution, and designed to minimise total token cost across generation + retries + context loading.
| File | Purpose |
|---|---|
src/main.rs |
CLI entry point, import resolution, .env loading |
src/lexer/mod.rs |
Tokeniser (logos) |
src/parser/mod.rs |
Recursive-descent parser |
src/ast/mod.rs |
AST types (Decl, Stmt, Expr, Type) |
src/verify.rs |
Type verifier |
src/interpreter/mod.rs |
Tree-walking interpreter |
src/vm/mod.rs |
Register VM + bytecode compiler |
src/codegen/ |
Python, explain, fmt, dense-wire emitters |
src/tools/ |
MCP client, HTTP tool provider |
examples/ |
Runnable example programs (also cargo test regression suite) |
skills/ilo/ |
Agent Skill (Claude Code plugin + cross-platform installer) |
npm/ |
npm package (WASM build + Node.js WASI shim for npx ilo-lang) |
SPEC.md |
Full language specification |
research/TODO.md |
Planned work |
ilo 'dbl x:n>n;*x 2' 5 # inline code
ilo program.ilo funcname args # from file
cargo test # full test suiteEvery new builtin reserves its name from the user namespace at parse time (ILO-P011). To keep that reservation forecastable across releases, follow these rules when adding a builtin:
- Land the long name first. New builtins ship under a name of 4 characters or longer (
countif,flatmap,cumsum,partition,dtparse, …). The 2-character namespace is closed to new entries - agents rely on "any 2-char name not in the published reserve list is mine to use, forever." Adding a new 2-char builtin breaks that promise and breaks every carry-forward script that happened to bind the name. - 3-char names are discouraged but not banned. The 3-char surface is already dense and most short forms are taken. If a 3-char name reads obviously natural for the operation (and no plausible domain binding would reach for it), it's acceptable, but the long form must land first and the 3-char form is added as an alias afterwards. Call out the new reservation in the changelog.
- Short aliases come later. Once the long-name builtin has shipped, a short alias may be added through the
builtin_aliasesmechanism (seesrc/ast/mod.rsand the### Builtin aliasessection of SPEC.md) - but only if:- The long form is unambiguous (no other builtin or near-name conflicts).
- The short form does not shadow a plausible user binding (e.g.
ctfor "count" was unsafe because analytics agents reach for it as "category text";nwhereorcountifwould have been the right long form). Verify bygrep-ing recent persona artifacts (/tmp/ilo-persona-*/) andexamples/*.ilofor binding-position uses of the candidate alias. - The new reservation is added to the
### Reserved namespacesenumeration inSPEC.mdin the same commit, and a targeted ILO-P011 guard is added inparse_decl/parse_stmt/parse_fn_declto reject the alias as a binding or user-function name (mirroring the canonical-builtin check). Precedent:rng→range(feature/mp-rng-aliases).
- Drift guard.
tests/regression_reserved_names_doc.rsasserts the SPEC enumeration matchesBuiltin::ALLat test time. Adding a builtin without updating the doc fails the suite - that's the contract that keeps the published forecast accurate. - Existing short builtins are grandfathered. Anything already on the reserve list (
avg,ct,sin,flat,frq, …) stays. The 3+ char-first rule applies to new entries only.
The manifesto framing: agents budget around the reserve list once, not once per release. The cost of a release that breaks carry-forward scripts on a name collision is paid by every running agent; the cost of a 4-char long-name plus a deferred short alias is paid once by the language.
- Bump version everywhere:
scripts/bump-version.sh X.Y.Z(rewritesCargo.toml,AGENTS.md,.claude-plugin/plugin.json,.claude-plugin/marketplace.json;npm/andpi/are bumped from the tag by CI) - Commit + tag
vX.Y.Z git push origin main --tags→ triggers.github/workflows/release.yml→ builds 5 native targets + WASM, publishes GitHub Release + npm package
cargo build --target wasm32-wasip1 --release --no-default-features produces ilo.wasm (2.1MB). The npm/ directory wraps it in a Node.js WASI shim published as ilo-lang on npm. Requires NPM_TOKEN secret in GitHub repo settings.