Skip to content

:script — The Gateway

“Explore fast. Ship when ready.”

:script is :core with the training wheels on. It’s designed for the moments when you just want to get something done — explore an idea, prototype a solution, or crunch some data. When you’re ready to ship, one command promotes your script to production-ready :core code.


  • Implicit types — The compiler figures it out
  • Top-level code — No main() wrapper required
  • REPL — Run janus repl and type directly
  • Auto-imports — Common stdlib modules available by default
  • Script arena allocator — No explicit memory management

The $-family is what makes :script the replacement for awk, bash, Ruby, and Python. It’s inspired by awk’s $1, $NF — but with static type safety.

FormMeaning
$_Current pipeline element, whole
$1, $2, …Positional component of the current element
$#Index of the current element in the stream
$NNumber of positional components
$_1, $_2, …Closure arguments by position (multi-arg)
$@Full closure argument tuple

All resolved at compile time. If $5 doesn’t exist on your element type, you get a compile error — not a runtime crash.

Terminal window
janus path/to/script.jans # First run: ~150ms compile + cache
janus path/to/script.jans # Second run: ~5ms (cached!)

Scripts compile to native binaries on first run, then cache for instant subsequent execution. No interpreter overhead. No JIT. Just fast.


ExcludedAvailable In
Not publishable via Hinge:core (after promotion)
No explicit allocator control:core, :service

Promotion is one command:

Terminal window
janus desugar script.jans > script.jan

Perfect for:

  • Learning Janus interactively
  • Prototyping an idea in 10 minutes
  • Data exploration and analysis
  • One-off automation scripts
  • AI agent tasks (short-lived, disposable code)
  • Homework and algorithm competitions

The rule: Use :script to explore. Use :code (:core) to ship.


# Just run this - no main() needed
print("Hello from :script!")

This is the syntax that makes Nexus operators delete their ~/.zshrc:

<<p"access.log">>
|> map($_.fields())
|> filter($5.to_int()? >= 500)
|> group_by($7)
|> map(($_1, $_2.len()))
|> sort_by($2, desc)
|> take(10)
|> for_each(println)

What this does:

  1. Stream lines from access.log
  2. Split each line into fields (whitespace-separated)
  3. Filter to status codes >= 500 (errors)
  4. Group by the 7th field (URL path)
  5. Count items per group
  6. Sort by count descending
  7. Take top 10
  8. Print each

Compare to the shell equivalent:

Terminal window
cat access.log | awk '{print $5, $7}' | grep -v '^[0-4]' | sort | uniq -c | sort -rn | head -10

The Janus version is:

  • Type-checked$5.to_int()? fails at compile time if not a number
  • Provenance tracked — every line knows its source file and line number
  • Fused — compiles to a single loop, zero intermediate arrays
<<p"server.log">>
|> grep(r/ERROR.*connection reset/)
|> map($_.split(":").1)
|> unique()
|> for_each(println)
# Read JSON, filter, transform, output CSV
let data := read_json("users.json")
|> filter($_.age >= 18)
|> map($.name)
|> sort()
for name in data do
println(name)
end

ConcernawkBashRubyPythonJanus :script
Positional $N
Pipeline operator
Type-checked positions
Zero-alloc fusion
Sub-10ms cold start
Static binary output
Promotion to production


Explore fast. Ship with confidence.