BAML (BoundaryML) Skill
BAML is a domain-specific language for building AI applications with type-safe LLM calls. It provides guaranteed type safety, automatic JSON parsing, retry logic, and streaming support across multiple languages.
When to Use This Skill
Use this skill when:
- Building AI applications with structured LLM outputs
- Need type-safe LLM function calls across Python/TypeScript/Ruby/Go
- Implementing complex prompt engineering with validation
- Extracting structured data from unstructured text (resumes, documents, etc.)
- Need streaming responses with partial parsing
- Working with multiple LLM providers (OpenAI, Anthropic, Google AI, etc.)
- Switching between LLM providers without code changes
- Testing LLM functions with the VSCode Playground
- Handling classification, extraction, or generation tasks with LLMs
Quick Reference
1. Define a BAML Function
// baml_src/extraction.baml
class Resume {
name string
skills string[]
education Education[]
seniority SeniorityLevel
}
class Education {
school string
degree string
year int
}
enum SeniorityLevel {
JUNIOR
MID
SENIOR
STAFF
}
function ExtractResume(resume_text: string) -> Resume {
client "openai/gpt-4o"
prompt #"
Extract the following information from this resume:
{{ resume_text }}
Classify seniority as:
- JUNIOR: 0-2 years experience
- MID: 2-5 years experience
- SENIOR: 5-10 years experience
- STAFF: 10+ years experience
"#
}
2. Generate Client Code
baml-cli generate
This generates type-safe client code in your language with:
- Automatic JSON parsing and validation
- Retry logic and error handling
- Streaming support
- Type safety and autocomplete
3. Call from Your Code
Python:
from baml_client import b
from baml_client.types import Resume
# Async client
resume = await b.ExtractResume(resume_text="John Doe, Python expert...")
# Sync client
resume = b.sync.ExtractResume(resume_text="John Doe, Python expert...")
# Streaming
stream = b.stream.ExtractResume(resume_text="...")
async for partial in stream:
print(partial.name) # Type-safe partial results
TypeScript:
import { b } from './baml_client'
// Async client
const resume = await b.ExtractResume({ resume_text: "John Doe..." })
// Streaming
const stream = b.stream.ExtractResume({ resume_text: "..." })
for await (const partial of stream) {
console.log(partial.name) // Type-safe partials
}
4. Common Client Configurations
// Multiple providers with fallbacks
client<llm> GPT4 {
provider "openai"
options {
model "gpt-4o"
api_key env.OPENAI_API_KEY
temperature 0.7
}
}
client<llm> Claude {
provider "anthropic"
options {
model "claude-sonnet-4-5"
api_key env.ANTHROPIC_API_KEY
}
}
client<llm> Gemini {
provider "google-ai"
options {
model "gemini-2.5-flash"
api_key env.GOOGLE_API_KEY
}
}
// Fallback chain
client<llm> MyAI {
provider "fallback"
options {
strategy [GPT4, Claude, Gemini]
}
}
5. Array Syntax
{
// Single-line arrays
skills ["Python", "Rust", "Go"],
// Multi-line arrays
cities [
"New York",
"Los Angeles",
"Chicago"
],
// Nested objects in arrays
education [
{
school "UC Berkeley",
degree "B.S. Computer Science",
year 2020
},
{
school "MIT",
degree "M.S. AI",
year 2022
}
]
}
6. Test Your Functions
test ExtractJohnDoe {
functions [ExtractResume]
args {
resume_text "John Doe
Skills: Python, Machine Learning, TypeScript
Education: UC Berkeley, B.S. Computer Science, 2020"
}
}
Run tests:
# Run all tests
baml-cli test
# Run specific test
baml-cli test ExtractJohnDoe
# Run from specific directory
baml-cli test --from /path/to/baml_src
Core Concepts
Type System
BAML provides a rich type system that maps to your target language:
Primitives:
string- Text dataint- Integersfloat- Floating point numbersbool- Boolean valuesnull- Null/None/nil
Collections:
string[]- Arrays/Listsmap<string, int>- Dictionaries/Maps
Custom Types:
class- Structured objectsenum- Enumerated values (automatically explained to LLM)
Example:
class Person {
name string
age int? // Optional field
tags string[]
metadata map<string, string>
}
Client Methods
Every BAML function generates these methods:
Direct Call:
result = await b.MyFunction(arg1="value")
Streaming:
stream = b.stream.MyFunction(arg1="value")
async for partial in stream:
print(partial)
Get Request (without sending):
request = await b.request.MyFunction(arg1="value")
# Returns HTTP request object, doesn't send it
Parse Response:
request = await b.request.MyFunction(arg1="value")
# Send request yourself...
parsed = b.parse.MyFunction(response)
Providers Supported
- OpenAI - GPT-4, GPT-4o, GPT-5, etc.
- Anthropic - Claude Sonnet, Claude Opus
- Google AI - Gemini 2.5 Pro/Flash
- Vertex AI - Google Cloud Vertex
- AWS Bedrock - Claude, Llama, etc.
- Azure OpenAI - Azure-hosted models
- OpenRouter - Access to 100+ models
- Ollama - Local models
- Groq - Fast inference
- Cerebras - Ultra-fast inference
- OpenAI-Generic - Compatible APIs
Multi-Language Support
BAML generates idiomatic code for:
- Python - Async/sync, Pydantic models
- TypeScript/JavaScript - Promises, Zod schemas
- Ruby - Async/sync support
- Go - Goroutines, struct types
- Elixir - Community-supported
Common Patterns
1. Classification with Context
enum Sentiment {
POSITIVE @description("Happy, satisfied, excited")
NEGATIVE @description("Angry, frustrated, disappointed")
NEUTRAL @description("Factual, no strong emotion")
}
function ClassifySentiment(text: string) -> Sentiment {
client "openai/gpt-4o-mini"
prompt #"
Classify the sentiment of this text: {{ text }}
"#
}
The @description annotations are automatically sent to the LLM for better classification.
2. Structured Extraction
class Invoice {
invoice_number string
date string
vendor string
line_items LineItem[]
total float
}
class LineItem {
description string
quantity int
unit_price float
total float
}
function ExtractInvoice(invoice_text: string) -> Invoice {
client "anthropic/claude-sonnet-4-5"
prompt #"
Extract invoice data from:
{{ invoice_text }}
"#
}
3. Fallback Strategy
client<llm> Primary {
provider "openai"
options { model "gpt-4o" }
}
client<llm> Backup {
provider "anthropic"
options { model "claude-sonnet-4-5" }
}
client<llm> Resilient {
provider "fallback"
options {
strategy [Primary, Backup]
}
}
function MyFunction(input: string) -> Output {
client Resilient // Auto-fallback on failure
}
4. Custom Retry Logic
retry_policy MyRetry {
max_retries 3
strategy {
type exponential_backoff
delay_ms 1000
multiplier 2
}
}
function MyFunction(input: string) -> Output {
client "openai/gpt-4o"
retry_policy MyRetry
}
5. React Hooks (TypeScript Only)
BAML auto-generates React hooks:
import { useExtractResume } from './baml_client/react'
function ResumeExtractor() {
const { mutate, data, isLoading, isStreaming, error } = useExtractResume({
stream: true,
onStreamData: (partial) => {
console.log("Streaming:", partial?.name)
},
onFinalData: (final) => {
console.log("Final:", final)
},
onError: (err) => console.error(err)
})
return (
<button => mutate({ resume_text: "..." })}>
Extract Resume
</button>
)
}
Working with This Skill
For Beginners
- Install BAML: Follow language-specific installation in
../../../references/llms-txt.md - Create
baml_src/folder: Store your .baml files here - Write your first function: Define types and prompt
- Run
baml-cli generate: Generates client code - Import and call: Use the generated client in your code
First Example:
// baml_src/hello.baml
function SayHello(name: string) -> string {
client "openai/gpt-4o-mini"
prompt #"Say hello to {{ name }} in a creative way"#
}
For Specific Features
- Streaming: Use
b.stream.FunctionName()- see AsyncClient/SyncClient section in references - Multi-provider: Define multiple clients and use fallback provider
- Testing: Write test blocks and run
baml-cli test - Debugging: Use VSCode Playground to see raw requests/responses
- Error Handling: See error handling section in references
For Advanced Users
- Custom Providers: Use
openai-genericfor compatible APIs - Media Handling: Configure
media_url_handlerfor images/audio/PDFs - Role Mapping: Use
allowed_rolesandremap_rolesfor custom providers - Finish Reason Control: Use
finish_reason_allow_list/deny_list - Prompt Caching: Use
allowed_role_metadatafor cache control
Key Advantages Over Other Frameworks
vs Langchain
Langchain:
llm = ChatOpenAI(model="gpt-4o")
structured_llm = llm.with_structured_output(Resume)
result = structured_llm.invoke("John Doe...")
# ❌ No visibility into prompts
# ❌ No testing without running code
# ❌ Provider-specific code
BAML:
function ExtractResume(text: string) -> Resume {
client "openai/gpt-4o"
prompt #"Extract: {{ text }}"#
}
result = await b.ExtractResume(text="John Doe...")
# ✅ Prompts visible in .baml files
# ✅ Test in Playground without code
# ✅ Change provider without code changes
vs Direct API Calls
- Type Safety: Guaranteed at build time
- Error Handling: Built-in retries and fallbacks
- JSON Parsing: Handles malformed JSON automatically
- Streaming: Partial object parsing built-in
- Testing: Playground for rapid iteration
- Multi-language: Same .baml files, multiple languages
Development Workflow
- Write BAML function in
baml_src/*.baml - Test in Playground (VSCode extension)
- Generate client:
baml-cli generate - Call from code with full type safety
- Iterate on prompt without changing code
Reference Files
This skill includes comprehensive documentation in ../../../references/:
- llms-txt.md (235 pages) - Complete BAML documentation including:
- Installation guides for all languages
- Function syntax and type system
- Client providers (OpenAI, Anthropic, Google AI, etc.)
- Streaming and async patterns
- Testing and debugging
- Error handling
- React hooks reference
- Provider-specific options
Use view ../../../references/llms-txt.md for detailed information on any topic.
Resources
Official Links
- Documentation: https://docs.boundaryml.com/
- GitHub: https://github.com/boundaryml/baml
- VSCode Extension: Search "BAML" in VSCode Marketplace
- Examples: https://github.com/boundaryml/baml-examples
CLI Commands
baml-cli generate # Generate client code
baml-cli test # Run all tests
baml-cli test TestName # Run specific test
baml-cli --version # Check version
Notes
- Auto-generated from official documentation (llms.txt format)
- All code examples are from official BAML docs
- Supports Python 3.10+, TypeScript/Node.js, Ruby, Go
- VSCode extension provides Playground for testing
- Zero runtime dependencies beyond the generated client
Updating
To refresh with latest BAML documentation:
python3 cli/doc_scraper.py --name baml --url https://docs.boundaryml.com/home
python3 cli/enhance_skill_local.py output/baml/
python3 cli/package_skill.py output/baml/