Skip to content
LogoLogo

Getting Started

Start with TypeScript-shaped code, then add Results and requirements

Overview

VibeLang uses a TypeScript-derived frontend. A .vibe file opts into VibeLang semantics; imported .ts and .js files retain their normal behavior.

The language focuses on:

  • expected failures as Result<A, E> values
  • absence as built-in Optional<T> values
  • capability-based dependency injection
  • deterministic compile-time execution
  • opt-in durable and distributed execution

Compiler intrinsics such as comptime(...) and durable(...) are imported functions rather than keywords.

Run the Current Checks

git clone https://github.com/smithersai/vibelang.git
cd vibelang
npm install
npm test

This builds the compatibility package, checks its declarations, runs Node tests, and runs the Go compiler-contract tests. The old regex language demo under prototype/ and poc/src/language is historical and does not define current syntax.

Your First Fallible Function

import { Context } from "vibelang/context"
 
class NotFound extends Error {
  constructor(readonly id: string) {
    super(`User not found: ${id}`)
  }
}
 
abstract class Users extends Context {
  abstract find(id: string): Optional<User>
}
 
function getUser(id: string): Result<User, NotFound> {
  const users = Users.context()
  return users.find(id).toResult(() => new NotFound(id))
}

The ordinary return type tells the whole story:

  • User is the success value.
  • NotFound is the expected Error.
  • Users.context() adds Users to the compiler-inferred requirement channel.
  • Optional<User> models a successful lookup with no value.

Handle or Propagate

Handle both Result variants with match, then use error.match for a known Error union:

const user = getUser("42").match({
  ok: user => user,
  error: error => error.match({
    NotFound: () => User.guest(),
  }),
})

Use .unwrap() when the enclosing function returns a compatible Result:

function displayName(id: string): Result<string, NotFound> {
  const user = getUser(id).unwrap()
  return user.name
}

Inside a Result-returning body, a plain return is lifted to success and a thrown Error is lifted to error. No explicit success/error constructor is needed.

Provide a Capability

import { Layer } from "vibelang/provider"
 
const App = Layer.succeed(Users, new PostgresUsers(databaseUrl))
 
Layer.provide(App, () => {
  console.log(displayName("42").unwrap())
})

Removing the Users provider is intended to be a compile error. Tests can provide an in-memory implementation without changing application code.

Async Results

async function loadUser(
  id: string,
): Promise<Result<User, Timeout | NotFound>> {
  const response = (await HttpClient.context().get(`/users/${id}`)).unwrap()
  return (await response.json(User)).unwrap()
}

await unwraps the Promise but leaves the Result. Authored VibeLang does not use Promise instance .then, .catch, or .finally.

Next Steps