Tutorials
Build Your First Validated Block
Create a price calculator block with domain-driven validation. You'll define the domain model, write the implementation, and run AI-powered validation.
Prerequisites
- Node.js 20+
- An OpenAI API key (or Anthropic/Google)
- 15 minutes
What You'll Build
A pricing.calculator block that:
- Takes a product and quantity as input
- Returns a price breakdown with subtotal, tax, and total
- Validates that the implementation follows your domain rules
Step 1: Create Project Structure
mkdir pricing-blocks && cd pricing-blocks
npm init -yCreate the folder structure:
mkdir -p blocks/pricing-calculatorStep 2: Define Your Domain in blocks.yml
Create blocks.yml in your project root:
$schema: "blocks/v2"
name: "Pricing System"
philosophy:
- "All monetary values must be in cents to avoid floating point errors"
- "Tax calculations must be explicit and auditable"
- "Never expose internal pricing logic in outputs"
domain:
entities:
product:
fields: [id, name, price_cents, tax_rate]
price_breakdown:
fields: [subtotal_cents, tax_cents, total_cents]
optional: [discount_cents]
semantics:
money_cents:
description: "Monetary value in cents (integer)"
schema:
type: integer
minimum: 0
tax_rate:
description: "Tax rate as decimal (0.0 to 1.0)"
schema:
type: number
minimum: 0
maximum: 1
ai:
provider: openai
model: gpt-4o-mini
validators:
- schema
- shape
- domain
blocks:
pricing.calculator:
description: "Calculates price breakdown for a product order"
path: blocks/pricing-calculator
inputs:
- name: product
type: entity.product
- name: quantity
type: integer
outputs:
- name: breakdown
type: entity.price_breakdownStep 3: Write the Block Implementation
Create blocks/pricing-calculator/block.ts:
import type { Product, PriceBreakdown } from './types';
export interface CalculatorInput {
product: Product;
quantity: number;
}
export interface CalculatorOutput {
breakdown: PriceBreakdown;
}
export function calculate(input: CalculatorInput): CalculatorOutput {
const { product, quantity } = input;
// Calculate in cents to avoid floating point errors
const subtotal_cents = product.price_cents * quantity;
const tax_cents = Math.round(subtotal_cents * product.tax_rate);
const total_cents = subtotal_cents + tax_cents;
return {
breakdown: {
subtotal_cents,
tax_cents,
total_cents,
},
};
}Create blocks/pricing-calculator/types.ts:
export interface Product {
id: string;
name: string;
price_cents: number;
tax_rate: number;
}
export interface PriceBreakdown {
subtotal_cents: number;
tax_cents: number;
total_cents: number;
discount_cents?: number;
}Create blocks/pricing-calculator/index.ts:
export { calculate } from './block';
export type { CalculatorInput, CalculatorOutput } from './block';
export type { Product, PriceBreakdown } from './types';Step 4: Install and Run Blocks
Install the CLI:
npm install -g @blocksai/cliSet your API key:
export OPENAI_API_KEY="your-key-here"Run validation:
blocks run pricing.calculatorStep 5: See the Results
If everything is correct, you'll see:
✓ pricing.calculator
✓ schema.io
✓ shape.exports.ts
✓ domain.validation
All blocks passed validation.Step 6: Try Breaking It
Let's see what happens when code violates domain rules. Edit block.ts to use floating point:
// BAD: Using dollars instead of cents
const subtotal = product.price_cents / 100 * quantity;
const tax = subtotal * product.tax_rate;
const total = subtotal + tax;
return {
breakdown: {
subtotal_cents: subtotal, // Wrong! This is dollars
tax_cents: tax,
total_cents: total,
},
};Run validation again:
blocks run pricing.calculatorThe domain validator will flag this:
✗ pricing.calculator
✓ schema.io
✓ shape.exports.ts
✗ domain.validation
DOMAIN_SEMANTIC_ISSUE: Implementation converts price_cents to dollars
before calculation, violating the philosophy "All monetary values
must be in cents to avoid floating point errors". The subtotal, tax,
and total are calculated as floating point dollars but stored in
fields named *_cents.What You Learned
- Domain modeling - Define entities and semantics in
blocks.yml - Philosophy - Guide AI validation with design principles
- Validation pipeline - Schema, shape, and domain validators work together
- Feedback loop - AI catches semantic violations humans might miss