Simplified BAML Runtime
A minimal implementation of the BAML runtime that demonstrates core concepts by reducing the original ~50K line codebase to ~5K lines.
What is BAML?
BAML is a language for defining and calling LLM functions with structured outputs. The runtime:
- Converts type definitions into human-readable schemas
- Injects schemas into Jinja2 templates
- Calls LLM APIs
- Parses and validates LLM responses
Quick Start
[]
= "0.1.0"
= { = "1.0", = ["full"] }
use *;
use ;
use HashMap;
// 1. Define types
// 2. Define function
// 3. Define client
;
async
Core Components
| Component | File | Purpose |
|---|---|---|
| IR | src/ir.rs |
Type definitions (Class, Enum, Field, BamlValue) |
| Macros | simplify_baml_macros/ |
#[derive(BamlSchema)], #[baml_function], #[derive(BamlClient)] |
| Registry | src/registry.rs |
Collects types and builds IR |
| Schema | src/schema.rs |
Converts IR to human-readable schema strings |
| Renderer | src/renderer.rs |
Jinja2 template rendering with schema injection |
| Parser | src/parser.rs |
Lenient JSON parsing with type coercion |
| Runtime | src/runtime.rs |
Orchestrates all components |
Macro System
#[derive(BamlSchema)] — Type Definitions
Type Mapping:
String→FieldType::Stringi64,i32→FieldType::Intf64,f32→FieldType::Floatbool→FieldType::BoolOption<T>→ optional fieldVec<T>→FieldType::List(T)- Custom types →
FieldType::ClassorFieldType::Enum
#[baml_function] — Function Definitions
#[derive(BamlClient)] — Client Configuration
// OpenAI
;
// Anthropic via OpenRouter
;
// Local endpoint
;
Multi-Provider Support
Use OpenRouter for access to 100+ models with one API key:
;
;
let runtime = new
.ir
.client
.client
.build;
Running Examples
Streaming
See STREAMING.md for streaming support with partial JSON parsing.
How It Works
┌─────────────────────────────────────────────────────────────┐
│ Rust Struct + #[derive(BamlSchema)] │
└────────────────────┬────────────────────────────────────────┘
│ Procedural Macro
▼
┌─────────────────────────────────────────────────────────────┐
│ IR (Intermediate Representation) │
│ Class { name: "Person", fields: [...] } │
└────────────────────┬────────────────────────────────────────┘
│ SchemaFormatter
▼
┌─────────────────────────────────────────────────────────────┐
│ Human-Readable Schema │
│ "Answer in JSON: { name: string, age: int }" │
└────────────────────┬────────────────────────────────────────┘
│ PromptRenderer (Jinja2)
▼
┌─────────────────────────────────────────────────────────────┐
│ Final Prompt → LLM → JSON Response │
└────────────────────┬────────────────────────────────────────┘
│ Parser (lenient, type coercion)
▼
┌─────────────────────────────────────────────────────────────┐
│ BamlValue::Map({ "name": String("John"), "age": Int(30) }) │
└─────────────────────────────────────────────────────────────┘
What's Different from Full BAML?
Omitted: BAML language parser, CLI, WASM, advanced tracing, test runner, multi-language codegen, VS Code extension, complex retry policies.
Kept: Core IR types, schema formatting, Jinja2 rendering, lenient parsing, basic runtime.
Added: Native Rust macros for type-safe IR generation.
License
Educational implementation. For production, use the official BAML runtime.