Give your model this link
faberlang.dev- Version
- 1.15.1
- Platforms
- macOS arm64 · Linux x64
- License
- MIT OR Apache-2.0
A statically typed language for coding agents and human authors · MIT OR Apache-2.0
Faber Romanus has a clear mechanical grammar, explicit static and generic types, and math-oriented operators. The same program renders in eight reader pack surfaces, and compiles to Rust, TypeScript, Go, Swift and more — so a library you write once can go into the project you already have.
Your model reads that file, downloads the current release for
your machine, verifies its checksum, installs the faber command, and runs
faber check on a hello program. It all happens on your machine.
The compiler front end, runner, standard library, and grammar are open source under MIT OR Apache-2.0. The official release also carries code generators that are not in the public source. Faber is experimental through version 1.
faber convert --to en — English reader surface — the base spelling for everyday sourceclass Span {
let f64 low
let f64 high
fn contains(f64 x) → bool {
return self.low ≤ x and x ≤ self.high
}
fn center() → f64 {
return (self.low + self.high) ÷ 2.0
}
}
fn choose<T>(bool first, T a, T b) → T {
return first ✓ a ✗ b
}
main {
let Span bytes ← Span { low = 0.0, high = 255.0 }
print bytes.center()
print choose(bytes.contains(300.0), "inside", "outside")
print -7 / 2
}faber convert --to la — Latin — the classical surface the language is named forgenus Span {
sit f64 low
sit f64 high
functio contains(f64 x) → bivalens {
redde ego.low ≤ x et x ≤ ego.high
}
functio center() → f64 {
redde (ego.low + ego.high) ÷ 2.0
}
}
functio choose<T>(bivalens first, T a, T b) → T {
redde first ✓ a ✗ b
}
incipit {
sit Span bytes ← Span { low = 0.0, high = 255.0 }
nota bytes.center()
nota choose(bytes.contains(300.0), "inside", "outside")
nota -7 / 2
}faber convert --to th-TH — Thai — spaceless scriptชนิด Span {
กำหนด f64 low
กำหนด f64 high
ฟังก์ชัน contains(f64 x) → ตรรกะ {
คืน ตัวฉัน.low ≤ x และ x ≤ ตัวฉัน.high
}
ฟังก์ชัน center() → f64 {
คืน (ตัวฉัน.low + ตัวฉัน.high) ÷ 2.0
}
}
ฟังก์ชัน choose<T>(ตรรกะ first, T a, T b) → T {
คืน first ✓ a ✗ b
}
เริ่ม {
กำหนด Span bytes ← Span { low = 0.0, high = 255.0 }
บันทึก bytes.center()
บันทึก choose(bytes.contains(300.0), "inside", "outside")
บันทึก -7 / 2
}faber convert --to zh-Hans — Simplified Chinese类 Span {
设 f64 low
设 f64 high
函数 contains(f64 x) → 布尔 {
返回 自身.low ≤ x 且 x ≤ 自身.high
}
函数 center() → f64 {
返回 (自身.low + 自身.high) ÷ 2.0
}
}
函数 choose<T>(布尔 first, T a, T b) → T {
返回 first ✓ a ✗ b
}
入口 {
设 Span bytes ← Span { low = 0.0, high = 255.0 }
显示 bytes.center()
显示 choose(bytes.contains(300.0), "inside", "outside")
显示 -7 / 2
}faber convert --to zh-Hant — Traditional Chinese類型 Span {
設為 f64 low
設為 f64 high
函式 contains(f64 x) → 布林 {
傳回 自身.low ≤ x 且 x ≤ 自身.high
}
函式 center() → f64 {
傳回 (自身.low + 自身.high) ÷ 2.0
}
}
函式 choose<T>(布林 first, T a, T b) → T {
傳回 first ✓ a ✗ b
}
入口 {
設為 Span bytes ← Span { low = 0.0, high = 255.0 }
註記 bytes.center()
註記 choose(bytes.contains(300.0), "inside", "outside")
註記 -7 / 2
}faber convert --to vi — Vietnamesekiểu Span {
đặt f64 low
đặt f64 high
hàm contains(f64 x) → logic {
trả tôi.low ≤ x và x ≤ tôi.high
}
hàm center() → f64 {
trả (tôi.low + tôi.high) ÷ 2.0
}
}
hàm choose<T>(logic first, T a, T b) → T {
trả first ✓ a ✗ b
}
bắt_đầu {
đặt Span bytes ← Span { low = 0.0, high = 255.0 }
ghi_chú bytes.center()
ghi_chú choose(bytes.contains(300.0), "inside", "outside")
ghi_chú -7 / 2
}faber convert --to ar — Arabic — right-to-left, bidi isolatedصنف Span {
ليكن f64 low
ليكن f64 high
دالة contains(f64 x) → منطقي {
أعد ذات.low ≤ x و x ≤ ذات.high
}
دالة center() → f64 {
أعد (ذات.low + ذات.high) ÷ 2.0
}
}
دالة choose<T>(منطقي first, T a, T b) → T {
أعد first ✓ a ✗ b
}
بداية {
ليكن Span bytes ← Span { low = 0.0, high = 255.0 }
اعرض bytes.center()
اعرض choose(bytes.contains(300.0), "inside", "outside")
اعرض -7 / 2
}faber convert --to hi — Hindi — Devanagariवर्ग Span {
बैठा f64 low
बैठा f64 high
फलन contains(f64 x) → तार्किक {
लौटाओ मैं.low ≤ x और x ≤ मैं.high
}
फलन center() → f64 {
लौटाओ (मैं.low + मैं.high) ÷ 2.0
}
}
फलन choose<T>(तार्किक first, T a, T b) → T {
लौटाओ first ✓ a ✗ b
}
आरंभ {
बैठा Span bytes ← Span { low = 0.0, high = 255.0 }
दिखाओ bytes.center()
दिखाओ choose(bytes.contains(300.0), "inside", "outside")
दिखाओ -7 / 2
}$ faber run
127.5
outside
-4
One program, eight readings. Every tab is the compiler’s own rendering
(faber convert), and each one runs. Keywords, types and
diagnostics change; identifiers and string literals do not.
Reader locales
People should not need English to use a model for code, or to read what the model wrote. English is the maintained documentation tree; each reader locale has a mapping page, and source is written the same way: one reader locale per file, sealed against the others, so a Thai file contains Thai keywords and nothing else.
Latin is the pack the language is named for. Reader locales also localize compiler diagnostics. See all languages · How reader locales work
Why Faber
A model writes best against a surface with few surprises. Faber keeps the rules small, regular and explicit, then shows the result in the reader’s language.
284 grammar productions, generated and checked as the parser’s
authority. One construct has one spelling. Arrows mean runtime effects
(← assign, → return, ⇥ error channel);
= and : only state compile-time facts.
Read the grammar
Declarations are type-first: f64 low, never low: f64.
Nullability is written T ∪ none. Generics are written out
(fn choose<T>), and crossing between integer and float is
an explicit ↦, not an accident.
Types and values
Integer / floors, so -7 / 2 is -4; true
division is ÷. Comparisons read as math (≤ ≥ ≠ ≈),
and tensor work has its own operators (· matmul,
⊙ elementwise). When math and hardware convention disagree,
Faber follows the math.
Glyphs and Latin
Diagnostics are coded and explainable. The documentation ships an agent index and focused skill guides at fixed paths, so a model can learn the language from the site itself. /llms.txt
Cross-compile
Faber compiles through one analyzed program to many targets. Write a
library in Faber, emit it in the language your project already uses, and
add it alongside your existing code. This small library, with no
generics and no main, is emitted below exactly as
radix emit produces it, and each panel was checked in its
own toolchain.
@ public
class Span {
let f64 low
let f64 high
fn contains(f64 x) → bool {
return self.low ≤ x and x ≤ self.high
}
fn center() → f64 {
return (self.low + self.high) ÷ 2.0
}
}
radix emit --target rust span.fab — builds as a Cargo package with faber build; uses the small faber runtime crate// … 9 lines of generated header and runtime shim elided …
#[derive(Clone, PartialEq)]
pub struct Span {
pub low: f64,
pub high: f64,
}
impl ::core::fmt::Debug for Span {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "Span {{ low = {}, high = {} }}", faber::display::fractus(*&self.low), faber::display::fractus(*&self.high))
}
}
impl Span {
pub fn contains(&self, p_x: f64) -> bool {
self.low <= p_x && p_x <= self.high
}
pub fn center(&self) -> f64 {
(self.low + self.high) / 2.0
}
}radix emit --target ts span.fab — a source file you add to your project; imports @faber/runtime// … 5 lines of generated header and runtime shim elided …
class Span {
low!: number;
high!: number;
toString(): string {
return "Span { low = " + display.value(this.low, "fractus", { true_: "true", false_: "false", none: "none" }) + ", high = " + display.value(this.high, "fractus", { true_: "true", false_: "false", none: "none" }) + " }";
}
contains(p_x: number): boolean {
return (this.low <= p_x) && (p_x <= this.high);
}
center(): number {
return ((this.low + this.high) / 2);
}
}radix emit --target go span.fab — a source file in package main// Code generated by faber. DO NOT EDIT.
package main
type Span struct {
Low float64
High float64
}
func (self *Span) Contains(p_x float64) bool {
return ((float64(self.Low) <= float64(p_x)) && (float64(p_x) <= float64(self.High)))
}
func (self *Span) Center() float64 {
return float64(((self.Low + self.High) / 2.0))
}radix emit --target swift span.fab — a source file; no runtime dependency// Generated by radix - do not edit
func faberFractusPlain(_ description: String) -> String {
var text = Substring(description)
var sign = ""
if text.hasPrefix("-") {
sign = "-"
text = text.dropFirst()
}
var exponent = 0
if let marker = text.firstIndex(where: { $0 == "e" || $0 == "E" }) {
exponent = Int(text[text.index(after: marker)...]) ?? 0
text = text[..<marker]
}
var whole = Substring(text)
var fraction = Substring("")
if let dot = text.firstIndex(of: ".") {
whole = text[..<dot]
fraction = text[text.index(after: dot)...]
}
let digits = Array(String(whole) + String(fraction))
let point = whole.count + exponent
var shown: String
if point <= 0 {
shown = "0." + String(repeating: "0", count: -point) + String(digits)
} else if point >= digits.count {
shown = String(digits) + String(repeating: "0", count: point - digits.count) + ".0"
} else {
shown = String(digits[..<point]) + "." + String(digits[point...])
}
return sign + shown
}
func faberFractus64(_ value: Double) -> String {
if value.isNaN { return "NaN" }
if value.isInfinite { return value < 0 ? "-inf" : "inf" }
if value.rounded(.towardZero) == value {
let sign = value.sign == .minus ? "-" : ""
let magnitude = value.magnitude
if magnitude < 9.0e18 { return sign + String(UInt64(magnitude)) + ".0" }
var digits = Array(String(magnitude.significandBitPattern | (UInt64(1) << 52)).utf8.reversed().map { $0 - 48 })
for _ in 0..<(Int(magnitude.exponent) - 52) {
var carry: UInt8 = 0
for index in 0..<digits.count {
let doubled = digits[index] * 2 + carry
digits[index] = doubled % 10
carry = doubled / 10
}
if carry > 0 { digits.append(carry) }
}
return sign + String(decoding: digits.reversed().map { $0 + 48 }, as: UTF8.self) + ".0"
}
return faberFractusPlain(value.description)
}
func faberFractus32(_ value: Float) -> String {
if value.isNaN { return "NaN" }
if value.isInfinite { return value < 0 ? "-inf" : "inf" }
return faberFractusPlain(value.description)
}
class Span {
var low: Double
var high: Double
init(low p_low: Double, high p_high: Double) {
self.low = p_low
self.high = p_high
}
func contains(x p_x: Double) -> Bool {
return ((self.low <= p_x) && (p_x <= self.high))
}
func center() -> Double {
return ((self.low + self.high) / 2.0)
}
}
extension Span: CustomStringConvertible {
var description: String { return "Span { low = \(faberFractus64(self.low)), high = \(faberFractus64(self.high)) }" }
}Rust builds as a Cargo package today. TypeScript, Go and Swift give you source files to add to your project; assembling them into installable packages is not built yet. Support is stated target by target: generics and some operators do not lower to every target, and the target matrix records where. Read the target matrix
| Target | Emits | Package | Runs | In practice |
|---|---|---|---|---|
| Source for your existing project | ||||
| Rust | yes | yes | yes | The primary target: a full Cargo package, and runnable through faber. |
| TypeScript | yes | — | — | Source emission; package assembly is not built yet. |
| Go | yes | — | — | Source emission; package assembly is not built yet. |
| Swift | yes | — | — | Source emission; a subset. |
| Python | yes | — | — | Source emission; a limited subset. |
| Haskell | yes | — | — | Source emission; a limited subset. |
| Systems, native and device | ||||
| Native executable | yes | yes | yes | MIR lowered to LLVM, linked for the local host. |
| WebAssembly | yes | — | — | WAT text; binary conversion uses external tools. |
| LLVM IR | yes | yes | yes | Text for LLVM tooling; also the CUDA device route. |
| Metal | yes | yes | yes | Shader source; device execution through the Metal route. |
| WGSL | yes | — | — | WebGPU compute shader source. |
| Portable package images | ||||
| FHIR | yes | yes | yes | A portable analyzed-program package envelope. |
| FMIR | yes | yes | yes | A source-independent package image that faber can run. |
Libraries
The libraries are ordinary Faber source. They show what the language is for, and each one can be read, changed and emitted like your own code. Status is stated plainly.
norma:*.
Gradus
autograd and ML
Automatic differentiation, losses, optimizers and neural-network primitives. Models are pure functions; the backward pass is compiler-generated code.
Triga
graphics and geometry
Scene graph, materials and geometry modeled on three.js shapes, written as a small, readable Faber library.
Tela
early; UI and view protocol
Typed HTML and SVG view values with fail-closed validation and deterministic HTML and CSS output. The static renderer comes first.
Inferentia
in development
A local-first GGUF inference server written in Faber. Today it is a command-line shell; model loading and HTTP serving are the next stages.
Cista
package store
The package manager: install, resolve, inspect and cache Faber packages, independent of the compiler.
triga-budapest
triga:geometriaExample scenes built with Triga.
Grammar
The language is specified as 284 productions in a single EBNF, generated from one source and published in full. It is large enough to be expressive and regular enough to hold in your head or a model’s context. The reference pages are generated from the same source, so they cannot disagree with the parser.
Compute
The same language carries numeric and device work. Tensor operators and
@ kernel kernels lower to WGSL, Metal and CUDA routes, and
Gradus uses them for
autograd. Device execution is explicit and fail-closed: a requested
backend never silently falls back to CPU. It is under active
development; device inference is not shipped.
Doors
For models
Machine surfaces are locale-less and live at the root:
/install.md to install,
/llms.txt for the index,
/agents/index.md for the
learning path, and
/.well-known/agent-skills/
for focused skill guides.