ExamplesFour checked-in examples.
Four checked-in examples.
Walk them in order and you know the language.
Every example compiles today. The repository order matches the authoring tiers: minimal → recommended → workflow → platform.
Tier 1 · minimal
hello-carrier
One file. JWT auth, typed request/response records, four routes. The safest first example for learning the language or validating AI-generated output.
What it teaches
- single-file project shape
- service + auth jwt
- public and protected routes
- typed input & response records
- built-in auth helpers
Routes to try
- POST /auth/register
- POST /auth/login
- GET /me
- GET /health
Commands
carrier check · carrier build · carrier openapi > openapi.jsonexamples/hello-carrier/src/main.carrier
single fileservice App { openapi { title: "Hello Carrier API" version: "0.1.0" } server { host: env("HOST", "0.0.0.0") port: env_int("PORT", 3000) }} auth jwt Auth { issuer: env("JWT_ISSUER", "carrier") audience: env("JWT_AUDIENCE", "carrier-users") secret: env("JWT_SECRET", "local-dev-secret")} type RegisterRequest { email: String @email name: String @length(min: 2, max: 100) password: String @length(min: 8)} type AuthTokens { access_token: String refresh_token: String } route POST "/auth/register" public -> AuthTokens { input: RegisterRequest handler { let user = auth.register( email: input.email, name: input.name, password: input.password ) return auth.issue_tokens(user.id) }} route GET "/me" protect Auth -> MeResponse { handler { return auth.current_user() }}Tier 2 · recommended production shape
inventory-control
Multi-file layout with numeric prefixes for compile order. Thin routes, business writes in actions, role-only policies, idempotent operational routes.
model · crud · policy
src/inventory/00_models.carrier
role-only policyenum InventoryStatus { active archived } policy InventoryItem { write: roles [operator] deleted: roles [operator]} model InventoryItem { id: UUID sku: String @length(min: 3, max: 80) name: String @length(min: 3, max: 120) warehouse: String available_units: Int @range(min: 0, max: 1000000) safety_stock: Int @range(min: 0, max: 1000000) status: InventoryStatus = active deleted_at: Time? created_at: Time updated_at: Time}action · transaction
src/inventory/20_actions.carrier
cycle-count lockaction lock_item_for_cycle_count(id: UUID) -> InventoryItem { let actor = auth.current_user() transaction { let item = InventoryItem.get_for_update(id: id, scope: "all") logs.warn("cycle count lock", { action_name: "lock_item_for_cycle_count" actor_id: actor.id item_id: item.id sku: item.sku }) } return InventoryItem.get(id: id, scope: "all")}What it teaches
- multi-file layout (00_models, 10_types, 20_actions, 30_routes)
- enum, model, type, crud, fn, action, custom route
- thin routes delegating to actions
- transaction-safe row locking
- idempotent operational routes
- policy declarations → manifest + generated RLS
- structured logs, loops, array & JSON helpers
Routes to try
- generated CRUD at /inventory/items
- GET /inventory/items/search
- POST /inventory/items/{id}/cycle-count-lock
- GET /inventory/summary/{warehouse}
Tier 3 · workflow & concurrency
booking-service
Scheduling logic with tenant-aware policy, optimistic @version, jobs, events, and schedules. The workflow counterpart to the flagship example.
tenant_field · @version
src/00_models/slots.carrier
AppointmentSlotpolicy AppointmentSlot { tenant_field: org_id read: roles [viewer, scheduler] write: roles [scheduler] deleted: roles [scheduler]} model AppointmentSlot { id: UUID org_id: String @index clinician_name: String @length(min: 3, max: 120) starts_at: Time status: SlotStatus = open version: Int @version deleted_at: Time? created_at: Time updated_at: Time}job · event · schedule
src/15_async/jobs.carrier
cron → enqueueevent SlotReminderQueued { slot_id: UUID trigger: String} job send_slot_reminder(payload: Json) -> Void { logs.info("slot reminder job", { job_name: "send_slot_reminder", payload: payload }) audit.record("send_slot_reminder", "AppointmentSlot", "scheduled", payload)} schedule "*/15 * * * *" run send_slot_reminder route POST "/slots/{id}/notify" protect StaffAuth roles [scheduler] idempotent -> Json{ params { id: UUID } handler { let job_id = jobs.enqueue("send_slot_reminder", { slot_id: params.id }, delay_seconds: 5) emit SlotReminderQueued { slot_id: params.id, trigger: "manual" } return { job_id: job_id } }}What it teaches
- tenant-aware models and policies
- optimistic @version
- transaction blocks with row locking
- idempotent write routes
- actions for lock/review flows
- jobs, events, schedules
- generated count_by_* / exists_by_* helpers
Routes to try
- generated CRUD at /slots and /bookings
- GET /slots/search
- POST /slots/{id}/lock
- POST /slots/{id}/notify
- GET /bookings/slot/{slot_id}/exists
Flagship · api/
doctor-directory
The runtime/platform showcase. Public paginated search with cache + events, admin reporting via raw SQL and DB functions, typed external client, and an idempotent admin lock route.
search · cache · emit
api/src/main.carrier
public searchroute GET "/search/doctors" public -> DoctorListResponse { query { q: String? specialty: String? city: String? country: String? page: Int = 1 per_page: Int = 20 sort: String = "rating" direction: String = "desc" scope: String = "active" } handler { let key = "doctor-search:" + json.stringify({ q: query.q, city: query.city, page: query.page }) if cache.exists(key) { return cache.get_as("DoctorListResponse", key) } let result = Doctor.search( q: query.q, city: query.city, page: query.page, per_page: query.per_page, sort: query.sort, direction: query.direction, scope: query.scope ) cache.set(key, result, ttl_seconds: 120) emit DoctorSearchCached { cache_key: key, scope: query.scope } return result }}sql.list_as
api/src/main.carrier
typed report rows/// Admin reporting endpoint using raw SQL mapped into a typed result listroute GET "/reports/doctors/by-city" protect AdminAuth roles [admin] -> DoctorCityReportRow[]{ handler { return sql.list_as( "DoctorCityReportRow", "select city, count(*)::bigint as total
from doctors
where deleted_at is null
group by city
order by total desc, city asc" ) }}client · typed JSON
api/src/main.carrier
external integrationclient WeatherApi { base_url: env("WEATHER_API_URL", "https://api.example.com") header "x-api-key": env("WEATHER_API_KEY", "") timeout_ms: 3000} type WeatherResponse { city: String temperature_c: Float condition: String} route GET "/weather/{city}" public -> WeatherResponse { handler { return WeatherApi.get("/forecast", query: { city: params.city }) }}What it teaches
- Postgres-backed model + CRUD
- paginated list & search with projection types
- soft delete + restore with explicit scopes
- role-aware auth and policy/RLS generation
- action + transaction with row locking
- route-level idempotency
- cache + Redis, typed cache reads
- jobs · schedules · events · audit records
- raw SQL and DB function helpers
- typed external JSON client
Routes to try
- GET /doctors · /doctors/{id}
- GET /search/doctors
- POST /admin/doctors/{id}/lock
- GET /reports/doctors/by-city
- GET /reports/normalize-city/{city}
- POST /admin/jobs/metrics
- GET /weather/{city}
- /health · /ready · /openapi.json · /docs