drang
Let your agents conduct the orchestra.
Real parallelism and process orchestration in a scripting language that ships as a single binary.
drang: Dutch/German for drive, urge, momentum.
# map -> pmap and the same work fans out across # a bounded worker pool — no GIL, no pool to wire up [1, 2, 3, 4] |> pmap(|$n| $n * $n) # [1, 4, 9, 16]
# square the evens, then sum them $xs := [1, 2, 3, 4, 5, 6] $xs |> filter(|$x| $x % 2 == 0) |> map(|$x| $x * $x) |> reduce(0, |$a, $b| $a + $b) # 56
# ? propagates failures, // recovers $cfg := read_file("app.json") // "{}" $port := from_json($cfg).port // 8080 say($port) # 8080
# $"..." interpolates; '...' and "..." stay literal $user := "ada" $msgs := 3 say($"hi $user, you have $msgs new") # hi ada, you have 3 new
# shell out, capture stdout, fail loud on error; # a timeout tree-kills the whole job $v := capture(exe(), "--version") say($"running $v") # running drang 0.12.1
# workers under {supervise: true} die with the parent: # the whole tree, on Windows (clean exit, crash, or kill) ["api", "worker", "cron"] |> map(|$svc| start(exe(), "-e", "sleep(30)", {supervise: true})) |> len # 3, all reaped when this script exits
# qr// literals, RE2-backed: no runaway backtracking $line := "a1 b22 c333" match_all($line, qr/[0-9]+/) # [1, 22, 333]
# a durable JSON store — remember a cursor between runs, no DB $s := store("state.store") $n := store_update($s, "runs", 0, |$n| $n + 1) say($"run number $n") # 1, then 2, then 3…
# a local htmx GUI in a clamped app window; ship it as one exe # with: drang build tool.dr --web web --gui fn .tick($req) { "server time: " ~ format_time(now(), "%H:%M:%S") } serve({routes: {"/tick": .tick}, static: "web"})
# validate: the type tokens are the conversion builtins, first-class $cfg := validate(from_json($body), {host: str, "port?": int, tags: [str]})? say($cfg.host) # every mismatch reported with its path, or the value passes through
Why drang
Real parallelism, no GIL
Change map to pmap and the same code fans out across a bounded,
process-wide worker pool — goroutine-backed and without a GIL. Mutable captures are
snapshotted for each callback; explicit handles remain shared coordination points.
Glue built in
run / capture / pipe with timeouts and
process-tree kill, line streaming, channels, and a minimal HTTP client.
One static binary
No runtime, nothing to install, fast startup. Source and payloads are bounded and
validated; format with drang fmt, test with drang test, and ship
atomically with drang build.
Errors are values
Failures are ordinary values: ? propagates, // recovers.
Migration lint flags directly recognizable discarded, boolean, and output Err uses.
Perl's soul, not its warts
One $ sigil, string interpolation and heredocs, qr// regex
literals, and |> pipelines.
Batteries, curated
Modules, frozen immutability, 161 direct builtins, 15 higher-order forms and a 25-function prelude, JSON & CSV, dates, hashing, a persistent store. Broad, not a kitchen sink.
Local GUI cockpits
serve({routes}) runs a token-gated local htmx server in a clamped
browser app window; drang build --web --gui packs tool, assets, and
runtime into one double-clickable exe.
Data you can trust
Modules are private-by-default (export names the API, exports deeply
frozen), and validate checks map shapes at boundaries — every
mismatch reported with its path.
Install
drang is Windows-only
(Windows 11 23H2+ / Server 2025+). Grab the prebuilt .exe from the latest
release, or build from source with Go:
go build -o drang ./cmd/drang