Skip to content

Quick Start

Welcome to Janus :core — the foundational profile that teaches systems programming with radical honesty. No magic, no hidden costs, just pure computational thinking.

Terminal window
# Clone the compiler
git clone https://git.sovereign-society.org/janus/janus-lang.git
cd janus-lang
# Build (requires Zig 0.16.x)
zig build
# Run your first program
./zig-out/bin/janus run examples/hello.jan

Create hello.jan:

func main() do
println("Hello, Monastery!")
end

Run it:

Terminal window
janus run hello.jan

What you learned:

  • func declares a function
  • main() is the entry point
  • println() prints to stdout (built-in)
func main() do
// Immutable binding (preferred)
let x = 42
let pi = 3.14159
let is_learning = true
// Mutable binding (when needed)
var count = 0
count = count + 1
println("Count: ")
print_int(count)
end

Types in :core:

TypeDescription
i32, i64Signed integers
f6464-bit floating point
boolBoolean (true / false)
voidNo return value
func check_sign(x: i32) do
if x > 0 do
println("Positive")
else if x < 0 do
println("Negative")
else
println("Zero")
end
end
func count_to_ten() do
for i in 0..10 do
print_int(i)
end
end
func describe_number(n: i32) do
match n {
0 => println("zero"),
1 => println("one"),
2 => println("two"),
_ => println("something else"),
}
end

::: tip SPEC-017 Law 2 match, enum, struct use { }. Control flow (func, if, for, while) uses do..end. This is law. :::

// Function with return value
func add(a: i32, b: i32) -> i32 do
return a + b
end
// Recursive function
func factorial(n: i32) -> i32 do
if n <= 1 do return 1 end
return n * factorial(n - 1)
end

All function signatures MUST have explicit types.

Janus uses Zig-style error unions — errors as values, not exceptions:

func divide(a: i64, b: i64) !i64 do
if b == 0 do
fail DivisionByZero
end
return a / b
end
func main() do
let result = divide(10, 0) catch |err| do
println("Error: division by zero")
0
end
print_int(result)
end

Keywords:

  • !T — error union return type
  • fail — return an error
  • catch — handle an error
  • try / ? — propagate an error

Janus can directly use the entire Zig standard library:

use zig "std/ArrayList"
use zig "std/heap"
func main() do
var allocator = zig.heap.page_allocator
var list = zig.ArrayList(i32).init(allocator)
defer list.deinit()
list.append(10) catch |_| do end
list.append(20) catch |_| do end
list.append(30) catch |_| do end
var sum: i32 = 0
for list.items |item| do
sum = sum + item
end
print_int(sum) // 60
end

What you get: ArrayList, HashMap, File I/O, JSON, Crypto, Networking — everything Zig provides.

In :core, memory is explicit:

use zig "std/ArrayList"
func create_list() do
var list = zig.ArrayList(i32).init(allocator)
defer list.deinit() // Automatic cleanup at scope exit
list.append(42) catch |_| do end
end

Golden rules:

  1. Every init needs a deinit
  2. Use defer for automatic cleanup
  3. No garbage collection, no magic

The :core profile intentionally excludes:

FeatureAvailable In
Concurrency (spawn, channels):service
Async/Await:service
Actors, supervision trees:cluster
GPU/NPU kernels:compute
Raw pointers, unsafe:sovereign

Why? To teach fundamentals without overwhelming complexity.

  • [Profiles System]/learn/profiles/ — Understand the capability ladder
  • [Why Janus?]/learn/introduction/ — The philosophy and design

“The Monastery teaches fundamentals. Master :core, understand all of Janus.”