Skip to content

v2026.4.8 — Phase Sigils and the :script Profile

v2026.4.8 — Phase Sigils and the :script Profile

Section titled “v2026.4.8 — Phase Sigils and the :script Profile”

Release date: 2026-04-22 Profiles affected: :core, :service, :script (new) Status: Standard release (6-month support)

This release codifies a language-level clarification that has been developing across the last two weeks and opens a new rung at the bottom of the profile ladder for quick, throwaway-or-promote programs.


Janus now encodes phase directly in its sigils. Every sigil belongs to exactly one world; no sigil crosses worlds.

SigilWorldWhat it doesExamples
§Compile-timeStructural computation, type reflection, code generation§size_of(T), §type_info(T), §{ ... }
$ExtractionRuntime pattern capture (regex, PEG, positional scripting)$1, $2, $*
@MetadataFFI bindings, attributes, capability declarations@ffi(path: ..., lang: .c), @requires(...)

What changes for existing code:

  • Compile-time builtins migrate from $ to §. $size_of is deprecated with warning W5001 in favor of §size_of. Same for $align_of, $offset_of, $is_integral, $is_float, and similar.
  • The $ sigil is now exclusively reserved for extraction — runtime pattern capture and the :script profile positional system.
  • @ is declaration-time only. let x = @ffi(...) was never valid and is now explicitly rejected; @ffi(...) attaches to an extern func declaration, nothing else.

Why this matters: The old convention overloaded $ for two unrelated phases — compile-time introspection and runtime extraction. That ambiguity meant readers had to infer which world a $name lived in from context. Splitting the worlds into three sigils with one purpose each makes every expression self-identifying about when it runs.


A new profile sits at the bottom of the ladder, below :core:

:sovereign → bare-metal
:compute → SIMD, tensors, device offload
:cluster → actors, supervision, distribution
:service → daemons, networking, structured concurrency
:core → deterministic micro-systems
:script → interactive scripting (NEW)

:script is :core with three additions and zero subtractions:

  1. Implicit defaults — entry point, allocator, capability set, common imports are all inferred.
  2. A bounded sugar surface — top-level statements, $-family positional arguments ($1, $2, $*), ergonomics that desugar mechanically into legal :core.
  3. AOT-cached executionjanus path/to/file.jans feels instant via content-addressed cache. No interpreter, no JIT, no second semantics.

The Script Law: Every :script program is a syntactically valid :core program after janus desugar. The transformation is purely additive. Promotion from :script to :core never requires a rewrite.

What :script is deliberately NOT:

  • Not dynamically typed
  • No meta.eval("code") — reflection is typed-AST only
  • No hot reload
  • No second error system (!T propagation remains the only mechanism)
  • No second concurrency primitive (nurseries remain the only concurrency mechanism)
  • Cannot be published through Hinge — :script artifacts are local-only

Status: Rough around the edges, but working. Suitable for throwaway scripts, one-off tooling, and quick prototypes that may later promote to :core.


Janus/.agents/architecture/LANGUAGE-REFERENCE.md is the single-source doctrine for writing Janus code — for humans and AI agents alike. It covers :core and :service completely, and :script as draft.

Two laws now sit at the foundation of the syntax:

Law 1do...end for control flow (imperative, vertical):

if cond do ... end
while cond do ... end
for iter do |x| ... end
func name() do ... end
test "name" do ... end

Law 2{ } for data structures (declarative, containers):

struct { field: type }
enum { Variant }
match expr { pattern => value }
extern struct { field: type }

These two laws are non-negotiable. No exceptions. Every syntactic question in Janus answers itself once you ask: is this control flow, or is this a container?


  • Doc comments use bare keys, not sigils: param:, returns:, error:, capability:, since:, see:, deprecated:, safety:, complexity:. No @ prefix — @ is reserved for metadata declarations, and documentation is not metadata.
  • discard keyword for explicit value discarding at statement level — replaces Zig’s _ = expr. Clear intent: “I am intentionally ignoring this result.”
  • test is a reserved keyword. test "name" do ... end is the only valid use. Naming a function, variable, or type test is a parse error.

  • Compile-time builtins using $ prefix ($size_of etc.) will emit warning W5001. Migrate to §size_of at your convenience — warnings, not errors.
  • Existing :core and :service code should compile unchanged (modulo the $§ deprecation).
  • Files using test as an identifier need renaming. The parser will flag these clearly.

Binary version: 2026.4.8 Git hash: 84133fa Built on: 2026-04-22