soundscript is a sound checker and language tooling layer for TypeScript projects.
Prebuilt macOS, Linux, and Windows CLI downloads are attached to GitHub releases.
The intended stable v1 surface is the checker, mixed .ts / .sts adoption story, the VS Code
extension, a very small stdlib, and a narrow macro surface. Broader macro work and Wasm remain
experimental.
For the fastest orientation on the builtin surface and the recommended coding patterns, see docs/reference/builtin-modules.md and docs/guides/idiomatic-soundscript.md and docs/guides/common-rewrites.md.
It adds a second file type, .sts, for code checked under a stricter rule set. Ordinary .ts files
keep normal TypeScript behavior. The goal is incremental adoption: move the parts of a codebase you
care about into .sts, keep the rest as .ts, and make interop explicit.
The release-facing v1 surface is:
.stsfor sound code- mixed
.ts/.stsprojects soundscript check- LSP support
- import-scoped macro authoring through the compiler-provided
sts:macrosbuiltin module- user-authored macro modules are
.macro.stscompile-time plugin modules, not ordinary.sts,.ts, or.jsscripts
- user-authored macro modules are
- compiler-owned builtin modules under
sts:*, with the stable v1 surface centered onsts:prelude,sts:result,sts:match,sts:failures,sts:url,sts:fetch,sts:text,sts:random,sts:json,sts:compare,sts:hash,sts:decode,sts:encode,sts:codec,sts:derive,sts:async,sts:hkt,sts:typeclasses, andsts:macros - the canonical runtime/toolchain npm package
@soundscript/soundscript, with emitted runtime and TS interop imports under@soundscript/soundscript/*
This repository also contains broader implemented experimental work beyond the stable v1 contract.
That includes the soundscript compile path, experimental builtin surfaces such as sts:numerics,
sts:value, and sts:experimental/*, #[newtype] and #[value], proof and framework macros like
#sql, #css, #graphql, and #component, and the broader public Wasm target/runtime matrix
work. Those surfaces exist in the repo, but they are not the stable release-facing v1 contract.
Build the CLI:
deno task build
./bin/soundscript --helpStart a new project:
./bin/soundscript init
./bin/soundscript checkThat creates src/main.sts and a tsconfig.json that includes both src/**/*.ts and
src/**/*.sts.
Add soundscript to an existing TypeScript project:
./bin/soundscript init --mode existing
./bin/soundscript check --project tsconfig.soundscript.jsonThat creates a tsconfig.soundscript.json overlay so you can start adding .sts files without
rewriting the rest of the project.
For CI or tooling:
./bin/soundscript check --project tsconfig.soundscript.json --format json
./bin/soundscript check --project tsconfig.soundscript.json --format ndjson
./bin/soundscript deno run src/main.sts
./bin/soundscript explain SOUND1002For local Node execution, use @soundscript/register:
node --import @soundscript/register src/main.stsYou can also opt selected .ts / .tsx / .mts / .cts files into local soundscript behavior
without renaming them:
{
"soundscript": {
"include": ["src/**/*.ts", "src/**/*.tsx"]
}
}@soundscript/register and soundscript deno expect @soundscript/soundscript to be installed in
the current project or an ancestor workspace, because the transformed graph imports the runtime
package.
For published libraries, the intended package shape is:
- ordinary ESM
js + d.tsfor TypeScript and runtime consumers - shipped authored
.stssource underpackage.json#soundscript.exports soundscript buildas the canonical package emit flow@soundscript/registerandsoundscript denoas local runtime wrappers for mixed.ts/.stsapps- explicit adapter packages for local source-driven apps and bundlers:
@soundscript/register,@soundscript/bun-plugin,@soundscript/vite, and@soundscript/webpack-loader - source maps back to original
.stsso stack traces and debuggers stay on authored source
The repository split is now:
soundscriptfor the checker, CLI, LSP, runtime package, and generic project-transform support used by first-party adapterswebsitefor the public docs site and mirrored reference pagesadaptersfor the explicit adapter packages and their host-specific implementationseditorsfor editor clients such as the VS Code extension and@soundscript/tsserver-plugin
The public website and docs now live in the standalone website repository: soundscript-lang/website.
The leaf adapter packages are no longer vendored in this repo. Use the standalone adapters repository: soundscript-lang/adapters.
The editor packages are no longer vendored in this repo. Use the standalone editors repository: soundscript-lang/editors.
For package emit:
./bin/soundscript build --project tsconfig.soundscript.jsonThe intended platform design is Deno-inspired:
- prefer Web-standard APIs first
- keep stdlib modules small and composable
- expose portable globals and leaf modules such as
fetch,URL, and text encoding where the current runtime supports them - keep host-specific behavior behind explicit wrappers instead of promising extra stable runtime modules
This package model is designed for external macro-authored libraries and frameworks. The soundscript repo keeps only small generic fixture coverage for packaged macro resolution and runtime materialization; framework implementations now live in their own repositories.
Exit codes are:
0for success with no blocking diagnostics1for project diagnostics or unsupported-code findings2for CLI usage, project setup/configuration failures, or unexpected internal tool errors
The canonical release version comes from src/cli/cli.ts.
For a normal public release, bump VERSION there, push main, then run the Publish Release
GitHub Actions workflow. It will:
- run the release checks
- prepare and publish the npm package set
- create and push the
v<version>tag - create the GitHub release
- attach the platform CLI archives plus checksums
The workflow is set up for npm trusted publishing from GitHub Actions. npm must be configured to
trust the publish-release.yml workflow file in this repository for every package in the release
set:
@soundscript/cli-darwin-arm64@soundscript/cli-darwin-x64@soundscript/cli-linux-arm64@soundscript/cli-linux-x64@soundscript/cli-win32-x64@soundscript/soundscriptsoundscript
If npm returns a 404 during npm publish, the usual cause is that the package's trusted-publisher
settings have not been added yet. The workflow also needs GitHub's id-token: write permission,
which is already configured in the workflow file.
You can bulk-configure the package set from a shell after logging in to npm with an account that has write access to all seven packages:
for package in \
@soundscript/cli-darwin-arm64 \
@soundscript/cli-darwin-x64 \
@soundscript/cli-linux-arm64 \
@soundscript/cli-linux-x64 \
@soundscript/cli-win32-x64 \
@soundscript/soundscript \
soundscript
do
npm trust github "$package" \
--repo soundscript-lang/soundscript \
--file publish-release.yml \
--yes
sleep 2
doneIf you need to reattach CLI archives to an existing release, use the separate Backfill CLI Assets
workflow.
.sts files are checked in soundscript.
.ts files are left alone.
When .sts code imports ordinary TypeScript, JavaScript, or declaration-only packages, the import
needs // #[interop]:
// #[interop]
import { readConfig } from './legacy.ts';From the other direction, .ts can import .sts without any annotation. It sees a projected public
TypeScript surface for the .sts module.
That is the adoption model. Existing TypeScript stays where it is. New or critical code can move
into .sts.
soundscript removes a large set of TypeScript unsoundness paths, but it still lives inside JS/TS runtime semantics. The main remaining rough edges are:
nullvsundefined, especially at JSON, regex, and trusted-interop boundaries- arbitrary foreign throws and rejections; expansion-enabled source normalizes
catch (error)and built-in Promise rejection handlers to plainError, but other boundaries still require explicit normalization such assts:failures.normalizeThrown(...) - stable v1 still defaults to ordinary JS
numberbehavior, includingNaN,Infinity, and-0; the repo also contains experimental machine numerics work understs:numerics, but that is outside the stable v1 contract - stable v1 still relies heavily on structural typing for same-shape interface and object values;
class nominality plus
#[newtype]and#[value]exist in the repo, but the broader nominal and value-semantics story remains outside the stable v1 contract - there is no active effort to remove raw
nullfrom the language; it remains part of the honest platform model
The release-facing contract for those boundaries is in docs/reference/v1-user-contract.md.
// src/math.sts
export function area(radius: number): number {
return Math.PI * radius * radius;
}
const raw = JSON.parse('{"radius": 3}');
if (
typeof raw === 'object' &&
raw !== null &&
'radius' in raw &&
typeof raw.radius === 'number'
) {
console.log(area(raw.radius));
}There is no new syntax here. The difference is the checker.
The main commands are:
soundscript initsoundscript checksoundscript buildsoundscript expandsoundscript denosoundscript explainsoundscript lsp
The repo also ships soundscript compile. compile and the broader compiler / Wasm surface remain
experimental; the checker is still the main entry point.
The language server runs over stdio:
soundscript lspThere is also a VS Code client in the separate editors repo:
git clone https://github.com/soundscript-lang/editors.git ../editors
cd ../editors/packages/vscode
npm install
npm run compileThen:
- open the
editorsrepo root in VS Code - run the
Run soundscript extensionlaunch configuration - in the spawned Extension Development Host, use
File -> Open Folder...to open the workspace you want to test, for examplesoundscript-example - open an
.stsfile to confirm thesoundscriptlanguage mode and TextMate grammar are active
Notes:
- the VS Code extension and
@soundscript/tsserver-pluginlive in soundscript-lang/editors - work from
../editors/packages/vscodewhen developing the extension locally - the extension prefers a workspace-installed
soundscriptbinary and falls back to PATH unless you overridesoundscript.server.command soundscript.server.*settings only configure how the already-loaded extension launches the language server; those settings do not make VS Code discover the extension- custom grammar-based syntax highlighting currently applies only to
.sts;.tsand.tsxuse the built-in TypeScript grammar and only pick up LSP features from soundscript
Current LSP support includes diagnostics, hover, signature help, definition, references, rename, completions, document symbols, formatting, semantic tokens, and code actions / quick fixes.
The repo also contains:
- checker and CLI
.ts/.stsinterop- LSP
- macro work
- compiler / Wasm work
You do not need macros or Wasm to use soundscript as a checker.
The maintainer toolchain is Deno:
deno task build
deno task check
deno task fmt
deno task lint
deno task test
deno task verifyStart here:
