# RakA programming language for hackers, OSINT investigators, and systems programmers. Build desktop GUI apps, backend SQL servers, shareable packages, and self-host the compiler. All in Rak.Hex is a first-class type. The bytecode VM runs about 6x faster than the tree-walker. There's a SQL engine written in Rak itself, and a Rak interpreter written in Rak.## What's new in 0.7.2- **DAP debugger server** — `rakc dap <file>` speaks the Debug Adapter Protocol over stdio (Content-Length framing). The VM runs the target on a worker thread while a reader handles requests: `setBreakpoints`/`remove`, `continue`, `next`, `stepIn`, `stepOut`, `stackTrace`, `scopes`/`variables`, `setVariable`, and full `exceptionInfo` — line-granular breakpoint gating via a `last-hit-line` guard. Wire it up from VS Code (the bundled `rak` extension), Neovim (nvim-dap), or any DAP client.- **Stdlib batteries** — everyday data modules on both backends: time & datetime (`time_now`, `time_fmt`, `time_parse`, `time_parts`, `time_add`, `time_diff`, `date_today`), randomness (`rand_seed`, `rand_int`, `rand_float`, `rand_bytes`, `rand_hex`, `rand_choice`, `rand_shuffle`), CSV (`csv_parse`, `csv_stringify`), YAML (`yaml_parse`), and archives (`gzip_compress`, `gzip_decompress`, `zip_list`, `zip_read`, `zip_write`).- **OSINT pack** — WHOIS lookups and parsing (`whois_lookup`/`whois_parse`), certificate-transparency subdomain enumeration (`ct_subdomains`), a hand-rolled **YARA-lite** scanning engine (`yara_scan`: hex wildcards, `nocase`, `at`/`in`, `all-of`/`any-of`/`none-of`, boolean conditions), and Markdown evidence reports (`report_markdown`). Docs: `docs/content/osint.md`, demo: `examples/osint_demo.rak`.- **Language core: `in` operator** — membership checks work on strings (substring/char), arrays, tuples, maps (key lookup), and byte sequences.- **Destructuring `let`** — `let (a, b) = pair`, `let [x, y, z] = list`, `let Point { x, y } = obj`, nested and `let mut` forms; arity mismatches raise a catchable error.- **Slice and negative indexing** — `a[1..3]`, `a[..2]`, `a[3..]`, `a[-2..]` slices, `a[-1]` reads and `a[-1] = v` writes from the end, with out-of-bounds raises on both backends.- **The VM caught up.** `rakc vm` now runs what the interpreter runs: `try`/`catch` and `expr?` (structured errors, LIFO defers before the handler), method dispatch on structs/enums (`obj.method(...)` via `impl` blocks), struct literals and enum constructors, and the full pattern language in `match` — struct patterns (`Point { x, y }`), enum variants, binary bytes patterns, or-patterns, ranges, `Some`/`None`/`Ok`/`Err`, and guards.- **Operator overloading** — `impl Add/Sub/Mul/Div/Rem/Eq/Compare/Neg for T` with `fn add(self, o)`-style methods, dispatched on both backends before the built-in arithmetic (`a + b`, `a == b`, `a < b`, `-a` on your types).- **Assignment on the VM** — `arr[i] = v`, `map[k] = v`, `s.field = v`, `x += 1`, and multi-assign `a, b = x, y` (copy-on-write, mutability rules enforced).- **Iterator builtins** — `zip`, `enumerate`, `skip`, `fold`, `reduce`, `any`, `all`, `flat_map`, `take_while`, plus `keys`/`values`/`has`/`get`, on both backends.- **`for (k, v) in map`** and indexed `for (i, x) in arr` work on the VM (`Op::IterItems` materializes any iterable; maps always yield pairs).- **`if let` / `while let` / `do { } while` / labeled `break`/`continue`** (`'outer: for ... { break 'outer }`) run on the VM.- **binstruct bitfields** — `u4`-style non-byte-aligned fields, packed LSB-first and round-tripped through `decode`/`encode` on both backends.- **`rakc fmt`** — AST-based formatter (`--write`, `--check` for CI).- **`rakc lint`** — advisory checks (unused vars, shadowing, unreachable code, missing `pub fn` return types, duplicate imports; `--deny` for CI).## InstallThe custom installer is an interactive TUI wizard that installs `rakc`, `rakpkg`, and the Rak IDE, edits PATH, sets `RAK_PATH`, creates shortcuts + `.rak` associations, and installs man pages + shell completions. It runs in net-install (downloads the latest release) or offline-bundle mode, and supports `--uninstall` / `--list` / `--yes` for scripting.**Linux:**```bashcurl -fsSL https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.sh | bash# non-interactive:curl -fsSL https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.sh | bash -s -- --yes --install rakc,rakpkg,ide --scope user```**Windows (PowerShell):**```powershelliwr -useb https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.ps1 | iex```Or download the setup binary directly from the [latest release](https://github.com/Louiml/Rak/releases/latest) (`rak-setup-linux-x86_64` or `rak-setup-windows-x86_64.exe`) and run it.Menu items: `rakc → bin + PATH`, `rakpkg → bin + PATH`, `IDE → portable dir / system location`, `Set RAK_PATH`, `Shortcuts + .rak association`, `Man pages + shell completions`. Install scope: `user` (default, no privileges) or `system`. A `~/.rak/manifest.json` records every action for clean uninstall/upgrade.The Tauri installers (NSIS/MSI on Windows, `.deb`/AppImage on Linux) remain on the release page for IDE-only users who want the OS-native installer.## Quick start```rakdump "Hello, World"``````rakscan "127.0.0.1" { range: [0x0016, 0x0050]} { if open { dump fmt("Port 0x{:04X}", port) }}```## What you getThe language started as an OSINT scripting tool. It grew into something bigger.**Forensic Structs & evidence provenance.** Declare a binary wire format once with `binstruct` and get both a decoder and an encoder for free (round-trip). Every decoded value is wrapped in an `evidence<T>` provenance tag carrying where/when/how it was collected, so `report(...)` emits a chain-of-custody-cited findings report. No other language bakes provenance into the value model — this only makes sense in a hex-first, OSINT-first language.**Bytecode VM.** `rakc vm` runs bytecode. Benchmarks show about 6x speedup over the tree-walking interpreter. Run `rakc bench file.rak` to see both.**Data pipelines.** A `|>` pipeline operator, regex literals (`/\d+/g`) with method syntax, and binary pattern matching over byte slices — built for OSINT log and PCAP triage.**Type system.** Signed and unsigned ints (i8 through u64), floats (f32, f64),typed literals like `42i32` and `3.14f64`, a first-class `char`, base literals(`0b1010`/`0o755`/`0xFF`), tuples, Result/Option, modules, closures with lexicalscoping, generics, traits with method dispatch, pattern matching (includingbinary byte-pattern matching, plus user enum variants), and string interpolationwith `f"hello {name}"`. A static type checker behind `rakc check` catches badannotations and non-exhaustive matches before you run anything.**Concurrency.** `spawn` launches a thread, `thread_join` waits for it, `channel()` gives you a sender/receiver pair. TCP networking built in with `net_listen`, `net_accept`, `tcp_read`, `tcp_write`. Async I/O via a Tokio runtime: `async fn`/`await`, `http_get_async`, `tcp_probe`.**SQL server in Rak.** A full SQL engine, lexer through executor, written in the language itself. It serves queries over TCP. See `examples/sql_server.rak`.**Self-hosting.** `examples/self_host.rak` is a Rak interpreter written in Rak. It lexes, parses, and evaluates real Rak source code.**Error handling.** `try`/`catch`/`raise`, the `?` operator, Result and Option types. Lexer and parser errors report line and column. `rakc check file.rak` prints diagnostics in the format IDEs expect.**Lexical closures.** Free variables resolve at the definition site, not the call site. Recursive closures like `let f = fn(n) { if n < 2 { return n } return f(n-1) + f(n-2) }` just work.**Real JSON.** `json_parse` returns native arrays, maps, ints, floats, bools, nil. `json_stringify` serializes back to a string. No more hand-rolling JSON in your SQL server.**Build standalone executables.** `rakc build file.rak` produces a self-contained binary with the source embedded. On Windows it's a `.exe`. On Linux it gets `chmod 755`. No Rak installation needed on the target machine.**GUI windows (incomplete).** With `--features gui`, Rak scripts can open a native desktop window rendering HTML, CSS, and JS via WebView2 on Windows. Treat it as a display-only preview: `gui_update`/`gui_title`/`gui_close` do not affect the window yet, JavaScript cannot call back into Rak, closing the window ends the process, and Linux does not work. See [GUI windows](#gui-windows).**Package manager.** `rakpkg` is a CLI for Git-based shareable Rak packages. Initialize, add dependencies from GitHub repos, install, run, and build. The manifest is a Rak file with `let` bindings.**Foreign Function Interface (FFI).** Call native C functions in `.so`/`.dll`/`.dylib` libraries. Declare bindings with `extern "C" { ... }` (resolved against the platform default C library, or an explicit `from "path"`) or load dynamically with `ffi_load` and `lib.call`. Marshal raw memory with `ffi_alloc`/`ffi_write`/`ffi_read`/`ffi_cstr_to_string`/`ffi_string_to_cstr`/`ffi_free`. Works on both the interpreter and the bytecode VM.```rakextern "C" { fn abs(n: i32) -> i32}dump abs(-42) // 42let libc = ffi_load("libc.so.6") // or "ucrtbase.dll" / "libSystem.dylib"dump libc.call("abs", [-9]) // 9libc.close()let buf = ffi_alloc(4)ffi_write(buf, 0, 0x41)dump ffi_cstr_to_string(buf) // "A"ffi_free(buf)```**Memory-mapped files.** Map huge PCAP / log files into memory and inspect them zero-copy. `mmap_open` maps a file; `mmap_slice` returns a view that keeps the mapping alive and reads directly from the mapped pages. Single-byte indexing, byte search, and line scanning work on both the interpreter and the bytecode VM; range slicing and binary pattern matching over slices work on the interpreter.```raklet m = mmap_open("trace.pcap", "r")dump mmap_size(m)let hdr = mmap_slice(m, 0, 8)dump hdr[0] // first byte (zero-copy)dump mmap_find(m, "\xff\xd8\xff") // byte search -> offsetfor (off, len) in mmap_lines_off(m, "\n") { dump string(mmap_slice(m, off, len))}```**Async event loop.** `async fn`, `await`, and Tokio-backed async I/O. `http_get_async` / `tcp_probe` / `tcp_connect_async` run on a lazily-started multi-thread Tokio runtime and return a `Future`; `await` blocks until it resolves. Works on both the interpreter (deferred `async fn` bodies) and the bytecode VM (`Op::Await`).```rakasync fn probe(host, port) { let open = await tcp_probe(host, port, 200) return open}dump await probe("127.0.0.1", 80)let body = await http_get_async("https://example.com")dump string(body)```**Raw sockets & packet forging.** Build IPv4/TCP/UDP headers with correct ones-complement checksums and send them on a raw socket. The packet builders are pure computation and run anywhere; `net_raw_send`/`recv` need `CAP_NET_RAW`/Administrator (unix) and return a `Result`.```raklet pkt = net_raw_tcp_syn("10.0.0.5", "10.0.0.10", 12345, 80)dump len(pkt) // 40 bytesdump pkt[0] // 0x45 (IPv4)dump pkt[33] // 0x02 (SYN flag)dump net_raw_send(pkt) // Ok(40) on a privileged unix box, Err(...) otherwise```**Protocol parsers (DNS / TLS / PCAP).** Hand-rolled DNS wire-format builder/parser + UDP query (no external DNS crate — works air-gapped). TLS ClientHello SNI extraction and DER cert-chain parsing via `x509-parser`. PCAP offline capture behind the `pcap` cargo feature (libpcap/Npcap). All return `Result`s so they degrade gracefully offline / without the feature.```rakdump dns_query("example.com", "A") // Ok({answers: [{name, type, ttl, rdata}, ...], truncated})let q = dns_build("example.com", "A") // raw query bytes (offline)let info = tls_parse_client_hello(bytes) // {sni, ciphers}let certs = tls_parse_cert_chain(der) // [{subject, issuer}, ...]dump pcap_open("capture.pcap") // Ok(<pcap>) or Err(...)```**Compile-time macros.** `macro name($params) { body }` defines an AST-expanding template; `name!(args)` splices the argument expressions into the body's `$param` placeholders before evaluation. Expanded in the frontend, so both backends see the expanded code. `const NAME = expr` binds a compile-time constant.```rakmacro add1(x: expr) { $x + 1 }dump add1!(41) // 42macro pair(a: expr, b: expr) { [$a, $b] }dump pair!(1, 2) // [1, 2]const MAX_LEN = 256dump MAX_LEN```## Forensic Structs & evidence provenanceA declarative wire-format DSL (`binstruct`) plus a provenance-typed value(`evidence<T>`) — the OSINT differentiator. Declare a binary layout once andget both a **decoder** and an **encoder** for free (round-trip); every decodedvalue is wrapped in an evidence tag carrying where/when/how it was collected, so`report(...)` emits a chain-of-custody-cited findings report. No other languagebakes provenance into the value model — this only makes sense in a hex-first,OSINT-first language.```rakbinstruct DnsHeader { id: u16be flags: u16be qdcount: u16be ancount: u16be nscount: u16be arcount: u16be}let q = dns_build("example.com", "A")let h = DnsHeader.decode(q) // -> evidence<struct> with provenancedump h.id // 0x1234dump h.qdcount // 1let back = DnsHeader.encode(h) // round-trip back to bytes```Field types: `u8`/`u16`/`u32`/`u64` and signed `i8`..`i64`, each with an optional`be`/`le` endianness suffix (default big-endian); `bytes(n)` for a fixed run ofraw bytes; `rest` for the trailing remainder; and a nested binstruct name for a`Ref` field. Works on both the interpreter and the bytecode VM (compile-timecodegen to per-struct native-fn globals — no new VM opcodes).Evidence provenance:```raklet ip = evidence<string> from "93.184.216.34" // root taglet answers = cite(dns_query("example.com", "A"), "dns_query", "example.com")dump report(ip, answers) // numbered assertions + cited sources (tool/target/ts)dump provenance(ip) // {tool, target, ts, raw_offset, raw_len, parent}dump strip_evidence(ip) // 93.184.216.34```- `evidence<T> from expr` — wrap a value in a root provenance tag.- `cite(value, tool?, target?)` — wrap a value, chaining `parent` to any existing evidence so provenance merges transitively.- `report(evidence, ...)` — render a Markdown-style report with numbered, source-cited assertions (the chain-of-custody output an investigator needs).- `provenance(value)` — the provenance chain as a map.- `strip_evidence(value)` — drop the provenance wrapper, return the inner value.Field access and indexing transparently unwrap evidence, so`evidence<struct>.field` reads through to the inner struct.## Build a standalone executable```bashrakc build examples/hello.rak # produces hello.exe on Windows, hello on Linux./hello # [DUMP] Hello, World```## GUI windowsIncomplete in 8.0.0. Requires `cargo build -p rakc --features gui`.```raklet html = "<h1 style='color:#22c55e;text-align:center;margin-top:40px'>Hello from Rak!</h1>"let win = gui_open("Rak GUI Demo", html, 600, 400)gui_wait()````gui_open` returns a window ID and `gui_wait()` blocks. That is all thatcurrently works. Specifically:- `gui_update`, `gui_title`, `gui_close` are declared but do nothing yet. `gui.rs` stores `HashMap<i64, ()>` and throws away the `Window` and `WebView` handles, so there is nothing to update.- `gui_callback` and `window.rak_call(fn, args)` do not work. The IPC handler receives the message and discards it, so JavaScript cannot call into Rak yet.- Closing the window ends the process, because tao's `run` calls `process::exit` when the last window closes. `gui_wait()` does not return and code after it is unreachable.- Linux does not work: `gui_open` builds the event loop on a spawned thread, which trips tao's main-thread assertion.- The VM has no GUI natives; use `rakc run`.Windows only, display only. The rewrite that fixes all of the above is trackedin `docs/V8-ROADMAP.md`.## Package manager```bashrakpkg init mylib # creates package.rak + lib.rakrakpkg add user/repo # git clone into .rak/packages/rakpkg install # install all deps from package.rakrakpkg run # run the entry point via rakc runrakpkg build # build to standalone executable via rakc buildrakpkg list # list installed packagesrakpkg remove mylib # remove a package```The manifest is a Rak file:```raklet name = "mylib"let version = "0.1.0"let deps = { net: "user/rak-net", crypto: "user/rak-crypto" }let entry = "lib.rak"```Import installed packages by file path or by name (Python-style). See theImports & exports section below for the full syntax.```rakuse "./packages/mylib/lib.rak" // file-path (back-compat)import mylib // name -> searches dir, ./packages/, RAK_PATH```## Imports & exportsRak has a Python-style module system with explicit `pub`/`export`, name-basedresolution, `from ... import`, directory packages, import-once caching, andcircular-import support. Works on both the interpreter and the bytecode VM.```rak// Whole-module import (binds the module; access via m.x)import "./math.rak" // file path -> binds "math"import math // name: searches dir, ./packages/, RAK_PATH for math.rakimport math as m // aliasuse math // back-compat: same as import// from-import (binds names directly)from math import addfrom math import add as plus, mul as timesfrom math import * // all exports; local bindings win on clash// Directory packages: `import pkg` runs pkg/init.rak; `import pkg.sub`// runs pkg/init.rak + pkg/sub.rak (interpreter; use `from pkg.sub import x`// on the VM).import pkgimport pkg.sub// Exports — both `pub` and `export` mark an item as exported (let/fn/const/// struct/enum/macro):pub let PI = 3.14export fn add(a, b) { return a + b }pub const MAX = 256// Re-exportspub use math // re-export all of math from this modulepub use {add, mul} from math // re-export named```Module resolution for a name `m`: the importing file's directory, then`./packages/`, then the `RAK_PATH` env var (`;` on Windows, `:` on Unix),trying `m.rak` then `m/init.rak`. Modules are imported once (cached); acircular import returns the partially-initialized module (Python semantics).## SQL server```bashrakc run examples/sql_server.rak # listens on 127.0.0.1:18393rakc run examples/sql_client.rak # CREATE, INSERT, SELECT, UPDATE, DELETE```The engine supports CREATE TABLE, INSERT, SELECT with WHERE and column projection, UPDATE, DELETE, and DROP. Storage is file-backed with a simple line format. The server handles each connection inline, parsing SQL and returning JSON.## Self-hosting```bashrakc run examples/self_host.rak # a Rak interpreter written in Rak```It reads Rak source, lexes it, parses it, and evaluates it. The output of `1 + 2 * 3` is 7. The output of `let x = 5; let y = 7; dump x * y - 1` is 34.## Language syntax### Variables```raklet target = "192.168.1.1"let port = 0x0050let mut counter = 0counter = counter + 1let pi = 3.14f64let n = 42i32```### Functions```rakfn add(a, b) { return a + b}dump add(0x10, 0x20)```### Control flow```rakif port == 0x0050 { dump "HTTP"} else { dump "Other"}for x in [1, 2, 3] { dump x }while counter < 0x0A { counter = counter + 1 }loop { break }```### Hex arithmetic```raklet sig = 0xDEADBEEFlet mask = 0xFF00FF00dump fmt("0x{:08X}", sig & mask)```### Error handling```raklet v = Ok(42)? // unwrap, propagate Errtry { raise "boom"} catch e { dump e}```### String interpolation```raklet name = "Rak"dump f"hello {name}!"```### Tuples and structs```raklet p = (1, 2)dump p.1struct Point { x: int, y: int }let o = Point { x: 1, y: 2 }dump o.x```### Pattern matching```rakmatch 2 { 1 => { dump "one" }, 2 => { dump "two" }, _ => { dump "other" }}```### Pipeline operator`x |> f` desugars to `f(x)`, and `x |> f(a, b)` to `f(x, a, b)`. Chaining isleft-associative, so `data |> parse |> load` is `load(parse(data))`. Works onboth the interpreter and the bytecode VM.```rakfn inc(n) { return n + 1 }fn dbl(n) { return n * 2 }dump 5 |> inc |> dbl // 12dump 3 |> add(10) // 13```### Regex literals`/pattern/flags` with flags `i` (case-insensitive), `m` (multi-line), `s`(dotall), `x` (extended). A `/` after a value is division; a `/` in operandposition starts a regex, so `a / b` and `let r = /\d+/g` both work.```raklet re = /\d+/gdump re.is_match("abc123") // truedump re.find_all("a1 b22 c333") // [1, 22, 333]dump (/\s+/g).replace("a b c", "_") // a_b_c// Free-function form (also works on the VM):dump regex_find_all(/[a-z]+/g, "a1bc2def") // [a, bc, def]```### Binary pattern matchingMatch a `bytes` value against byte literals (hex, int, or char) with atrailing `..` to match the rest. Useful for magic-number sniffing.```rakfn sniff(data: bytes) { match data { [0x89, 'P', 'N', 'G', ..] => { return "png" }, [0xFF, 0xD8, 0xFF, ..] => { return "jpeg" }, ['%', 'P', 'D', 'F', ..] => { return "pdf" }, _ => { return "unknown" }, }}dump sniff(b"\x89PNG\x0d\x0a\x1a\x0a") // png```### Traits (Display, Iterable, Index, IndexMut)The receiver is passed as the first argument of each method. `Display::fmt`drives `dump`, `Iterable::iter` drives `for x in target`, `Index::index` /`IndexMut::set` drive `obj[key]` reads and writes.```rakstruct Point { x: int, y: int }impl Display for Point { fn fmt(self) { return fmt("({}, {})", self.x, self.y) }}dump Point { x: 3, y: 4 } // (3, 4)struct Range { lo: int, hi: int }impl Iterable for Range { fn iter(self) { let out = []; let i = self.lo while i <= self.hi { out = push(out, i); i = i + 1 } return out }}let s = 0for n in Range { lo: 1, hi: 5 } { s = s + n }dump s // 15```### Characters and base literals```raklet c: char = 'a'let hebrew: char = 'א'let alpha = '\u{03B1}' // αlet bin = 0b1010 // 10let oct = 0o755 // 493dump 0xA == 10 // true```### Generic functions```rakfn identity<T>(value: T) -> T { return value }dump identity<int>(42) // 42dump identity<string>("hi") // hidump identity(99) // inferred: 99```### Defer`defer f()` runs in LIFO order when the current function exits. The last oneregistered runs first. Same on the interpreter and the VM.```rakfn work() { defer dump "cleanup-last" defer dump "cleanup-first"}work() // cleanup-first, then cleanup-last```### Tests and type checking```raktest "addition works" { assert add(2, 3) == 5 assert_eq(add(2, 3), 5) expect_error(fn() { raise "boom" })}``````bashrakc test tests/math.rak # PASS/FAIL, exit non-zero on failurerakc check file.rak # type mismatches, non-exhaustive matches```The full design and implementation plan for these plus FFI, memory-mappedfiles, macros, an async event loop, raw sockets, and DNS/TLS/PCAP parsers isin [`docs/rak-features-spec.md`](docs/rak-features-spec.md).## Standard library### TCP networking```raklet listener = net_listen("127.0.0.1:18392")let conn = net_accept(listener)let stream = conn.0tcp_write(stream, "hello\n")dump tcp_read_line(stream)tcp_close(stream)```### Concurrency```raklet h = spawn(fn() { return 42 })dump thread_join(h)let (tx, rx) = channel()chan_send(tx, "hi")dump chan_recv(rx)```### Strings, arrays, and math```rakdump replace("hello", "l", "L") // heLLodump find("hello", "lo") // 3, or -1 if not founddump starts_with("hello", "he") // truedump ends_with("hello", "lo") // truedump slice("hello", 1, 4) // elldump repeat("ab", 3) // abababdump trim_start(" hi") // hidump reverse("abc") // cbadump reverse([1, 2, 3]) // [3, 2, 1]dump sum([1, 2, 3, 4]) // 10dump max(3, 9, 2) // 9dump min(3, 9, 2) // 2dump abs(-5) // 5dump sqrt(16) // 4dump pow(2, 10) // 1024dump clamp(15, 0, 10) // 10```### JSON```raklet j = json_parse("{\"user\": \"admin\", \"id\": 7}")dump j.user // admindump j.id // 7dump json_stringify(j) // {"user":"admin","id":7}```### OSINT (where it started)```rakfor port in scan_ports("127.0.0.1", { range: [0x0016, 0x0050] }) { dump fmt("Open: 0x{:04X}", port)}dump md5("password")dump sha256("secret")dump hex_encode("ABC")dump html_links(html)```### Cryptography (native — no FFI)`hmac_sha256`, AES-256-GCM (`aes_gcm_encrypt` / `aes_gcm_decrypt`), and Ed25519(`ed25519_keypair`, `ed25519_sign`, `ed25519_verify`). All take and return`bytes`/`string` and are available on both the interpreter and the VM.```rakdump hmac_sha256("key", "data")let key = b"\x00\x01...\x1f" // 32 byteslet nonce = b"\x00\x01...\x0b" // 12 byteslet ct = aes_gcm_encrypt(key, nonce, b"payload")dump aes_gcm_decrypt(key, nonce, ct) // b"payload"let pair = ed25519_keypair(seed)let sig = ed25519_sign(pair.1, b"msg")dump ed25519_verify(pair.0, sig, b"msg") // true```### DNS toolkitBeyond `dns_query`/`dns_build`/`dns_parse`, the investigation API:`dns_resolve(host)`, `dns_reverse(ip)` (real PTR, v4 + v6), `dns_records(host)`(all record types), and `dns_walk(domain, prefixes)`.```rakdump dns_resolve("example.com") // all A + AAAA addressesdump dns_reverse("8.8.8.8") // [dns.google]for r in dns_records("example.com") { dump r.type }dump dns_walk("example.com", ["www", "mail", "api"])```### Process API`process_spawn(cmd, args)`, `process_wait(pid)`, `process_stdout(pid)`,`process_stderr(pid)`, `process_kill(pid)`.```raklet pid = process_spawn("cmd", ["/c", "echo", "hi"])process_wait(pid)dump process_stdout(pid)```### HTTP server (pull-based)A minimal HTTP/1.1 server. Requests are queued and read on the main thread, sohandlers can use arbitrary Rak logic (closures, etc.). Works on both backends.```rakhttp_server_start("127.0.0.1", 8080)loop { let req = http_server_poll() // nil when idle; never blocks if req == nil { sleep(10) } else { if req.path == "/users" { http_server_respond(req.id, 200, { "Content-Type": "application/json" }, "{\"ok\":true}") } else { http_server_respond(req.id, 404, {}, "not found") } }}````http_server_start(addr, port)` binds and queues parsed requests (returns thebound port); `http_server_poll()` returns`{id, method, path, query, headers, body}` or `nil`; `http_server_respond(id,status, headers, body)` writes the response; `http_server_stop()` cleans up.String-keyed map literals (`{ "Content-Type": "application/json" }`) are nowsupported for JSON-style maps.### WebSocketRFC 6455 framing + handshake built on the existing TCP stream handle.`ws_connect(url)` performs the client handshake; `ws_handshake(stream)` repliesto a client Upgrade request on a `net_accept` connection; `ws_send(stream, data,mask)` sends a text frame (client→server frames must be masked, servers pass`false`); `ws_recv(stream)` returns `{opcode, payload}` or `nil`; `ws_close(stream)`sends a close frame. Interpreter-only (the VM has no TCP layer).```rak// server: accept + handshake + echolet list = net_listen("127.0.0.1:19001")let (stream, _) = net_accept(list)ws_handshake(stream)loop { let m = ws_recv(stream) if m == nil { break } if m.opcode == 1 { ws_send(stream, m.payload, false) }}// clientlet ws = ws_connect("ws://127.0.0.1:19001/echo")ws_send(ws, "hello", true)dump string(ws_recv(ws).payload) // hello```### Structured logging (machine-readable)`log_level(level)`, `log_init(path?)`, and `log_info` / `log_warn` / `log_error`/ `log_debug`. Each call emits one JSON line (default stdout, or append-onlyfile) — greppable with jq.```raklog_level("debug")log_info("scan_start", { host: "127.0.0.1", ports: [80, 443] })```### Secrets API`secret_get(name)`, `secret_set(name, value)`, `secret_persist(name, value)`(0600 file), `secret_delete(name)`, `secret_ls()`. Resolution: session → envvar → durable store. Never logged.```raksecret_set("API_KEY", "abc123")dump secret_get("API_KEY")```## CLI```bashrakc run <file> Run a Rak script on the interpreterrakc vm <file> Run on the bytecode VMrakc build <file> Build a standalone executablerakc bench <file> Benchmark interpreter vs VMrakc check <file> Static type check; print diagnostics with line/columnrakc test [file] Run test blocks (--filter NAME, --verbose)rakc lex <file> Print tokensrakc parse <file> Print ASTrakc repl Start an interactive REPLrakc lsp Start the language server (stdio)rakc bindgen <h> Generate Rak bindings from a C headerrakc --versionrakpkg init [name] Create a new packagerakpkg add <user/repo> Add a package from GitHubrakpkg install Install all dependenciesrakpkg run Run the entry pointrakpkg build Build to a standalone executablerakpkg list List installed packagesrakpkg remove <name> Remove a package```## Tooling### REPL`rakc repl` starts an interactive session. State persists between lines, so variables and functions stay defined. Unclosed blocks continue on the next line. Commands start with `:`.```rak> let x = 10rak> dump x[DUMP] 10rak> fn add(a, b) { return a + b }rak> dump add(3, 4)[DUMP] 7rak> :ast 1 + 2rak> :help````:vars` shows defined variables. `:ast <expr>` prints the AST. `:bytecode <expr>` prints the compiled chunk. `:clear` resets state. `:quit` exits.### Language server`rakc lsp` is a stdio language server. It reports parser and lexer diagnostics, offers keyword, type, and builtin completion, shows hover text for identifiers, and jumps to `fn`, `let`, `struct`, and `enum` definitions.Build it with `cargo build --release --features lsp`. The `vscode-rak/` directory has a VS Code extension with a TextMate grammar that pairs with it. For Neovim, point `nvim-lspconfig` at `rakc lsp` for `.rak` files.### C header bindgen`rakc bindgen header.h -o bindings.rak` reads a C header and generates a Rak file with a function per C function (calling `extern_call`) and a struct per C struct. Pointers map to `u64`, `char*` maps to `string`, numeric types map to `i8` through `u64` and `f32`/`f64`.```bashcargo build --release --features bindgenrakc bindgen sdl.h -o sdl.rak```The generated functions call `extern_call`, which returns an error until a Rust wrapper is linked into the standard library. The wrapper is where the actual FFI linking happens.## Platform supportWindows and Linux. On Windows, the GUI uses WebView2 (ships with Edge) and is display-only; Linux GUI does not work in 8.0.0. Note that the feature is per-crate, so it needs `-p rakc --features gui`, not a workspace-wide `--features gui`. `rakc build` produces `.exe` on Windows and an executable with `chmod 755` on Linux. The IDE ships as NSIS/MSI on Windows and `.deb`/AppImage on Linux via GitHub Actions CI, alongside the custom `rak-setup` installer (net-install + offline bundle) on both.## Project structure```Rak/├── rakc/ Compiler, interpreter, VM, GUI│ └── src/│ ├── lexer.rs Tokenizer (logos)│ ├── parser.rs Recursive descent parser│ ├── ast.rs AST definitions│ ├── interpreter.rs Tree-walking interpreter + stdlib builtins│ ├── bytecode.rs Opcode set and chunk│ ├── compiler.rs AST to bytecode│ ├── vm.rs Stack-based bytecode VM│ ├── gui.rs WebView2/WebKitGTK window management│ ├── repl.rs Interactive REPL│ ├── lsp.rs Language server│ └── bindgen.rs C header bindgen├── stdlib/ Rust native stdlib (net, crypto, encoding, recon, web, file, json, log, process, secrets, http_server, websocket)├── rakpkg/ Package manager CLI├── rak-setup/ Custom interactive installer (TUI wizard: net-install + offline)├── dist/ One-liner bootstraps (install.sh / install.ps1), man pages, completions├── ide/ Tauri + Next.js IDE├── .github/workflows/ CI (Linux .deb + AppImage builds)├── examples/│ ├── hello.rak│ ├── quick.rak│ ├── osint_scan.rak│ ├── echo_server.rak TCP echo server│ ├── sql_server.rak SQL server in Rak│ ├── sql_client.rak│ ├── self_host.rak Rak interpreter in Rak│ ├── bench.rak VM benchmark│ ├── gui_demo.rak GUI window demo│ ├── json_demo.rak JSON parse and stringify│ ├── closures.rak Lexical closures and recursion│ ├── vm_features.rak Map, tuple, index, interp, match on the VM│ ├── pipeline.rak Pipeline operator (|>)│ ├── regex.rak Regex literals and matching│ ├── binary_patterns.rak Binary byte-pattern matching│ ├── traits.rak Display/Iterable/Index trait protocols│ ├── ffi.rak FFI: extern bindings + raw memory (interpreter + VM)│ ├── ffi_dynamic.rak FFI dynamic loader (lib.call/lib.sym/lib.close)│ ├── mmap.rak Memory-mapped files: zero-copy slice/search/lines│ ├── async.rak Async event loop: async fn / await / tcp_probe│ ├── net_raw.rak Raw sockets: forge IPv4/TCP/UDP packets│ ├── parsers.rak DNS / TLS / PCAP wire-format parsers│ ├── macros.rak Compile-time macros: macro / name! / const│ ├── import_demo.rak Python-style import / from / export (with mymod/ package)│ ├── forensic_structs.rak binstruct decode/encode round-trip + evidence provenance│ └── stdlib_demo.rak String, array, and math builtins```## Build from source```bashgit clone https://github.com/Louiml/Rak.gitcd Rakcargo build --release # rakc + rakpkgcargo build --release -p rakc --features gui # rakc with GUI supportcd ide && npm install && npx tauri build # IDE```Linux requires `libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`, and `librsvg2-dev`.## Tech stackThe compiler is Rust. Logos handles lexing. The parser is hand-written recursive descent. Two backends: a tree-walking interpreter and a stack-based bytecode VM.The standard library uses `ureq` for HTTP, `scraper` for HTML parsing, `md-5`/`sha1`/`sha2` for hashing, `std::net` for TCP, `std::thread` and `mpsc` for concurrency, `libloading` for FFI, `memmap2` for memory-mapped files, and `tokio` for the async event loop. Real JSON via `serde_json`.The IDE is Tauri v2, Next.js, TypeScript, and Tailwind CSS. It runs Rak scripts as child processes, streams output, and has an integrated terminal.## LicenseApache-2.0## AuthorLouiml (Ryuzaki)