Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14,675 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ScalaScript

CI

Site: scalascript.dev overview · SclJet — a SQLite engine in pure ScalaScript

A language where Markdown is syntax, not decoration.ssc files are executable documents combining YAML front-matter, Markdown prose, and Scala 3 code blocks.

.ssc files support two code-block languages:

Annotation Language Backends
```scalascript ScalaScript dialect — effects, handlers, content helpers, TCO interpreter · JS transpiler · JVM · Rust (native binary; up to R.5 web toolkit) · WebAssembly
```ssc Alias for scalascript interpreter · JS transpiler · JVM · Rust
```scala Scala-3-subset alias — runs through the ScalaScript engine, byte-identical to scalascript today (64-bit Int) interpreter · JS · JVM · Rust
```rust Standard Rust — passthrough verbatim into the emitted Cargo crate Rust

scala fences run in document order alongside scalascript fences. Today a scala fence is not compiled by real Scala 3 / Scala.js — it is parsed and executed by the same ScalaScript engine as a scalascript fence, so its output is byte-identical on every lane (native / interpreter / JS / JVM). In particular Int is 64-bit, per the normative width contract (specs/numeric-widths.md) — the width follows the BACKEND, not the fence tag. Real Scala.js/scalac compilation (which would carry Scala's own 32-bit Int) is a future, separately-widthed capability that is not wired up. The runScalaFences: / run-scala-fences: front-matter key is reserved and currently a no-op (no compiler/interpreter code reads it; scala fences already run by default). Full measurement + rationale: specs/w5-int-width-findings.md.

---
name: hello
version: 1.0.0
---

# Hello World

```scalascript
def greet(name: String): String = s"Hello, $name!"
println(greet("World"))
```
Hello, World!

After installing, every .ssc file is a first-class executable:

$ ssc hello.ssc
Hello, World!

# The shebang line (#!/usr/bin/env ssc) lets you run files directly:
$ chmod +x hello.ssc && ./hello.ssc
Hello, World!

# Watch mode — re-runs on every save:
$ ssc watch hello.ssc

Quick Start

Standard 2.1 runtime requirement: Java 21+. Scala CLI/scalac/javac are not required by plain ssc (or its ssc-standard alias); Scala CLI is an optional tools-tier dependency reached only through explicit ssc-tools commands. Node.js is needed for the JS backend, and sbt for contributor builds.

The standard self-hosted route supports named indented given ... with objects and explicit property/method calls on both its VM and direct-ASM lanes. Ordinary object Name: bodies retain their first and later members with the same owned method/property semantics as explicitly braced objects. Indented extension bodies close at dedent and retain selected-call ownership when imported through another .ssc module. An imported symbolic extension such as parser choice | handles non-primitive values while 6 | 3 remains ordinary integer bitwise OR. Exact top-level summon[TC[T]] resolves a matching named given. Product Mirror.Of[T] / Mirror.ProductOf[T] metadata and custom derives TC evidence are self-hosted on the standard VM/direct-ASM/build-jvm route; anonymous givens, sum Mirrors, and general implicit search remain migration gaps. Parameterless def value: T = ... references evaluate the nullary definition, while explicit def value(): T = ... keeps its required call. List map and flatMap spread portable pair elements into matching two-parameter callbacks. Explicit direct[Option] and direct[List] blocks are compiler-free too: fresh assignments bind, Option short-circuits, and List expansion keeps source order; broader direct inference and monads remain compatibility-only gaps. Named case-class .copy(field = value) is likewise native: labels are preserved independently of call order, omitted fields are retained, and the receiver/overrides evaluate exactly once from left to right. Top-level case object declarations are stable portable nullary values across imports, direct references, equality, and pattern matching. Its built-in math object is also portable on both lanes (Pi, E, abs, sqrt, pow, floor, ceil, and round) without loading the tools tier. Nested constructor patterns fall through to later source arms correctly, so repeated outer case-class tags can be distinguished by inner Some/None.

git clone https://github.com/sergey-scherbina/scalascript
cd scalascript

# Standalone install, once releases are published:
cs install ssc --channel https://releases.scalascript.io/coursier.json

# Contributor checkout only: builds and stages local bin/ launchers.
./install.sh --dev

# Pipe sops-decrypted secrets into a script (${sops:key} references in databases:)
sops -d secrets.enc.yaml | ssc myapp.ssc

# Default, physically slim 2.1 tier: self-hosted frontend + v2 VM / direct ASM
bin/ssc run examples/hello.ssc
bin/ssc run --bytecode examples/hello.ssc
# Descriptive alias with the identical standard classpath
bin/ssc-standard run examples/hello.ssc

# Explicit native provider: adds only the selected provider classpath while
# keeping StandardMain + the self-hosted frontend/VM or direct ASM
bin/ssc-provider pdf run examples/invoice-pdf.ssc
bin/ssc-provider pdf run --bytecode examples/pdf-extract-demo.ssc
RDF4J_URL=http://localhost:8080/rdf4j-server/repositories/kg \
  bin/ssc-provider graph-rdf4j run examples/graph-rdf4j-http-storage.ssc
SWIFT_AGGREGATOR_URL=http://localhost:9000 SWIFT_API_KEY=secret \
  bin/ssc-provider swift run examples/international-bank-rails.ssc

# Roll back through the explicit optional tools/compatibility tier
bin/ssc-tools run --v1 examples/hello.ssc
bin/ssc-tools run --compat-frontend examples/hello.ssc
# Compiler/target-owned documents stay on explicit tools lanes
bin/ssc-tools run --v1 examples/quoted-macro-constfold.ssc
bin/ssc-tools emit-wasm examples/wasm-scalascript.ssc
bin/ssc-tools run-jvm examples/x402-client.ssc
# Plain ssc never delegates; this fails early and names ssc-tools:
bin/ssc run --v1 examples/hello.ssc

# Watch mode — re-run on every file change
bin/ssc-tools watch examples/hello.ssc

# Interactive REPL
bin/ssc-tools repl

# Transpile to JavaScript and run via Node.js
bin/jssc examples/hello.ssc

# Compile to JVM bytecode and run via Scala 3 / scala-cli
bin/sscc examples/hello.ssc

# Build a deterministic self-contained JAR directly through native CoreIR + ASM
bin/ssc build-jvm examples/hello.ssc -o hello.jar
java -jar hello.jar

# Contributor/release check: remove the tools tier and prove the remainder works
tests/e2e/v21-slim-distribution-gate.sh \
  --report target/v21-slim-distribution.tsv

# Also remove java.compiler/jdk.compiler from the resolvable module graph
tests/e2e/v21-jre-module-gate.sh --report target/v21-jre-module.tsv

# Authoritative negative release: no tools/compiler/scalameta files or commands,
# no compiler modules, exhaustive frontend + VM/ASM + providers/server
tests/e2e/v21-negative-toolchain-release-gate.sh \
  --report target/v21-negative-toolchain-release.tsv

# Compile to a native binary via Rust + Cargo (requires `cargo` on PATH;
# see docs/rust-backend.md for the capability surface).
bin/ssc-tools build-rust examples/hello.ssc && ./hello
bin/ssc-tools run-rust   examples/hello.ssc

# Inspect or run the checked ScalaScript 2 CoreIR Swift package (Swift 6+)
bin/ssc-tools emit-swift --target macos -o appcore-swift examples/swift/appcore-money.ssc
bin/ssc-tools run-swift examples/swift/appcore-money.ssc
bin/ssc-tools run-swift examples/swift/appcore-nativeui.ssc # ABI debug CLI; emit also writes the reactive AppleApp sources
bin/ssc-tools build --target macos examples/swift/appcore-nativeui.ssc # real Xcode .app
bin/ssc-tools run --target ios examples/swift/appcore-nativeui.ssc     # build/install/launch Simulator app

# Run on Apache Spark (Spark 4.0.0 / Scala 3.7.1, local[*] by default)
bin/ssc-spark examples/spark-encoder-demo.ssc

# Run all examples
./examples/run-all.sc

# Start HTTP server for the examples browser
bin/http.ssc

Documentation

Full categorized index of all docs: docs/README.md.

Working on this repository

POLICY.md The single source for how work is managed here — claiming, boards, where an entry is recorded, what goes to the coordination room, what a gate has to prove. Rules are numbered (P-3.5) so they can be cited. Read this before your first commit.
AGENTS.md The working brief: build commands, sbt/worktree mechanics, architecture rules. Process rules live in POLICY.md.

Getting started

Project Summary One-page overview — what ScalaScript is, the five backends, and the headline capabilities
User Guide Installation, CLI commands, language basics, HTTP, effects, actors, Apache Spark, WebAssembly, frontend frameworks, cluster, x402 — practical day-to-day reference
Tutorial 1 — Todo API Build a todo API step by step — data model → REST → auth → WebSocket → TLS → MCP
Tutorial 2 — Spark ETL End-to-end Spark pipeline — Dataset[T]@SqlFn UDF → @TempView → Delta Lake
Tutorial 3 — Frontend Toolkit demo Compile + emit + serve a toolkit SPA through React / Vue / Solid / Custom + SSR via ssc serve
Tutorial 4 — Full-stack .ssc SQLite + REST API + reactive runtime/std/ui frontend in one .ssc file — databases:, sql blocks, serve(lower(tree, theme), port)

Language reference

Language Specification Formal grammar, type system, semantics, all language constructs
UniML / YAML 1.2.2 adapter Cross-platform token-as-instruction tree VM with lossless JSON/XML/YAML dialect modules; YAML preserves presentation syntax and exposes explicit Core/JSON/Failsafe plus bounded alias projection
Direct Syntax Do-notation over any monad — direct[M] { x = expr }, .! postfix bind, effect-row unions; explicit Option/List blocks also run on the compiler-free standard 2.1 path
Coroutines & Generators / 2.1 native provider Coroutine primitive underlying one-shot effects and generators; core-free VM/direct-ASM/build-jvm contract
Algebraic Effects spec Typed effect rows — ! operator, multi effect, Rémy-style unification, typed stdlib, Reader[R], NonDet
Error Handling Checked errors via throws[A, E], attemptCatch, HasStackTrace
Metaprogramming / v2 macros inline, derives, compiletime.*; partially implemented restricted quoted macros for ssc link, interpreter ssc run, and the JVM + JS backends, incl. Expr.asValue match compile-time constant folding, with targeted unsupported-body diagnostics; product Mirror.Of[T] and user derived(m: Mirror) typeclasses also run on the compiler-free standard 2.1 path
Markdown Content Introspection Markdown-to-frontend content layer: Markdown/YAML/GFM tables/fenced language blocks lower to std/ui through contentToolkitNode() or explicit contentToolkitBlock(id) / contentToolkitSection(id) selectors, including declarative yaml @ui=toolkit controls, Markdown-authored tables as TableNode, contentData(id) lookup, explicit contentComponent(...) registries for component=<name> / data=<id> metadata, pure-ScalaScript contentBind(value, bindings) resolution for Markdown ${name} placeholders (including compiler-free native VM/ASM and build-jvm), and cross-backend std/content lookup helpers contentCurrentSection(), contentSection(id), contentBlock(id), contentMetadata(path), contentPlainText(value), contentToMarkdown(value), plus direct imported module content namespaces via contentModule(namespace) for interpreter, JS, and JVM targets; .scir and .sscc preserve the current-module DocumentContent snapshot when present; low-level contentView(contentDocument()) remains available
Markdown Content Linked Namespaces Focused contract for reusing Markdown-authored sections, blocks, data, and content: metadata from direct .ssc imports through contentModules() and namespace-scoped lookup helpers; the 2.1 native structural provider carries the same direct-import content through VM, ASM, standard/slim/JRE, and deterministic build-jvm without a host Markdown parser
Markdown Content Native Client Parity Same Markdown-authored toolkit controls render through Swing, JavaFX, and SwiftUI native frontends by normalizing shared std/ui/lower View.Element output into native text fields, checkboxes/toggles, buttons, and signal state
DSL Authoring Parser combinators, multi-pass pipelines, runtime/std/parsing/*

Platform & runtime

Architecture Compiler pipeline, module structure, backend SPI
Target Backends Interpreter · JS transpiler · JVM · Rust (Cargo crate → native binary) — capabilities and tradeoffs
Rust backend guide ssc emit-rust / build-rust / run-rust — compile .ssc to a native binary via Cargo, with mixed ```rust fence blocks
Actors & Distributed Spawn, supervise, cluster over WebSocket
Distributed Wire Protocol Planned: opt-in JSON/MsgPack/CBOR internal wire layer for actors, Dataset/DStream, typed route clients/RPC, object sync, security, compression, and compatibility
Distributed Runtime Planned: canonical local/remote/distributed runtime model for streams, actors, typed async calls, cluster lifecycle, cluster operations, code deployment, and worker bundles
Dataset / MapReduce Dataset[T] — local, parallel, distributed
Apache Spark backend Spark 4 + Scala 3.7.1: Dataset[T], sql blocks, @SqlFn UDFs, Structured Streaming, Delta Lake, Hive catalog, MLlib — see §13 of the User Guide
Frontend Framework SPI React / Vue / Solid / custom frontend backends; design doc has historical planning context
Frontend Toolkit High-level declarative widgets: Forms, Routing, Widgets v2, Table
Cluster Management Bully election, phi-accrual failure detector, federation, Raft, ZooKeeper client
x402 micropayments HTTP 402 protocol, Ethereum + Cardano flows, MCP × x402 paid tools
Bank Rails v1.54 SEPA CT/DD, ACH, Pix, FedNow — BankRailsProvider SPI, mandate lifecycle, async settlement
International Bank Rails v1.55 SWIFT MT103 + pacs.008, SEPA Instant, UK FPS/BACS/CHAPS, India UPI, Japan Zengin, Singapore PayNow
Browser SQL Cross-backend sql fenced blocks (JS / Node / Wasm / JVM)
Electron SQL Current sqlite: behavior in Electron desktop bundles, including the localStorage-backed renderer fallback
Electron Persistence Bridge Main/preload bridge for durable Electron SQLite under app.getPath("userData")
SclJet Pure ScalaScript SQLite engine — no C, no bundled library. Reads and writes real .db files (byte-identical to sqlite3, verified both ways), full SQL with enforced CREATE UNIQUE INDEX, a JDBC façade + jdbc:scljet: driver, crash-safe durable writes, and value-level addressing. Live overview · guide · spec
Secret Resolvers ${env:} · ${file:} · ${sops:} · SecretResolver SPI for Vault / AWS SM / GCP / Doppler / 1Password
MCP Support MCP server tools + resources, MCP client
Rozum / Agent SDK Generic app-owned agent loop over a stateless OpenAI-compatible rozum gateway, with strict tool schemas and in-process tool handlers
Rozum Agent Streaming runAgentStream / collectAgentStream for OpenAI-compatible SSE text/tool-call deltas with ordered AgentEvents
Rozum Agent Endpoint Pool AgentEndpointPool + runAgentPool / streaming pool variants for bounded ordered failover across multiple rozum gateways
Rozum Agent Schema Derivation AgentSchema[A] derives + agentToolFor[A] for typed tool inputs with OpenAI-compatible JSON Schema parameters
Markdown as Syntax How Markdown constructs map to AST nodes
SwiftUI / iOS / macOS V2 checked-CoreIR Swift/AppCore generation with authoritative manifest entrypoints, the standard locale/JsonValue/keyed lower/serve toolkit path, native SwiftUI observation/rendering, persisted/online adapters, lifecycle-safe URLSession fetch/actions/tables, isolated trusted HTML, deterministic verified macOS/iOS Xcode applications, signed device/IPA/Developer-ID/notary/DMG packaging, and explicit TestFlight/App Store uploads
GraalVM native binary ssc native binary via GraalVM native-image; no-JVM distribution; ssc-plugin-host.jar bridge
Native plugin guide Compile a plugin to a native binary — fully JVM-free ssc → plugin

Planned / partial

Blockchain SPI Draft / planned, not fully implemented: pluggable chain abstraction below wallet and x402 support
Electron JVM REST Backend Partially implemented: explicit ssc run --frontend electron --backend jvm-rest, ssc run --target desktop-jvm, plain ssc run for frontend: electron full-stack sources, server-only ssc run --mode server --backend jvm, Electron client-only, and web client preview via ssc run --mode client --frontend react --server-url ... with opt-in --open-browser plus --host/--port preview binding; packaging and runtime-level JVM bind-host support remain planned
Full-stack in-process transport Planned, partially implemented: BackendTransport types, `ssc run --transport http
JVM Desktop Frontend Partially implemented: frontend-swing backend, ServiceLoader registration, ssc run-jvm --frontend swing, static Swing toolkit subset emission, local signal action bridge, Swing fetchAction / dataTable / typed route client backend dispatch in the same JVM process, no-socket full-stack examples, and a swing-plugin skeleton for future interpreter intrinsics; JavaFX/Compose adapters remain planned
Typed route clients Planned, partially implemented: apiClients: / api-clients: front-matter endpoint metadata parses into AST and codegen metadata; when no manual client metadata is present, RouteDeriver synthesizes Api from route(...), mount(...), and routes: declarations, including callable path-param methods such as Api.getApiItemsById("42"); JVM/Swing generates callable in-process client methods, and JS/browser/Electron bundle codegen emits Promise-returning HTTP clients over fetch using --server-url / __sscBackendBaseUrl; awaitClient(...) gives client-side ScalaScript code a small await bridge; generated clients call a stable typed JSON codec facade sourced from backend/typed-data; JVM/Swing typed clients use JsonCodec[T], and JS/browser/Electron typed clients use generated runtime codec metadata for known case-class/enum shapes
Contract validation Planned, not implemented yet: shared OpenAPI/GraphQL validation model for route/resolver signatures, request/response bodies, typed errors/status codes, profiles, overlays/imports, CLI checks, compatibility diffs, and contract tests
Typer real types roadmap Planned, partially implemented foundation: reduce accidental Any in exported symbols/IR and carry structured type evidence through case classes, enums, generics, routes/remotes, OpenAPI/GraphQL schemas, Dataset/Spark mapping, and plugin metadata
Client/server object store Complete: JS/browser/Electron IndexedDb.store[A] typed local client store, JVM/JDBC ObjectStore, generated JVM REST sync routes, Sync.pull/push/sync[A], durable queued Sync.put/remove[A], explicit Sync.conflicts/resolve[A], generated JVM conflict policies (manual / server-wins / client-wins), and Sync.status / Sync.isOnline / Sync.isSyncing UI helpers
Graph storage Planned, partially implemented: graphs: front matter parses into AST/IR; JVM codegen exposes Graph.* over in-memory, embedded TinkerGraph property, and RDF4J memory RDF stores plus Sparql.select over RDF4J; the core-free 2.1 standard provider exposes deterministic process-local Graph.* property/RDF storage on VM/direct ASM/build-jvm. ssc-provider graph-rdf4j adds remote SPARQL query/update without compatibility fallback; Neo4j and JanusGraph/TinkerPop remain separate provider work
Typed data mapping Planned, partially implemented: backend/typed-data owns the shared emitted typed JSON facade for generated route clients plus JsonValue / DecodeError / JsonCodec[A], explicit object helpers, JsonFieldSpec rename/default/key/unknown-field helpers, derives JsonCodec for case classes/sealed ADTs, schema annotations for derived JVM/interpreter product codecs, schemas: front-matter metadata for interpreter typed SQL, initial RowValue / RowFieldSpec / RowCodec[A] support for simple case-class rows and explicit JVM column metadata, initial ObjectValue / ObjectFieldSpec[A] / ObjectCodec[A] support for portable IndexedDB/ObjectStore document shapes, VertexValue / EdgeValue / RdfValue plus VertexCodec[A] / EdgeCodec[A] / RdfCodec[A] for graph/RDF mapping, DatasetCodec[A] for local/MapReduce Dataset element serialization and distributed worker partition payloads, DatasetWire JSON/MsgPack/CBOR envelope + chunk helpers for DatasetWirePartition, std/mapreduce runDistributedWire and runDistributedShuffleWire for direct DatasetWirePartition actor/shuffle payloads, DistributedDataset.encode/decode[A] typed boundary helpers, DistributedDataset.run/runShuffle[A, B] actor-effect wrappers, and SparkSchemaCodec[A] for Spark-like schema metadata using the same field annotations; JS/browser/Electron IndexedDb.store[A] typed local object storage, and JVM/JDBC ObjectStore storage through ObjectCodec[A]; SqlRuntime.query/insert/update[A] use RowCodec[A]; interpreter and JVM codegen expose Db.query/insert/update[A] for typed SQL reads and writes; SparkGen typed readers use SparkSchemaCodec[A] metadata when present and alias external column names back to Scala field names before .as[T]; richer cross-store convergence remains planned
Distributed binary wire protocol Planned, partially implemented: opt-in wire: config with JSON fallback plus MsgPack/CBOR profiles for internal ScalaScript distributed actors, Dataset/DStream, typed route clients/RPC, WebSocket subscriptions, object sync, compression, integrity, and future schema evolution. Implemented pieces include shared WireEnvelope, actor binary WS, typed RPC binary HTTP negotiation, and DatasetWire JSON/MsgPack/CBOR partition envelopes with chunking
Distributed runtime Planned, partially implemented: local / remote / distributed placement vocabulary, named operation registry, code identity, stream bridges, typed actor remote spawn, ! Async remote calls, cluster runner UX, token rotation, rolling upgrades, and cluster-aware deployment. Implemented pieces include stream bridge basics, typed actor refs/remote spawn, ClusterCapability, static SeedResolver, interpreter code identity checks, typed cluster: / registry front-matter metadata, interpreter remoteHandlers: lowering with in-process Remote.function plus HTTP JSON fallback routes, explicit Remote.http[A, B](url) calls, path-based Remote.stub(baseUrl) HTTP stubs, and generated RemoteRpc typed HTTP client metadata for path: remote handlers

Dataset/MapReduce binary wire now reaches actor messages directly: wireFormat = "msgpack" | "cbor" sends DatasetWire envelope bytes for partition, shuffle-bucket, and key-result messages, while JSON keeps the object-message fallback.

What Works

All three backends support scalascript blocks. scala blocks run today through the same ScalaScript engine (a Scala-3 subset), byte-identical to a scalascript block on every lane — Int is 64-bit, per specs/numeric-widths.md. Compilation by real Scala 3 / Scala.js (which would carry Scala's 32-bit Int) is a future, separately-widthed capability, not wired up (see specs/w5-int-width-findings.md).

Core language

Feature Syntax
Values and variables val x = 42, var n = 0
Functions def f(x: Int): Int = x * 2
Lambdas and closures val double = (x: Int) => x * 2
Higher-order functions xs.map(double), xs.filter(_ > 0)
Default parameters def f(x: Int, step: Int = 1), also on class/enum constructors
Case classes case class Point(x: Double, y: Double)
Enums / sealed traits enum Color { case Red; case Green; case Blue }
Recursive ADTs enum Tree { case Leaf(v: Int); case Branch(l: Tree, r: Tree) }
Pattern matching x match { case Some(n) => n; case None => 0 }
For comprehensions for x <- xs if x > 0 yield x * x
While loops while n > 0 do { ... }
Collections List, Map, Option, Set, Vector, Array, LazyList, Seq, IndexedSeq, Iterable — full method dispatch; native List.mkString preserves the requested separator for empty, singleton, and multi-element lists
Real collection semantics The interpreter models true Scala semantics — Array is mutable with reference identity (a(i) = x), LazyList is lazy (#:: defers; infinite streams work), Vector is a distinct indexed type with O(log₃₂ n) access; constructors Seq/Vector/Array/IndexedSeq/Iterable/LazyList(...) + .toSeq/.toVector/.toArray/.toList/.toLazyList conversions
Tuples val t = (1, "hello"); t._1
Bitwise operators a & b, a | b, a ^ b, a << n, a >> n, a >>> n, ~a on Int
String interpolation s"Hello, $name", s"${items.mkString(", ")}" (full expressions, including nested string literals), md"..." (self-hosted interpolation + indent stripping on ScalaScript 2.1 native VM/ASM/build-jvm; no Scalameta or host parser)
Math math.sqrt, math.abs, math.pow, math.Pi, …
Extension methods extension (n: Int) def squared: Int = n * n; imported symbolic operators dispatch on ADTs while primitive Int operators retain their built-in meaning
Typeclasses trait Show[A], given, summon[Show[Int]], context bounds
Higher-kinded types (HKT) trait Functor[F[_]], sealed dispatch, auto-resolution
Standard typeclasses Functor, Applicative, Monad, Foldable, Traversable, Either, Eq, Show, Hash, Order, Semigroup, Monoid, Bifunctor, MonadError, Selective
Recursion factorial, Fibonacci, tree traversal
Tail-call optimisation self-TCO and mutual TCO — no @tailrec required
Case-class .copy p.copy(field = newValue, ...); named labels and evaluation order are compiler-free on the standard 2.1 path
List / map literals [1, 2, 3]List(…), ["k" -> v, ...]Map(…), []List() — compact sugar in .ssc code blocks

Optics

Feature Syntax
Lenses Focus[T](_.a.b)Lens with get / set / modify / andThen
Prisms Prism[Sum, Variant]getOption / set / modify / reverseGet
Optionals Focus[T](_.maybe.some.field)Optional for paths through Option fields
Traversals Focus[T](_.items.each.field)Traversal — multi-foci getAll / modify / set

Effects and concurrency

Feature Syntax
Algebraic effects effect E: has an atomically enforced one-shot resume; a second call fails as ONESHOT_VIOLATION. Use multi effect E: for reusable resume. VM, direct ASM, and Swift share this contract
Deep residual-effect forwarding On the portable VM and direct ASM, an operation unmatched by the nearest handler remains the same three-field Op for the next enclosing handler. Resuming it reinstalls the skipped handler and preserves the original one-shot or reusable continuation; see the verified design and axis-19 probe
Stack-safe deep effect resume Portable VM and direct ASM fold handler resumptions through one iterative runtime: 100,000 tail/sequence operations and 20,000 non-tail or escaped continuation resumes run without growing the native stack. See the verified design and axis-20 probe
Scala 3 control API (explicit Tier 1 + lexical direct M1 implemented) Publication-ready _3 leaf in scalascript.control: typed Eff, deep handlers, generative multi-prompt shift/reset, reusable and one-shot local continuations, stackless state machines, and bounded direct.reset/direct.shift macros that lower only to that explicit protocol. Local save() rejects with typed UnmanagedCapture; see the runnable Scala example, macro contract, and Scala/JVM profile
JavaScript/TypeScript explicit control API (first slice implemented) ESM-only @scalascript/control leaf in v2/host/js/control: zero-production-dependency iterative Eff, deep handlers, reusable/one-shot resumptions, named generative effect owners, true shift/reset, opaque runtime authority, branded .d.ts, and an Apache-licensed five-file tarball. Its 31 package tests cover all 17 currently specified local semantic vectors plus 1,000,000-bind/state and 100,000-operation stress gates; generated facades, bridges, durable runners, and lane qualification remain open
JavaScript/TypeScript lexical direct control (T1 fourth repair implemented; rereview pending) Zero-production-dependency @scalascript/control-direct package in v2/host/js/control-direct: a TypeScript 5.9 consumer-owned compiler transform plus real packed ssc-control-tsc bin, lowering closed synchronous direct.reset blocks and top-level const/let shift bindings to the one explicit ABI. Its exact eight-file manifest is self-contained—only the registry TypeScript 5.9.3 dev pin, never a repository-local sibling—and is clean-extraction install tested. JavaScript emit removes completed marker/type-only edges while declaration emit retains types; runtime CommonJS import = require is rejected while import type = require erases. Checker-resolved ownership also rejects suffix capture, surviving values, direct eval, and unmanaged frames. Package-local differentials cover vectors 18/22/23/24 without claiming the pending generated-JS lane. See the bounded contract
Shared control semantic vectors (implemented) One validated catalog and lane matrix carries 26 stable law vectors across 9 declared lanes. Portable VM and direct ASM each pass 13/13 eligible process vectors; the explicit Scala API passes 17 semantic vectors plus coverage, and the lexical direct lane passes vectors 18/23 plus coverage. Vector 22 additionally requires prompt forwarding through a nested different-prompt reset and remains explicit/plugin evidence; unqualified generated host and AOT lanes remain explicitly PENDING
Full control interoperability (in progress) One target-neutral contract in specs/control-interoperability.md. The bounded Scala lexical macro M1 is implemented; successful durable save/run, network transfer, Scala↔ScalaScript typed bridges, managed callbacks/TCO, compiler plugins, admission, and exact/portable runners remain post-X1 work
Canonical interop descriptors (Slice A infrastructure) Target-neutral v2/interop/descriptor leaf with bounded canonical codecs and checked factories for ApiDescriptor, ControlSummary, and ArtifactManifest; compiler/linker producers and runtime/admission consumers remain queued in descriptor v3
Plugin capability profiles (infrastructure) Target-neutral v2/interop/plugin-profile leaf derives stable semantic/schema identities, pins exact target implementation bytes, projects one canonical descriptor binding, and validates target/capability/transitive dependency closure before plugin installation. The JVM NativePlugin adapter remains source/binary compatible; package/linker population is a later descriptor slice. See the verified profile
Host/runner profiles (in progress) The JS/TS explicit local leaf is landed and the bounded lexical direct-transform repair is at pre-integration rereview; native typed bidirectional bridges and remaining host/runner slices for Scala/JVM, JS/TS, Rust, and Swift stay mandatory, measured against the portable-VM reference runner, plus the WASM/WASI runner
Typed effect rows def foo(): A ! Logger — effect appears in function type; closed row (no !) = total/pure
multi effect Explicit multi-shot effects — continuation can be resumed many times; raw CoreIR effect.perform also remains reusable
Reader[R] capability Context-injection effect: Reader.get, runReader(value)(body)
NonDet multi-shot Nondeterministic branching via multi-shot continuations
EffectAnalysis Compile-time error for unhandled effects (not just a warning)
Standard effects — Logger Logger.info(msg), runConsoleLogger, runTestLogger
Standard effects — Random Random.nextInt(n), runSeededRandom(seed)
Standard effects — Clock Clock.now(), Clock.millis(), runSystemClock
Standard effects — State State.get, State.set(v), State.modify(f), runState(init)
Standard effects — Env Env.get(key), runEnv(map)
Standard effects — Http Http.get(url), Http.post(url, body), runHttpClient
Standard effects — Retry Retry.attempt(n)(body), runRetry(policy)
Standard effects — Cache Cache.getOrSet(key)(body), runCache
Standard effects — Tx Tx.begin, Tx.commit, Tx.rollback, runTx
Standard effects — Auth Auth.check(claims), runAuth(verifier)
Direct syntax (do-notation) direct[M] { x = expr; y = expr2 }, .! postfix bind
Effect-row unions direct[Async | Random] { ... }
Built-in Async effect runAsync { Async.delay(ms); Async.parallel(...) } — deterministic and core-free on 2.1 native VM/direct ASM/build-jvm
Real-thread runAsyncParallel ordered JDK 21 virtual-thread concurrency without changing call sites or loading compatibility code
Built-in Storage effect runStorage { Storage.put(k, v); Storage.get(k) } — core-free JSON file-backed or ephemeral handlers on 2.1 native VM/direct ASM/build-jvm
Coroutines coroutineCreate, coroutineResume, suspend, Step[Y,T], coroutineCancel — lazy two-way handoff with opaque handles, core-free on 2.1 native VM/direct ASM/build-jvm
Generators generator[T] { () => suspend(v) }, pull/combinator pipelines — core-free on 2.1 native VM/direct ASM/build-jvm; Dataset bridging remains explicit
Reactive signals Signal(0), s.get / s.set(v), computed { … }, effect { … } with diamond-dedup flush — core-free on 2.1 native VM/direct ASM/build-jvm
Free monad Free[F,A], liftF, foldMap, runM — in runtime/std/free.ssc

Actors

Feature Syntax
Local actors runActors, spawn, self(), pid ! msg, timed/plain receive, and exit(pid, reason) are core-free on the 2.1 standard VM/direct ASM/build-jvm path; links, monitors, and supervision trees remain explicit compatibility/advanced-provider surfaces
Distributed actors actor cluster over WS, bully leader election, Phi-accrual FD, gossip, membership events
Typed actor refs + named remote spawn ActorRef[M], ref.tell(msg), ref.address, ref.isLocal, registerBehavior, spawnRemote; the 2.1 standard provider supplies deterministic process-local named loopback, while network transport remains explicit compatibility/advanced-provider work
Cluster capability + code identity clusterOf, SeedResolver.staticList, codeIdentity, assertCodeIdentity for typed cluster snapshots and deterministic SHA-256 code checks
Remote handler registry remoteHandlers:, @remote(...) def, and simple remote def declarations lower to an interpreter RemoteHandlerRegistry; Remote.function[A, B](name).call(value) uses the in-process path, path: entries expose POST HTTP JSON fallback routes, Remote.http[A, B](url) calls those routes explicitly, remoteStub[Api](baseUrl) / Remote.stub[Api](baseUrl) provide a path-based HTTP JSON fallback stub, and RemoteClientDeriver exposes path: handlers as generated RemoteRpc typed HTTP client metadata for JS/JVM codegen. Generated trait methods, async effect-row lowering, WebSocket/internal-wire transport, and binary WireCodec[A] negotiation are planned

Web and HTTP

Feature Syntax
HTTP server route(method, path)(handler), serve(port), Request/Response
REPL web mode :serve/:stop/:clear/:mount/:load/:reload/:unmount/:routes/:http/:call — mount handlers and test routes interactively; :set errorDetails true|false
HTTP streaming streamResponse, SSE via sse(req)
HTTP middleware CORS, gzip, cache headers, /_health / /_ready, /_openapi.json / /_swagger with typed response schemas for front-matter/generated JVM routes when apiClients: metadata is available; ssc emit-openapi exports the same document as JSON/YAML without starting a server; @openapi(...) adds per-route summary/description/tags/deprecated/security metadata and openApiSecurity(...) declares OpenAPI security schemes
WebSocket server onWebSocket(path), ws.send/recv/close/ping, rate limiting, per-route maxConnections
TLS tls("cert.pem", "key.pem"), serve(443, tls=...), wss://
HTTP client httpGet/httpPost, httpClient { }, httpGetStream for SSE/LLM streaming
WebSocket client wsConnect(url) { ws => }, wss://
REST ergonomics jsonParse/jsonStringify/jsonRead, req.json, JsonValue, validate { }, middleware
YAML data parseYaml / toYaml, total yaml* accessors, and heading-scoped <SectionId>.yaml / yml fences — core-free on 2.1 native VM/direct ASM/build-jvm
Typed handlers CaseClass => CaseClass auto-deser (path/query/body) + auto-ser (JSON 200); Either[Request, Input] for explicit error handling
SQL databases databases: front-matter declares named JDBC connections; ```sql ``` fenced blocks execute DDL/DML; ```transaction ``` fenced blocks run multiple ;-separated statements atomically (JDBC transaction, commit/rollback); Db.query/execute for programmatic access; SQLite, H2, PostgreSQL out of the box
XML markup ```xml ``` fenced blocks parse well-formed XML 1.0 into Value.MarkupV(doc: Markup.Doc); ${expr} interpolation with automatic XML escaping; bound as <section>.xml; zero-dependency PureMarkupCodec parser
XSLT transformation MarkupCodec.default.transform(doc, xslt, params) applies an XSLT 1.0 stylesheet to a Markup.Doc; returns Either[TransformError, Markup.Doc]; parameter substitution via Map[String, String]; JVM / interpreter only (Feature.Xslt); see examples/xslt-transform.ssc
Secret resolution ${env:VAR}, ${file:/run/secrets/pw}, ${sops:key.path} in database URLs/credentials; SecretResolver SPI for Vault, AWS SM, GCP SM, Doppler, 1Password and more
Progressive Web App pwa(name, themeColor, icons, precache) — registers GET /manifest.json + GET /sw.js; cache-first precaching service worker; works in ssc run and ssc run-jvm

The ScalaScript 2.1 compiler-free standard launcher executes sql fences natively in document order, converts ${expr} to JDBC binds, preserves $$, and exposes _sqlBlock_N plus the first <Section>.sql result. This path works on standard VM, direct ASM, slim/JRE, and build-jvm without Scalameta, the v1 frontend, or a transparent fallback. Typed native Db.query/insert/update[A] now derives bounded portable product schemas from Mirror, validates generated identifiers, binds every value, and reconstructs case-insensitive JDBC rows on the same compiler-free lanes.

Planned, not implemented yet:

Feature Planned shape
Full-stack in-process transport ssc run and ssc run-jvm recognize `--transport http
JVM desktop frontend ssc run-jvm --frontend swing app.ssc launches the JDK-only Swing runtime in the current JVM process; ssc run-jvm --frontend swing --transport in-process is accepted as the monolithic JVM mode foundation; Swing fetchAction can call generated JVM backend routes in-process; ssc run --frontend swing remains the interpreter path and reports that Swing intrinsics are planned; JavaFX/Compose adapters remain planned
Typed route clients apiClients: / api-clients: front matter preserves endpoint method/path/request/response metadata in AST and JVM/JS codegen. JVM/Swing generates callable in-process clients that encode case-class/ADT inputs through JsonCodec[T], dispatch through generated BackendTransport, and decode typed JSON responses through JsonCodec[T]. JS/browser/Electron bundle codegen emits Promise-returning HTTP clients over fetch and passes request/response type names through the shared typed JSON facade; generated JS case-class/enum metadata decodes known response shapes back into generated JS values. Client-side ScalaScript can use awaitClient(Messages.list()), which lowers to JS await and enables the needed async wrapper. emit-spa --server-url, web client mode, and Electron JVM REST dev mode can route those relative calls to a JVM backend. examples/frontend/typed-client-distributed/ demonstrates one source running as backend on one machine and client on another
Client/server object storage JS/browser/Electron code can use IndexedDb.store[A]("store", "dbName", "keyField") for Promise-based typed local object storage, awaited with awaitClient(...); native IndexedDB is used when available, with a lightweight fallback for Node/tests. JVM code can use ObjectStore.put/get/all/delete/changes[A](dbName, store, ...) over the declared JDBC database. JVM codegen emits typed GET /__ssc/sync/{store}/changes and POST /__ssc/sync/{store}/push routes for objectStores: entries with sync: client-server. JS clients call Sync.pull/push[A] or the combined Sync.sync[A]; Sync.put/remove[A] persist local queued mutations for offline-friendly pushes. Conflicts are listed with Sync.conflicts, resolved with Sync.resolve[A], or handled automatically by generated JVM conflict: policies. Sync.status(store, db?) returns { pending, conflicts, lastPulled, lastPushed, isSyncing } for sync-status badges; Sync.isOnline and Sync.isSyncing(store, db?) give per-store and network availability signals
Graph storage backend/graph now provides GraphCapabilities, PropertyGraphBackend, RdfGraphBackend, GraphBackend, GraphRuntime.inMemory(), GraphRuntime.tinkerGraph(), GraphRuntime.rdf4jMemory(), and GraphRuntime.sparqlSelect() for portable JVM property/RDF storage through typed codecs plus RDF4J SPARQL SELECT. graphs: front matter survives AST/IR/.sscc; JVM codegen emits a typed Graph.* facade for declared in-memory, embedded-tinkergraph, and rdf4j-memory graph stores plus Sparql.select for RDF4J-backed stores. The core-free v2/runtime/std/graph-plugin mirrors deterministic process-local property/RDF operations on standard VM/direct ASM/build-jvm; remote SPARQL/Cypher/Gremlin require explicit providers and produce bounded diagnostics locally. Production adapters such as Neo4j, JanusGraph/TinkerPop providers, and RDF4J-compatible repositories remain planned
Typed data mapping backend/typed-data now provides the shared emitted typed JSON facade for generated route clients plus explicit JsonValue, DecodeError, JsonCodec[A], JsonFieldSpec, RowValue, RowValueCodec[A], RowFieldSpec[A], RowCodec[A], ObjectValue, ObjectFieldSpec[A], ObjectCodec[A], VertexValue, EdgeValue, RdfValue, VertexCodec[A], EdgeCodec[A], RdfCodec[A], DatasetCodec[A], DatasetWire, and SparkSchemaCodec[A] helpers. derives JsonCodec supports case classes and sealed ADTs; derives RowCodec, derives ObjectCodec, derives VertexCodec, derives EdgeCodec, derives RdfCodec, and derives SparkSchemaCodec support simple case-class rows/documents/graph records/schema records. DatasetCodec[A] derives from JsonCodec[A] and now exposes partition payload helpers for distributed MapReduce worker movement; DatasetWire wraps those payloads in shared JSON/MsgPack/CBOR WireEnvelopes and chunks large partitions. std/mapreduce can move DatasetWirePartition payloads directly through runDistributedWire and runDistributedShuffleWire, with DistributedDataset.encode/decode[A] wrapping the typed boundary and DistributedDataset.run/runShuffle[A, B] wrapping the actor-effect calls for map and shuffle. SparkSchemaCodec[A] uses the same @fieldName, @key, and Option nullability conventions to produce Spark-like schema metadata, and SparkGen typed readers consume that metadata when it is in scope. Graph/RDF codecs add @graphLabel, @graphEdge, @graphFrom, @graphTo, @rdfClass, @rdfId, and @rdf. SqlRuntime.query/insert/update[A] use RowCodec[A], and interpreter/JVM codegen expose Db.query/insert/update[A] for typed SQL reads and writes. Broader cross-store migration helpers remain planned

Dataset/MapReduce typed wire calls can select wireFormat = "msgpack" | "cbor" to send DatasetWire envelope bytes through actor partition, shuffle-bucket, and key-result messages.

Auth and security

Feature Syntax
Sessions + CSRF req.session, withSession(Map(...)), csrfToken() / csrfValid(req)
JWT bearer tokens jwtSign(Map(...)), jwtVerify(token), RS256 and HS256
Password hashing hashPassword/verifyPassword (PBKDF2)
TOTP 2FA totpGenerateSecret, totpVerify(secret, code)
WebAuthn / passkeys Server verifier: webauthnChallenge, webauthnVerifyRegistration, webauthnVerifyAssertion, webauthnStore*; browser actions: webauthnRegister / webauthnAssert from std/ui/webauthn.ssc
OAuth2 oauthAuthorizeUrl(...), oauthExchangeCode(...), oauthUserinfo(...), Google + GitHub presets

MCP (Model Context Protocol)

Feature Syntax
MCP server mcpServer { srv => srv.tool(...) }, serveMcp(Transport.stdio/Http/Ws)
MCP client mcpConnect(url) { client => client.callTool(...) }

Both halves are in the standard graph as of 2026-07-31 and run on plain ssc — there is no ssc-provider mcp lane any more.

Data processing

Feature Syntax
Dataset / MapReduce Dataset[T] with map/filter/flatMap/groupBy/reduceByKey/top/countByValue
Execution modes runLocal, runParallel, runDistributed
Apache Spark Same Dataset[T] source → sql fenced blocks · @SqlFn UDFs · Scala 3 native encoder derivation · Structured Streaming · Delta Lake · Hive metastore · MLlib pipelines

DSL authoring and metaprogramming

Feature Syntax
Parser combinators runtime/std/parsing/* — Parser ADT, ~/~>/~<, rep, opt, sep, error recovery, indentation-aware
Multi-pass pipelines runtime/std/dsl/*Pass[A,B], andThen/parallel/recover, Visitor, cata, ana
Metaprogramming inline def/val/if/match, compiletime.constValue/summonInline/error. Restricted quoted macros run on the interpreter, JVM, and JS backends (MacroCodegen.expand pre-codegen pass), including Expr.asValue match compile-time constant folding and cross-module macro expansion, with targeted unsupported-body diagnostics; ssc check warns on interpreter-only macros. Mirror.Of[T] conformance + custom derived(m: Mirror) typeclasses (JVM + JS)
Derives derives Eq/Show/Hash/Order/Foldable/Traversable/Functor; structural stdlib + custom derives cross-backend (JVM + JS)
Checked errors throws[A, E] = Either[E, A], throwsRaw[A, E] = A | E, attemptCatch, HasStackTrace

Module system and tooling

Feature Syntax
Package system package: org.example.ui in frontmatter, namespaced exports, collision-safe imports
Module imports [name](./lib.ssc) Markdown links bring definitions into scope; one pure Markdown paragraph may contain multiple import links
URL imports [X](https://...) URL fetch, cached at ~/.cache/ssc/
Dependency imports [X](dep:org/lib:1.2) legacy source resolver, [X](dep:org:name:version) Coursier resolver, [X](jitpack:com.github.owner:repo:tag), [X](github:owner/repo@tag[#asset]), sha256: pins, ssc.lock
Package registry ssc search / ssc info / ssc add against https://sergey-scherbina.github.io/scalascript/packages.yaml by default, overrideable with --registry or registry.url
Project scaffolding ssc new my-app, `--template lib
Plugin system .sscpkg format, essential bundled plugins auto-loaded from bin/lib/compiler/plugins, advanced bundled plugins available locally under bin/lib/compiler/plugin-available and enabled with --plugin / ssc plugin install, ~/.scalascript/registry.yaml
sbt integration ScalascriptInteropPlugin, sscGenerateFacade, sscCompile, sscLink, sscTest, sscRun, sscRepl, sscWatch, sscBspSetup, sscBackends cross-build (emit JVM/JS/Rust/Wasm artifacts from one source), Phase 5 dependency resolution, src/main/scalascript/ source convention
Config system config: front-matter, ```yaml config "name" fenced blocks, config.files: [...], typed derives Config, JsConfigEmitter, ScalaConfigEmitter — see specs/config-system.md
Separate compilation ssc emit-interface, ssc emit-ir, ssc compile-jvm/compile-js, ssc link, ssc build --incremental, .scim/.scir/.scjvm/.scjs; .scir and .sscc preserve Markdown content snapshots when present

Browser and UI

Feature Syntax
Browser SPA target ssc emit-spa file.ssc — same route() source runs as a single-page app
Web Components ssc emit-wc, customElements.define
SSR + hydration wc(tag, component, args*) declarative shadow DOM
Component library runtime/std/ui/* — Button, Input, Select, Modal, Card, Spinner, Alert, DatePicker, Combobox, and more
Frontend Framework SPI One .ssc source compiled to React, Vue 3, Solid, or a custom runtime via frontend-{react,vue,solid,custom} backends
Reactive primitives Signal[T], ShowSignal (conditional render), ToggleSignal, ForSignal[T] (list render) — uniform semantics across all 4 frontend backends
runtime/std/ui script toolkit Declarative widget DSL from a .ssc file — vstack/hstack (hstack also takes a trailing wrap: Boolean = false that sets flex-wrap: wrap so a row's children flow onto additional lines instead of overflowing/shrinking on one — browser-computed, not caller-pre-grouped; specs/std-ui-hstack-wrap.md), textField, checkbox, select(options, selected, label, placeholder, disabled) dropdown over (value, label) pairs two-way bound to a Signal[String] (specs/std-ui-select.md), selectFrom(items, key, optionFn, selected, label, placeholder, disabled) — the reactive-options sibling: items is a Signal[List[A]] instead of a static list, so the <option> children re-render (item added/removed/reordered, DOM identity preserved for kept items) on the JS runtime lane when the signal changes, e.g. a fetched contracts list (specs/std-ui-select.md § "Reactive options (selectFrom)"), signalButton, actionButton, signalLabelButton, signalActionButton — all four take a trailing variant: String = "primary" (`primary
Browser WebAuthn actions std/ui/webauthn.ssc exports webauthnRegister and webauthnAssert EventHandlers for passkey buttons on the production emit-spa --frontend custom path; begin routes return challenge/options JSON, complete routes receive verifier-shaped base64url JSON
Native Markdown toolkit controls Markdown/YAML @ui=toolkit controls lower through the same std/ui View pipeline for Swing, JavaFX, and SwiftUI native clients; see examples/frontend/markdown-native-controls/
NFC NDEF (std.nfc) nfcCapabilities, nfcPermissionStatus, readNdef, writeNdef, textRecord, uriRecord, mimeRecord; in the standard graph since 2026-07-31, so plain ssc supplies the native VM/ASM host provider and its deterministic unsupported-hardware snapshot; Android/iOS/Web adapters remain capability-gated
Rozum / agent loop (std.agent) runAgent, runAgentPool, runAgentStream, runAgentStreamPool, collectAgentStream, collectAgentStreamPool, AgentEndpoint, AgentEndpointPool, AgentSchema, AgentTool, agentToolFor, RunOptions, ToolResult, AgentEvent — OpenAI-compatible tool-call loop for stateless rozum gateways; apps own prompts, typed or explicit tool schemas, validation, streaming callbacks, failover policy, and side effects
Fetch primitives fetchUrlSignal — live GET binding (v2: real fetch + headers); seedSignal — editable draft seeded from another Signal[String] until user input makes it dirty, supported by the browser runtime and frontend emitters including JVM desktop; fetchAction/fetchActionClear — POST/PUT/DELETE on button click with optional headers: Signal[String] for bearer tokens; the compiler-free standard JVM/static lane constructs these fetch descriptors without network I/O or a compatibility fallback, while emitted browser runtimes execute them; dataTableView over any TableDataSourcestaticRowsSource (in-memory rows, no fetch), signalRowsSource (reactive rows signal), or a bare fetch signal (Remote) — on interpreter, JVM, and JS browser backends alike; rowPostAction bodies via fieldPayload / wholeRowPayload / fieldsPayload; incSignal — manual refresh; emptyHeaders sentinel
Fetched-view state helper std/ui/state.ssc provides loadState, stateName, errorText, triState, and triStateText for loading/empty/error/ready views over existing signals, with no new backend intrinsic
Themes defaultTheme (light) · darkTheme · custom Theme(ColorPalette, SpacingScale, TypographyScale, RadiusScale)
Frontend Toolkit (v1.18 B+ / B++ / C) High-level declarative UI via Tk facade (sbt API) — vstack/hstack, card, textField, form with validators, router, modal/drawer/tabs, table. Backend-agnostic: lowers to React / Vue / Solid / Custom or to static HTML via Ssr.renderToHtml.
WebAssembly target ssc emit-wasm file.sscscalascript blocks lowered to Wasm; cross-backend sql fenced blocks supported. Algebraic effects compile and run on Wasm (arithmetic, collection HOFs, multi-shot resume, cross-module) via a pure-Scala effect runtime with no preamble bloat. @wasm extern FFI + cross-module inlining + macro expansion are wired
Native Rust SSR server serve(view, port) on the Rust backend (ssc build-rust) emits a self-contained tokio + hyper server with server-side rendering, a reactive signal store, computed-signal live recompute, Server-Sent Events push (/__ssc/events), and a direct WebSocket signal endpoint on port + 1 — no JS framework, no Node runtime. See docs/rust-backend.md
i18n translations: frontmatter, t(key), setLocale(code)
Env access getenv(key) / getenv(key, default)
Content helpers Self-hosted md"..." plus recursively composable doc(...) / render(...) structured output (nested docs flatten; reserved tags never leak); the ScalaScript 2.1 native VM, direct ASM, and build-jvm artifact use language lowering + the core-free host provider with no v1 DocV, PluginBridge, Scalameta, or parser dependency
HTML / CSS interpolators html"..." (auto-escaping) and css"..." with ${expr}

Blockchain, wallets, and micropayments

Feature Syntax
x402 micropayments HTTP 402 → typed payment challenge / settlement via Payment[T], x402Server { … }, x402Client(...) — Ethereum + Cardano payment families
Blockchain SPI (draft / planned, not fully implemented) BlockchainBackend trait — EVM (mainnet, L2s), Bitcoin, Solana, Cardano via pluggable backends. See specs/blockchain-spi.md
Wallet Connect (WC v2) Relay-transport cryptographic primitives — pairing, session, JSON-RPC, X25519 / HKDF / ChaCha20-Poly1305
Browser MetaMask wallet x402ClientJs helper — Wallets.metaMask(Network.Base) over window.ethereum + EIP-712 signing
Ledger hardware wallets JVM HID and browser WebHID vaults — Ledger HID APDU framing, Ethereum app signing, Cardano CIP-8 helpers
MPC wallet vaults wallet-vault-mpc remote signing core plus wallet-vault-mpc-fireblocks provider adapter — Fireblocks JWT auth, RAW transaction signing, polling
Solana Wallet Standard solana-wallet-std translator — Wallet Standard ↔ unified Wallet SPI
ERC-4337 account abstraction EntryPoint v0.7 PackedUserOperation — bundlerless and bundler-driven flows
Cardano CIP-8 wallet Ed25519 key-derived enterprise bech32 address, CIP-8 message signing, Scalus-source escrow validator with on-chain canonical CIP-8 proof verification, exact receiver-output check, claim/refund validity-window checks, Scalus script-context validator tests, stable EscrowScript.address(network) script address helper, Scalus-mode structured claim-message signing, server-side Scalus proof verification, bloxbean claim Tx draft with script data hash + relayer witness, typed Blockfrost protocol params, protocol min-fee draft balancing, static/bloxbean/Blockfrost/Ogmios Plutus ex-units, and env-gated Preprod integration coverage
Cross-backend crypto JVM: native Ed25519, secp256k1, BLS12-381; JS: @noble/curves Scala.js backend — uniform CryptoBackend SPI
std.crypto hashing sha256 (hex) / sha256Base64 (base64 digest) / sha256OfBase64 (digest over decoded bytes), byteLengthUtf8, hmacSha256, base64Encode/base64Decode — digests + encoding (e.g. KSeF invoiceHash/encryptedInvoiceHash)
std.crypto encryption AES-256-GCM (aesGenKey/aesGcmEncrypt/aesGcmDecrypt + byte variants), AES-256-CBC + PKCS#7 with external IV (aesGenIv/aesCbcEncrypt/aesCbcDecrypt), RSA-OAEP (rsaOaepEncrypt), X.509 SPKI extraction (x509PublicKey) — hybrid encryption for KSeF 2.0 etc. (JVM, including compiler-free native VM/ASM)
std.crypto signature verify verifyEd25519/verifyEd25519Url, verifyRsaSha256 (PKCS1/PSS) — total verifiers (malformed → false, never throw) for trustless federation (JVM, including compiler-free native VM/ASM)
std.crypto signing ed25519Sign/ed25519SignUrl, rsaSignSha256 (PKCS1/PSS) — private-key signers that round-trip with the verifiers; for chain-checkpoint evidence a third party can verify without a shared secret (JVM, including compiler-free native VM/ASM)
std.crypto OTP + secret sharing RFC 4226/6238 hotp/totp/totpValidate plus prime-field shamirSplit/shamirRecover; fixed vectors and threshold recovery agree on native VM/ASM
std.pdf generation htmlToPdfBase64(html) — render a confined HTML/CSS subset (table layout, A4, typography/borders/bg) to base64 PDF bytes via OpenHTMLtoPDF; explicit native VM/ASM provider: ssc-provider pdf ... (JVM only)
std.pdf extraction pdfToMarkdown(pdfBase64) / pdfPageCount(pdfBase64) — read a PDF's text layer (Apache PDFBox), pages split by ---; explicit native VM/ASM provider, non-PDF throws (JVM only)
std.mime assembly buildMimeMessage(from,to,subject,htmlBody,attachments) — hand-rolled RFC 5322 multipart/mixed; the dependency-free MIME companion is selected with the explicit PDF invoice provider lane (JVM only)
MCP × x402 mcpServer { srv => srv.tool(...).requirePayment(...) } — paid LLM tools

Cluster, leader election, federation

Feature Syntax
Bully leader election cluster.leader() returns the current bully-elected leader; reactive on membership change
Phi-accrual failure detector Heartbeat-driven liveness; tunable phi threshold per cluster
Self-health cluster.self.health — driver-side health metric stream
Federation Multi-cluster gossip + cross-cluster routing — see specs/cluster-federation.md
Raft consensus Strongly-consistent state machine — see specs/cluster-raft.md
ZooKeeper client zkClient { … } for legacy coordinator integration — see specs/client-zookeeper.md
Operational HTTP routes /_ssc-cluster/status, /_ssc-cluster/members, /_ssc-cluster/leader — built-in across all 4 frontend / Node backends

Examples

File Description
hello.ssc Minimal "Hello, World!"
fs-roundtrip.ssc std.fs write / read / append / list / delete round-trip
os-env.ssc std.os env vars, path helpers, platform detection
nfc-ndef.ssc std.nfc capability check plus text/URI/MIME NDEF record constructors
rozum-agent.ssc Self-contained fake rozum gateway plus std.agent tool-call loop over an accounting-style tool
rozum-agent-schema-derived.ssc Self-contained fake rozum gateway with derived AgentSchema and explicit tool schemas side by side
rozum-agent-pool.ssc Self-contained fake primary/secondary rozum gateways plus AgentEndpointPool failover
rozum-agent-streaming.ssc Self-contained fake rozum SSE gateway plus runAgentStream callbacks for text/tool-call events
yaml-parse.ssc std.yaml parse/access/stringify plus heading-scoped fenced YAML; exact on core-free 2.1 VM/direct ASM/build-jvm
ui-typed-json.ssc std.json navigable JsonValue (total accessors, exact asDecimal) + structured builders
ui-fetch-json.ssc fetchJsonValue (GET → navigable JsonValue) + fetchJsonAction (POST structured body)
frontend/std-ui/styled-primitives.ssc std.ui status primitives (badge/tag/pill/kpiCard/tabBar), token-aware styled(), box sizing; re-themes under dark
datatable-static-spa.ssc Browser SPA backed by a static in-memory DataTable (staticDataTable / fieldsBody); renders client-side with no fetch, identical on interpreter / JVM / JS
index.ssc Landing page for the serve examples browser
script.ssc Functions, loops, Fibonacci
data-types.ssc Case classes, sealed traits, enums, pattern matching
functional.ssc Lambdas, closures, HOF, composition, pipelines
enums.ssc Simple and parameterised enums, recursive ADTs
extensions.ssc Extension methods, for comprehensions, while, recursion
imports.ssc Math, geometry, statistics
multi-link-imports.ssc Two std modules imported from one pure Markdown paragraph
typeclass.ssc Show, Eq, Ord, Monoid, Functor via given/summon
quoted-macro-interpreter.ssc Restricted quoted macros on the interpreter run path with Expr.asValue / Expr.asTerm
quoted-macro-constfold.ssc Compile-time constant folding via Expr.asValue match (literal → Some, else None); interpreter run + ssc link fold
custom-derives-mirror.ssc User-defined typeclass derives through runtime Mirror metadata
typed-data.ssc Data pipelines, Option, enums
graph-storage.ssc JVM graphs: front matter plus generated Graph.* facade over embedded TinkerGraph property graph storage
graph-rdf4j-storage.ssc JVM graphs: front matter plus generated Graph.* and Sparql.select facades over RDF4J memory RDF storage
graph-storage-interpreter.ssc Interpreter Graph.* facade over in-memory property graph storage
content.ssc md interpolator, auto-output, doc/render
content-introspection.ssc Markdown-to-frontend authoring: Markdown body content, YAML data, section ids, and multiple real std/ui controls declared directly in yaml @id=... @ui=toolkit blocks and selected by id; runs as a live serve(page, 8099) phone preview
std-ui/raw-html-demo.ssc Toolkit v2 rawHtml escape hatch demo: trusted markup injection beside escaped rawText
std-ui/tri-state-demo.ssc Toolkit v2 loading/empty/error helper demo: triStateText switches a fetched view over existing state signals
markdown-toolkit-links.ssc Live serve(page, 8099) example where textField, checkbox, button, signalText, and badge controls are declared as ordinary Markdown toolkit: links instead of YAML, including a visible Apply-status update
content-to-markdown.ssc Reverse-render selected DocumentContent regions back to semantic Markdown with contentToMarkdown(value)
content-linked-namespaces.ssc Read section content from a directly imported module namespace with contentModuleSection(namespace, id) and render the imported money module's BigInt minor-unit result identically on native VM/ASM and build-jvm
content-tables.ssc Use a Markdown GFM pipe table as ContentBlock.Table, show raw ${name} placeholders, bind YAML data with contentBind(...), and lower the bound table through contentToolkitBlock(id) to a toolkit TableNode
content-toolkit-transitive/app.ssc Entry module renders a @ui=toolkit control block through contentToolkitBlock(id) called from a transitively-imported child — the JS backend emits the content-toolkit runtime for imports anywhere in the graph
content-live-rows.ssc Bind a live fetch Signal as the rows of a Markdown-authored table: a toolkit:table?rows=<id> link resolves a contentRows(id, signal, columns) registration to a live DataTable (content-toolkit 3b)
content-toolkit-yaml-controls.ssc Declarative @ui=toolkit YAML control tree whose {type: button, action: <id>}, {type: table, source: <id>}, and {type: signalText, signal: <id>} reference a registered action / data source / computed signal by id, and the table declares typed columns: (text/date/money/status/link) inline (declarative-ui Scope B.1 + B.5 + B.2)
content-data-source.ssc @ui=toolkit tables bound to named data sourcescontentDataSource(id, source, columns) registers a fetchSource(...) (managed GET, re-fetch on tick, with an optional dotted rowsPath envelope path) or a staticSource(...) (in-memory rows) under an id that source: resolves (declarative-ui Scope B.3)
content-action-onsuccess.ssc A @ui=toolkit button bound to an action whose structured onSuccess runs after a 2xx — fetchActionWith(method, url, body, [onBumpTick(t), onSetSignal(s, v), onNavigate(path)]) refreshes a table, flashes a status signal, and routes, in order; a failed POST runs none (declarative-ui Scope B.4)
content-form-submit.ssc A @ui=toolkit form whose submit action assembles its POST body from the named field signalsfetchActionWith("POST", url, formBody([("customerName", "customer"), "amount"]), …) serialises {customerName, amount} from the live signals at click (a (jsonKey, signalId) entry remaps a signal to a different wire key), no hand-maintained body signal (declarative-ui Scope B.4+)
content-slot.ssc A @ui=toolkit panel with a {type: slot, id: <id>} escape hatch filled by a code-built TkNode registered with contentSlot(id, node) — when the declarative vocabulary can't express a widget, the author drops a ScalaScript-authored one into the panel by id (declarative-ui Scope B.6)
markdown-native-controls.ssc Same Markdown/YAML-declared controls rendered through native clients: `ssc run-jvm --frontend swing
recursion.ssc Self-TCO, mutual TCO, Collatz — deep recursion without overflow
effects.ssc Algebraic effects — one-shot Console/Fail operations, explicit multi-shot nondeterminism, early return
std-effects-demo.ssc Logger, Random, Clock, State, Env standard effects
direct-demo.ssc direct[M] do-notation, .! postfix bind, effect-row unions
async-demo.ssc Built-in Async effect — runAsync, async, await, parallel, delay
coroutine-demo.ssc Lazy two-way and nested Coroutine[Y,R,T] values plus idempotent cancellation; exact on native VM/direct ASM/build-jvm
signals-demo.ssc Reactive signals — Signal, computed, effect, diamond dedup
storage-demo.ssc Built-in Storage effect — core-free JSON-backed and ephemeral handlers on native VM/direct ASM
actors-demo.ssc Actors — spawn, send, receive, supervision, cluster
actors-pingpong.ssc Core-free local actor lifecycle — FIFO send, typed receives, timeout, self, and exit on native VM/direct ASM/build-jvm
actors-typed-remote-spawn.ssc Typed ActorRef[M] helpers plus named registerBehavior / spawnRemote
cluster-capability.ssc ClusterCapability, static seed discovery, and code identity checks
remote-registry-rpc.ssc remoteHandlers: / @remote / remote def registry declarations, Remote.function, typed remoteTryCall, HTTP JSON fallback path metadata, and generated RemoteRpc typed client metadata for path: handlers
openapi-annotation.ssc @openapi(...) route metadata and openApiSecurity(...) security schemes surfaced in /_openapi.json and Swagger UI
ws-recv-demo.ssc Sync-style ws.recv() loop alternative to onMessage callbacks
mcp-demo.ssc MCP server with tools and resources; MCP client usage
dataset-stats.ssc Dataset MapReduce — runLocal, runParallel, aggregations
distributed-word-count.ssc Offline distributed word count using local MapReduce actor workers via localLoopbackCluster
distributed-log-aggregation.ssc Offline distributed ERROR-count aggregation; pass a log path after --
distributed-join.ssc Offline distributed customer/order join using local shuffle workers; pass order and customer CSV paths after --
dsl-demo.ssc Parser combinators, error recovery, multi-pass compilation pipeline
lenses.ssc Native standard-path .copy, structural Focus Lens/Optional/Traversal, and Prism with no macro/compiler fallback
default-params.ssc Default parameter values on defs, classes, and enum cases
lang-split.ssc scala vs scalascript block annotations side by side
scala-js-demo.ssc Pure scala 3 document — runs on all three backends with byte-identical output
rest-api.ssc Tiny in-memory REST API — route(), html"...", serve()
mount-demo/ mount() intrinsic — file-based handlers, typed (CaseClass => CaseClass auto-deser/ser), 1-arg, 2-arg with ctx, static response
sql-sqlite-file.ssc SQLite file database — databases: front-matter, sql DDL/DML blocks, Db.query/execute
scljet-hello.ssc First taste of SclJet — create a books database and work with it through the JDBC façade: CRUD, an ORDER BY query, and a bound ? parameter (runs on interpreter, JS, and the default ssc run)
scljet-unique-index.ssc Enforced CREATE UNIQUE INDEX — composite key, SQLite-shaped duplicate diagnostic, atomic rejection, and a legal insert (interpreter + JS)
scljet-file.ssc Two engines, one file — SclJet writes a real .db to disk, then the same program shells out to the reference sqlite3 (via std.process) to read it, run integrity_check, and write into it (JVM host; degrades cleanly if sqlite3 is absent)
scljet-readonly-codecs.ssc Pure low-level SQLite 3.53.3 header, B-tree cell, and record decoding without JDBC/sql.js
scljet-readonly.ssc Write a pinned SQLite image through the JVM VFS plugin, then open its schema and stream a table row through SclJet's pure immutable pager
scljet-text-projection.ssc Project a decoded SQLite text field to an SqlText String with SclJet's portable code-points/UTF-16-units API — astral-safe, no host decoder, raw bytes stay the source of truth (interpreter, JS, and native agree)
typed-sql-crud.ssc Typed SQL CRUD — derives RowCodec, Db.insert/update/query[A] on interpreter and JVM codegen paths
typed-object-codec.ssc Typed object/document codec — derives ObjectCodec, portable object fields, aliases/defaults, and key extraction
graph-codecs.ssc Typed graph/RDF codecs — derives VertexCodec, EdgeCodec, and RdfCodec
dataset-typed-mapping.ssc Typed Dataset element mapping — DatasetCodec[A] over JsonCodec[A] in a JVM Dataset pipeline
distributed-dataset-codec.ssc Distributed Dataset partition payloads — DatasetCodec.encodePartitions/decodePartitions[A]
distributed-dataset-wire-protocol.ssc Distributed Dataset wire protocol — DatasetWirePartition payloads through local MapReduce actor workers
distributed-dataset-wire-shuffle.ssc Distributed Dataset wire shuffle — DatasetWirePartition reduceByKey through local MapReduce actor workers
distributed-dataset-typed-helpers.ssc Distributed Dataset typed helpers — DistributedDataset.run/runShuffle[A, B] around actor map + shuffle wire execution
spark-schema-mapping.ssc Spark-like schema metadata — derives SparkSchemaCodec using shared field annotations
spark-shared-schema-reader.ssc Spark typed CSV reader — Dataset.fromCsvAs[A] using SparkSchemaCodec[A] external column names
indexeddb-drafts.ssc Typed client IndexedDB store — IndexedDb.store[A], local put/get/all/keys, awaitClient(...)
indexeddb-sync-client.ssc Typed client sync helper — Sync.push[A] / Sync.pull[A] over local IndexedDB and REST sync endpoints
sync-todo.ssc Full sync UI helper API — Sync.put, Sync.sync, Sync.status, Sync.isOnline, Sync.isSyncing, Sync.pending
object-store-jdbc.ssc Typed server ObjectStore — JDBC JSON table, ObjectStore.put/get/all/delete/changes[A], derives ObjectCodec
object-store-sync-routes.ssc Typed ObjectStore sync routes — objectStores: front matter generates JVM REST pull/push endpoints
sql-transaction.ssc Atomic multi-statement transaction block — debit + credit in one JDBC transaction
spa-demo.ssc Same route() / serve() source, browser SPA via ssc emit-spa
pwa-demo.ssc Progressive Web App — pwa(name, icons, precache), GET /manifest.json + GET /sw.js
swing-hello.ssc Minimal JDK-only Swing desktop window
swing-fullstack/ No-socket JVM desktop full-stack example: Swing fetchActionClear posts to generated JVM backend routes and dataTable reads/deletes rows in the same process
swing-typed-client/ No-socket JVM desktop full-stack example using generated apiClients: methods over backend routes
typed-client-distributed/ Same-source distributed typed route client: JVM server on one machine, browser/Electron client on another via --server-url
webauthn-toolkit-demo/ Full-stack passkey enrol/sign-in demo using std/auth.ssc server verifiers and std/ui/webauthn.ssc browser actions
auth-demo.ssc Login / logout with signed cookie sessions + CSRF tokens
fetch-auth.ssc Bearer-token authed fetch: fetchActionClear with headers Signal (v1) + fetchUrlSignal GET with headers (v2)
seed-signal.ssc Editable draft signal seeded from fetchUrlSignal; reloads update the draft only while it is pristine
oauth-demo.ssc Full OAuth2 sign-in (GitHub or Google) — state, exchange, userinfo
tls-demo.ssc HTTPS + WSS server with tls(cert, key)
wc-demo.ssc Web Components via ssc emit-wc, SSR + hydration
wasm-fibonacci.ssc scalascript → WebAssembly module via ssc emit-wasm
wasm-sorting.ssc · wasm-matrix.ssc · wasm-primes.ssc · wasm-collections.ssc Wasm benchmark suite
wasm-scalascript.ssc scalascript blocks → WebAssembly — Point geometry with //> using dep
wasm-http.ssc HTTP Fetch via scalajs-dom in Wasm — //> using dep hoisted directive
algebraic-effects.ssc Typed effects end-to-end — discharge signatures, Reader[R], NonDet, multi effect
durable-save-run.ssc The same-process save/run idiom — capture a reusable continuation once via multi effect, run it many times; a prefix counter proves the prefix fires exactly once (no replay)
examples/frontend/counter/ · show-hide/ · todo/ · toolkit-demo One source compiled to React / Vue / Solid / Custom — first three via Frontend Framework SPI, toolkit-demo via high-level Toolkit (Tk facade) and covered by an Electron Add-flow smoke test
x402-server.ssc · x402-client.ssc HTTP 402 micropayment server + client (Ethereum settlement)
x402-metamask.ssc Browser x402 wallet helper — connect MetaMask and sign EIP-712 via window.ethereum
x402-cardano.ssc x402 on Cardano — CIP-8 wallet, Scalus escrow validator, end-to-end client + server
wallet-ledger-js.ssc Browser Ledger/WebHID vault sketch — connect lifecycle, Ethereum signer, Cardano CIP-8 helper
wallet-mpc-fireblocks.ssc JVM Fireblocks MPC vault sketch — remote secp256k1 signing through Fireblocks RAW transactions
spark-sql-demo.ssc Spark SQL via sql fenced blocks + ${expr} bind parameters + section aliases
spark-encoder-demo.ssc Scala 3 native Encoder[T] derivation — Dataset[CaseClass] end-to-end on Spark 4
spark-streaming-rate-console.ssc Structured Streaming — rate source → console sink with auto-awaitTermination
spark-delta-demo.ssc Delta Lake — auto-emit delta-spark dep + extension/catalog configs
spark-hive-demo.ssc Hive metastore via spark-hive-metastore: + @TempView("...") + Dataset.fromTable[T]
spark-mllib-pipeline.ssc MLlib — Tokenizer + HashingTF + LogisticRegression pipeline end-to-end
xslt-transform.ssc XSLT 1.0 transformation — identity, element rename, parameter substitution, HTML generation (MarkupCodec.transform)

Run them all at once:

./examples/run-all.sc

Frontend Toolkit demo

A reference SPA built entirely through the high-level Tk facade (layout + form-like fields + display widgets + theming). Compiles to all four frontend backends + static HTML via SSR.

# 1. Compile + test (frontend-toolkit 217 tests, frontend-examples 41)
sbt frontendToolkit/test frontendExamples/test

# 2. Generate 16 (4 demos x 4 backends) HTML+JS bundles
sbt "frontendExamples/runMain scalascript.frontend.examples.EmitAll"
#   → target/frontend-examples/toolkit-demo/{custom,react,solid,vue}/

# 3. Serve via the bundled ssc static-file server (no Python/Node)
ssc serve 8000 target/frontend-examples/toolkit-demo/react
# open http://localhost:8000/

Details: examples/frontend/README.md and docs/user-guide.md#16-frontend-toolkit. For SSR (Ssr.renderToHtml) and the full widget catalog see specs/frontend-toolkit-spec.md.

Benchmarks

Cold start (interpreter)

The interpreter uses lazy plugin loading (v1.33): the ServiceLoader scan for HTTP/SQL/OAuth/etc. plugins is deferred until the first plugin name is actually accessed. Scripts that never call a plugin skip the scan entirely.

Script Steady-state cold start
hello.ssc (no plugins) ~0.31 s
Script with HTTP/SQL/auth ~0.35 s (scan runs on first access)

Application Class-Data Sharing (AppCDS) is enabled in bin/ssc and the install.sh launcher (-XX:+AutoCreateSharedArchive, JDK 19+; the archive is auto-created on first run and auto-recreated on classpath change — no build step). It cuts a fresh ssc run hello.ssc from ~378 ms → ~182 ms (−51%) and peak RSS from 167 → 114 MB (−32%). Old JDKs ignore the flags; opt out with SSC_NO_CDS=1. Three real-workload-perf harnesses live under tests/perf/: coldstart/ (fresh-run wall-clock + RSS), serverrss/ (steady-state server RSS

  • leak detection — the interpreter server settles at ~195 MB with no climb), and GC-under-load.

Microbenchmarks (scripts/bench)

Everything benchmark-related goes through one wrapper:

scripts/bench interp                  # all interpreter microbenchmarks
scripts/bench interp recursionFib     # filter to one bench
scripts/bench cross                   # interp vs JS vs JVM (RuntimeBench)
scripts/bench off recursionFib        # prove the off-mode fall-back works
scripts/bench profile recursionFib    # JFR alloc + GC profile
scripts/bench wall                    # cross-language wall-clock (ssc/scala/node)
scripts/bench help                    # full command list

The canonical reference — what each bench measures, when to use it, how to add a new one — is docs/benchmarks.md.

Quick non-blocking smoke checks for perf-sensitive changes:

ssc bench --smoke               # corpus-driven CLI smoke
scripts/bench smoke             # one-iter JMH smoke (writes bench/jmh-smoke.json)

The checked-in workflow and baseline policy live in bench/perf-manifest.yaml and bench/README.md. Raw JMH/runtime outputs are ignored; only curated summaries should be promoted into tracked baseline files.

Watch reload benchmark

ssc watch-bench measures the same parse-cache, incremental typer, and interpreter reload path that ssc watch uses, but runs against a temporary copy so the source file is not modified:

ssc watch-bench --cycles 10 --target-ms 100 examples/rest-api.ssc
ssc watch-bench --cycles 10 --target-ms 100 --require-target examples/rest-api.ssc

The command reports warm-up, p50, and max cycle times. --require-target turns the target into a non-zero exit condition for local performance gates.

Running the tests

One command, before every push:

scripts/smoke-ci                # the pre-push suite, ~3-4 min
scripts/smoke-ci --list         # show what it runs, without running it

This is the same suite GitHub runs on the push (.github/workflows/smoke.yml executes this exact script), so a red locally is a red you were going to get anyway — earlier, and with the failing check named. Exit 0 is green; exit 1 means a check failed or the run exceeded its time budget. Output is per-check timings plus a per-module rollup, and the corpus slice's results are broken down by backend lane.

The runner itself is written in ScalaScript — scripts/smoke-ci.ssc, executed on the v2 native lane, so the compiler under test runs the suite. That file's header explains what is in the suite and why each check earns its place; adding a check means editing it.

It refuses to run against a launcher built from different sources than your working tree and tells you to ./install.sh --dev, because a verdict from a stale toolchain is a verdict about the wrong code. Useful knobs:

SSC_SMOKE_BUDGET=<seconds> raise the time budget (default 420)
SSC_SMOKE_ALLOW_STALE=1 skip the toolchain freshness check, for a deliberate A/B

The full suite, on demand, is scripts/full-ci (needs yq). It reads its steps straight out of .github/workflows/ci.yml rather than keeping a copy, so it cannot drift from what CI does:

scripts/full-ci                 # every job, in workflow order
scripts/full-ci validate        # one job
scripts/full-ci --list          # the plan, without running it

On GitHub, smoke.yml runs on every push; the full ci.yml runs on pull requests, on a 4-hourly schedule, and on demand (gh workflow run ci.yml --ref main). Check a verdict with scripts/ci-status --sha <sha>.

The sections below cover the individual suites the two runners are built from.

End-to-end smoke

e2e/rest-smoke.sc boots examples/rest-api.ssc through each of the three backends in turn and diffs their HTTP responses — guards against drift between the interpreter / JVM / JS serve runtimes.

scala-cli e2e/rest-smoke.sc

Conformance Suite

Cross-backend tests that verify JVM interpreter and JS transpiler produce identical output.

Run through the RAM-bounded wrapper (recommended) — it bounds how many conformance runs execute at once host-wide and caps the child JVM heap, so parallel worktrees don't saturate the machine (see specs/conformance-perf.md):

scripts/conformance                 # recommended (guarded); forwards args to run.sc
# or, unguarded:
scala-cli conformance/run.sc
Test What it covers
arithmetic Integer and floating-point ops, math.*
strings String methods and interpolation
collections List — map, filter, fold, take, drop, …
option Optionmap, getOrElse, filter, …
pattern-matching Literals, guards, Option, tuple patterns
case-classes Case class construction, field access, pattern matching
for-comprehensions yield, guards, nested generators, do
higher-order-functions Lambdas, compose, flatMap, eta-expansion
recursion Factorial and Fibonacci
tail-recursion Self-TCO at depth 100 000 — sum, countdown
mutual-recursion Mutual TCO — isEven/isOdd at depth 100 000
sealed-traits ADT hierarchy with sealed trait + case class
variables var mutation and while loops
tuples Tuple construction, _1/_2/_3, destructuring
maps Mapsize, getOrElse, contains, keys, values
list-companion List.fill, List.tabulate, List.range
modules [name](./path.ssc) imports — bind definitions from another file
effects Algebraic effects: Console routing, Choose nondeterminism, Fail early-return
std-effects Logger, Random, Clock, State, Env standard effects with default + test handlers
async Built-in Async effect — runAsync drives async / await / parallel / delay
async-parallel runAsyncParallel — real-thread Async on JVM
storage Built-in Storage effect — get / put / remove / has / keys via ephemeral or file-backed handler
direct Direct-syntax do-notation: direct[M], .! bind, pure lift, control flow
coroutines Lazy two-way coroutineCreate / coroutineResume / suspend, terminal Step[Y,T], nesting, and coroutineCancel
generators generator[T] { () => suspend(v) }, lazy map / filter / take / drop / flatMap / zip pipelines
streams Source[A] / Sink[A] / Flow[A, B], stream { emit(x) }, bounded buffers, overflow strategies, wall-clock throttle/debounce, live Source.signal, and sig.bind(source)
signals Reactive Signal / computed / effect with diamond-dedup flush
lenses Native .copy, Focus[T](_.a.b/.some/.each), and Prism[Sum, Variant] — get / set / modify / compose
prisms Prism[Sum, Variant] — getOption / set / modify on enum / sealed-trait cases
optional Focus[T](_.maybe.some.field) — Optional optic with getOption / set / modify / andThen
traversal Focus[T](_.items.each.field) — Traversal with getAll / modify / set / andThen
actors spawn / send / receive / supervision / link / exit
actors-dist Distributed actor cluster, WS transport, gossip, leader election
mcp MCP server tools + resources; MCP client callTool
dataset Dataset[T] local sequential, parallel, distributed MapReduce
dsl Parser combinators, error recovery, indentation-aware, multi-pass pipeline
metaprogramming inline, derives, compiletime.*, restricted quoted macro link/interpreter expansion (partial), compiler-free product Mirror.Of[T] custom derives
checked-errors throws[A, E], attemptCatch, HasStackTrace
websocket onWebSocket, ws.send/recv, rate limiting, wss://
tls tls(cert, key), HTTPS, WSS

Backends

ScalaScript supports the following bundled backends, all loaded through the Backend SPI plugin architecture (specs/backend-spi.md):

Command Backend id How it works
bin/ssc file.ssc / ssc run file.ssc v2 Default self-hosted frontend/checker → CoreIR → v2 VM. --bytecode selects direct ASM; program args use ssc run file.ssc -- [args...]. There is no compatibility fallback.
ssc run --native file.ssc v2-native Idempotent assertion of the same standard ScalaScript 2.1 path: structural CoreIR + Frontmatter YAML + Markdown Profile → v2 VM, with no host Markdown/front-matter parser and no Scala CLI/scalac/javac process. --native --bytecode selects direct ASM; unresolved runtime dispatch/effects fail instead of printing Stub/Op.
ssc-tools run --compat-frontend file.ssc / ssc-tools run --v1 file.ssc int Explicit optional Scalameta/v1 compatibility paths. Plain ssc rejects these flags and names ssc-tools.
ssc-tools run --target jvm file.ssc jvm Compile via JvmGen → temp .scscala-cli run. True JVM semantics, no artifacts left on disk. Requires scala-cli.
ssc-tools run-jvm file.ssc jvm Alias for ssc-tools run --target jvm (kept for backward compatibility)
ssc-tools run-js file.ssc js Compile via JsGen → temp .jsnode. True Node.js semantics, no artifacts left on disk. Requires node.
ssc-tools run-js --v2 file.ssc [args...] v2-js Explicit tools-tier v2 JS lane: FrontendBridge → CoreIR → v2 JsGen → temp .cjsnode.
bin/jssc file.ssc js Alias for ssc run-js via bin/ wrapper
bin/sscc file.ssc jvm Alias for ssc run-jvm via bin/ wrapper
ssc emit-openapi file.ssc openapi Headless interpreter dry-run that exports registered routes as OpenAPI 3.1 JSON or YAML. Flags: --format json|yaml, -o, --title, --version, repeatable --server.
ssc emit-spa file.ssc scalajs-spa Self-contained SPA HTML + JS bundle
bin/ssc-spark file.ssc spark Apache Spark 4 — generates a Scala 3.7.1 .sc script with //> using dep directives, runs via scala-cli. Auto-detects sql blocks, @SqlFn UDFs, readStream/writeStream, .format("delta"), @TempView, MLlib imports. See §13 of the User Guide.
ssc emit-wasm file.ssc / examples/run-wasm.sh wasm WebAssembly module — scalascript/ssc blocks lowered to Wasm IR. Cross-backend sql fenced blocks supported (v1.27 Phase 5).
ssc-native (GraalVM) native No-JVM ssc binary; plugins via ssc-plugin-host.jar subprocess bridge
(sub-backend) node Node.js runtime variant of js — emits server-side JS with fs/path shims and a cross-backend SQL runtime (v1.27 Phase 4).
(sub-backends) frontend-{react,vue,solid,custom} Frontend Framework SPI (v1.18 Phase A): same .ssc UI source compiled to React (useState/useEffect), Vue 3 (ref/render), Solid (createSignal/createEffect), or a minimal custom runtime — ShowSignal/ToggleSignal/ForSignal reactive primitives shared across all four. See specs/frontend-framework-spi-plan.md.
JVM desktop sub-backend frontend-swing Partially implemented JDK-only JVM desktop frontend. It provides SPI discovery, ssc run-jvm --frontend swing, Swing source emission for text/buttons/fields/toggles/stacks/spacers/dividers/scroll views, basic style hints, local signal actions, Swing fetchAction / dataTable / typed route client dispatch through generated JVM BackendTransport, no-socket full-stack examples, and a swing-plugin skeleton for future interpreter intrinsics; JavaFX/Compose adapters remain planned. See specs/jvm-desktop-frontend.md.

The Backend trait + ServiceLoader discovery let third parties add their own backend without touching core — drop a JAR and attach it via ssc --plugin path/to/your-backend.jar. See docs/writing-a-backend.md and the worked samples under examples/plugins/.

Useful flags:

ssc --list-backends                 # list every visible backend
ssc --list-source-languages         # list registered SourceLanguage plugins
ssc --describe-backend jvm          # capabilities + intrinsics + sources
ssc --backend js run file.ssc       # override the per-command default

Built-in fenced languages are SourceLanguage plugins too: scala, html, css, javascript/js, xml, bind-aware sql, and bind-aware transaction are visible through --list-source-languages. Third-party DSLs follow the same path.

The JavaScript backend handles both block types with the same custom JS transpiler (JsGen) today:

  • scalascript blocks — transpiled by JsGen, which supports ScalaScript-specific features (effects, content helpers, TCO, imports).
  • scala blocks — currently also transpiled by JsGen (parsed as the Scala-3 subset the engine supports), not compiled by real Scala.js. Output is byte-identical to a scalascript block, so Int is 64-bit on the conforming lanes (specs/numeric-widths.md) — the width follows the BACKEND, not the fence tag.

A real Scala.js route for scala blocks (via scala-cli --js, giving full Scala 3 fidelity and Scala's own 32-bit Int) exists only as unreachable, guarded scaffolding today — see specs/w5-int-width-findings.md. When it is wired up it will be a separately-widthed target, and the guard test tests/e2e/scala-fence-width-parity-smoke.sh will fail loudly the moment a scala block's output diverges from a scalascript block's, rather than let one word mean two widths silently.

Compiler Plugins with Intrinsics

A compiler plugin lets you extend ScalaScript with new native capabilities — cryptographic primitives, ML inference, GPU kernels, hardware I/O — by mapping extern def declarations in a .ssc source to platform-specific implementations.

// crypto.ssc  (shipped inside the .sscpkg)
extern def sha256(input: String): String
extern def hmacSha256(key: String, data: String): String

Call it from any .ssc file just like a normal function:

import [Crypto](crypto)

val digest = sha256("hello, world")
println(hmacSha256("secret", digest))

Each extern def maps to an IntrinsicImpl:

Variant When to use
NativeImpl(fn) Interpreter — call the JVM lambda directly
RuntimeCall(sym) JVM / JS codegen — emit sym(args…) and ship sym as a runtime helper
InlineCode(emit) Emit arbitrary target code at each call site
HostCallback(name) Out-of-process backends — route through the host wire protocol

Plugins are packaged as .sscpkg (a ZIP containing manifest.yaml, sources/*.ssc, runtime/jvm.scala + runtime/js.js, and an intrinsics/*.jar that registers a Backend via ServiceLoader):

ssc plugin pack  _pkg/   -o org.example.crypto-1.0.0.sscpkg
ssc plugin install      ./org.example.crypto-1.0.0.sscpkg   # permanent
ssc --plugin ./org.example.crypto-1.0.0.sscpkg run use-crypto.ssc  # ad-hoc

Installed distributions also include first-party advanced plugins locally under bin/lib/compiler/plugin-available; use --plugin with one of those .sscpkg files when you want opt-in capabilities without a registry domain.

See examples/plugins/crypto-plugin/ for a complete worked example and docs/user-guide.md §21 for the full API reference.

CLI Commands

ssc run file.ssc              # v2 VM default runner
ssc-tools run --v1 file.ssc   # explicit v1 tree-walking compatibility
ssc run --v2 file.ssc         # explicit v2 VM runner
ssc run --native file.ssc     # staged self-hosted frontend -> CoreIR -> v2 VM
ssc run --native --bytecode file.ssc # same native frontend -> direct ASM execution
ssc-tools run --compat-frontend file.ssc # explicit Scalameta bridge
ssc run file.ssc -- arg1 arg2 # pass program args to the v2 VM runner
ssc run --bytecode file.ssc -- arg1 arg2 # pass args to the v2 JVM bytecode lane
ssc-tools run --target jvm file.ssc # compile via JvmGen + run with scala-cli (no artifacts)
ssc-tools run-jvm file.ssc     # same as above (backward-compat alias)
ssc-tools run-js file.ssc      # compile via JsGen + run with node (no artifacts)
ssc-tools run-js --v2 file.ssc # explicit v2 CoreIR JS lane through node
ssc-tools watch file.ssc       # watch mode (re-run on change)
ssc-tools watch-bench file.ssc # benchmark watch reload cycles on a temp copy
ssc-tools bench --smoke        # quick interpreter-only benchmark wiring smoke
ssc-tools check file.ssc       # compatibility type-check only; exit 0=clean 1=type-err 2=parse-err 3=notfound
                              #   also warns on @ui=toolkit controls that reference an unregistered action/data-source id (declarative-ui B.7)
ssc check --json file.ssc     # structured JSON diagnostics
ssc check --quiet file.ssc    # no output, exit code only (for pre-commit hooks)
ssc check --watch file.ssc    # re-check on file change, Ctrl-C to stop
ssc check src/                # recursively check all *.ssc files in a directory
ssc repl                      # interactive REPL
ssc build myapp.ssc           # build project file → dist/ (--target ssc|jvm|js|web)
ssc build                     # auto-discover <dirname>.ssc or single .ssc in cwd
ssc build src/                # dir-walk mode (backward compat)
ssc package myapp.ssc         # build all targets: listed in frontmatter
ssc install [--prefix <dir>]  # install ssc to ~/.local (or custom prefix)
ssc compile-jvm file.ssc      # compile to .scjvm artifact
ssc compile-js file.ssc       # compile to .scjs artifact
ssc emit-interface file.ssc   # emit .scim interface
ssc emit-ir file.ssc          # emit .scir normalized IR
ssc link --backend jvm dir/   # link artifacts
ssc build --incremental dir/  # incremental build
ssc emit-js file.ssc          # transpile to JS
ssc emit-lib --host js|jvm|rust|java --feature optics -o dir/  # standalone host library (npm/jar/crate/maven)
ssc emit-spa file.ssc         # SPA HTML bundle
ssc emit-wc file.ssc          # Web Components bundle
ssc test file.ssc             # run tests
ssc preview file.ssc          # preview component variants
ssc deps file.ssc             # show import closure
ssc search json [--refresh|--offline]
ssc info io.scalascript/json [--registry <url>]
ssc add io.scalascript/json [<version>] [--file <manifest>]
ssc info artifact.scjvm       # inspect artifact
ssc plugin install/list/uninstall/check/pack/registry
ssc --list-backends / --describe-backend <id>
jssc file.ssc                 # JS transpiler runner
sscc file.ssc                 # JVM runner
ssc-spark file.ssc            # Apache Spark runner (Spark 4 + Scala 3.7.1)
ssc submit file.ssc           # spark-submit fat JAR (cluster deploy)
ssc --spark-master <url>      # override Spark master (local[*] / spark:// / yarn / k8s://)
ssc --spark-version <v>       # override Spark version (default 4.0.0)

Project Layout

bin/
  ssc          # interpreter launcher (tree-walking, no compilation step)
  jssc         # JS runner: transpiles .ssc → JS and runs via Node.js
  sscc         # JVM runner: compiles .ssc → Scala 3 → JVM via scala-cli
  ssc-js       # JS transpiler: emit JS to stdout, or --run to execute
  http.ssc     # HTTP server for examples browser

runtime/backend/spi/        # SPI traits (Backend, SourceLanguage, PluginRegistry, Capabilities, …)
runtime/scalascript-plugin-api/ # Stable plugin author API (PluginValue, PluginNative, capability traits)
v2/interop/descriptor/      # Target-neutral canonical API/control/artifact descriptors
ir/                         # IR types + JSON/MsgPack codecs
core/
  src/main/scala/scalascript/
    parser/    # Markdown + YAML + Scala parser
    typer/     # Type checker
    ast/       # AST types
    imports/   # Cross-file import resolver
    interpreter/Value.scala  # Computation Free monad (used by interpreter+codegens)
    transform/ # Normalize, DirectDesugar, EffectAnalysis
    plugin/    # PluginRegistry facade, BackendRegistry, SubprocessBackend, WireProtocol
runtime/backend/jvm/      # JvmGen — emits Scala 3 source
runtime/backend/js/       # JsGen — transpiles to JavaScript
runtime/backend/scalajs/  # ScalaJsBackend — emits SPA via Scala.js
runtime/backend/interpreter/
  src/main/scala/scalascript/
    interpreter/    # Tree-walking interpreter
    server/         # Built-in HTTP / WebSocket / Actor / MCP runtime
    bench/          # WsStress benchmark
runtime/runtime-server/common/      # Shared HTTP/WS server primitives (all backends)
mcp/common/                 # Shared MCP protocol types + codec
cli/                        # Main entry point (ssc command)

conformance/     # Cross-backend conformance test suite
  expected/      # Canonical expected outputs

examples/        # Runnable .ssc files
  run-all.sc     # Runs all examples in order
  plugins/       # Worked backend plugin examples

build.sbt        # sbt build — multi-module per spec §4.1
project/
  build.properties
  plugins.sbt    # sbt-assembly for fat-jar packaging

docs/            # Architecture, spec, design docs
  architecture.md        # Compiler pipeline and module structure
  backend-spi.md         # Backend SPI design (source of truth)
  direct-syntax.md       # Direct do-notation (v1.8+)
  coroutines.md          # Coroutine primitive (v1.9+)
  dsl.md                 # DSL authoring and parser combinators (v1.20)
  mapreduce.md           # Dataset / MapReduce API (v1.21–1.22)
  mcp.md                 # MCP server + client (v1.17)
  actors-dist.md         # Distributed actors design
  metaprogramming.md     # inline/derives (v1.14)
  error-handling.md      # Checked errors / throws (v1.15)
  modularity.md          # Package system and separate compilation
  markdown-as-syntax.md  # Markdown as Syntax design
  targets.md             # Target Backends
  user-guide.md          # Practical user reference
  tutorial.md            # Step-by-step todo-list application tutorial
tools/scripts/         # launchers/ and validate-frontmatter.scala

Installing as a Binary

# Install scala-cli first (if needed)
./setup.sh

# Build ssc into bin/
./install.sh --dev

After installation:

ssc examples/hello.ssc
jssc examples/hello.ssc
sscc examples/hello.ssc

Library Usage (sbt)

ScalaScript can be used as a Scala 3 library via sbt:

sbt compile      # compile all modules
sbt test         # run unit tests
sbt cli/assembly # produce a self-contained ssc.jar
sbt cli/installBin # stage bin/lib so bin/ssc works from the checkout

The public API surface:

import scalascript.parser.Parser
import scalascript.interpreter.Interpreter
import scalascript.codegen.{JsGen, JvmGen}

val module = Parser.parse(source)            // parse a .ssc file
Interpreter.run(module)                      // interpret
val js    = JsGen.generate(module)           // emit JavaScript
val scala = JvmGen.generate(module)          // emit Scala 3 script

The target-neutral descriptor leaf is the sbt project v2InteropDescriptor at v2/interop/descriptor; its Maven coordinate is io.scalascript:scalascript-interop-descriptor_3. The scalascript.interop.descriptor package exposes bounded canonical codecs and checked factories. Slice A supplies infrastructure only: compiler/linker producers and runtime/admission consumers remain deferred.

Plugin dependency identity and admission live in sbt project v2PluginCapabilityProfile at v2/interop/plugin-profile, published as io.scalascript:scalascript-plugin-profile_3. The scalascript.interop.plugin package exposes checked declaration/implementation binding, one aggregate DependencyKind.Plugin projection, and pure inventory validation. ssc.plugin.NativePlugin.capabilityDeclaration is an optional JVM adapter; legacy providers keep the concrete None default. Automatic .sscpkg carriers and linker population remain deferred.

ScalaScript libraries can also be packaged as .ssclib archives:

ssc package --lib --precompile --manifest ssclib-manifest.yaml -o dist/my-lib.ssclib
ssc check-compat dist/my-lib-1.0.ssclib dist/my-lib-1.1.ssclib

--precompile embeds .scim public interface artifacts under ir/. check-compat reports removed or changed public symbols between library versions and falls back to deriving interfaces from packaged sources when a library has no precompiled interface artifacts.

Design Principles

  1. Reuse, don't invent. Markdown, YAML, Scala 3 — use what works.
  2. One source, many targets. Source semantics are target-independent.
  3. Human and machine readable. Pleasant for humans, trivially parseable for machines.
  4. No AI at runtime or compile time. The language stands on its own.

License

Apache License 2.0

Author

Sergiy (Victorovych) Shcherbyna sergey.scherbina@gmail.com

About

Literate Scala 3 in Markdown. One .ssc source runs on a tree-walking interpreter, transpiles to JavaScript, compiles to the JVM, emits a native Rust binary, or targets WebAssembly. Algebraic effects, typeclasses, reactive UI, and a native reactive web server — pick the backend at build time.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages