The geastack TypeScript-to-C++ compiler.

It is a clean-room rewrite. The design goal is the second constraint below: a statically typed value that reaches a dynamic carrier is a defect. The earlier implementation could not be driven to zero of them, because boxing was load-bearing in its emitter and removing it anywhere broke it somewhere else. Starting from a tree where the carrier algebra is closed and fail-closed from the first commit is what makes "no boxing" a property rather than an aspiration.

See docs/ARCHITECTURE.md for the pipeline, the layering

and the constraints, and CLAUDE.md for the code conventions.

identity/ canonical IDs

semantics/ the target-neutral frontend: regions, structural types,

operations, edges, coverage. The frontend/backend boundary.

representation/ physical carriers, the sealed plan, and fail-closed guards

conversion/ the closed dynamic-conversion capability algebra

preflight/ whole-pipeline capability census and certificate

ir/ typed IR: verified operations and SSA values

targets/cpp/ emission; consumes typed IR only

diagnostics/ authority-component sweep, deterministic ordering

Nothing after semantics/ may import typescript or touch a TypeScript AST.

That boundary is what stops two layers from answering the same question

differently.

- No source-shaped authority. No decision may depend on a file name,

path, source offset, .pos/.end/getStart()compared to a literal, source text, declaration or local spelling, statement layout, or generated C++ text. Identity is a checker symbol/declaration, a sealed semantic ID, or a versioned protocol identity.

- No boxing. A value with a static type never gets the dynamic carrier.

Representation.dynamicis admissible only for the four declaredDynamicReasonvalues insrc/representation/model.ts.

- Fail closed. A guard firing is always correct; the defect is upstream.

Never relax a guard, never downgrade an unresolved, never default when a fact is missing.unresolvedis lattice bottom, not an answer.

scripts/architecture.mjs enforces the layering over src/**/*.ts: file and

directory size maximums, and zero-tolerance checks for RegExp literals under

src/targets/cpp/, source-position literal comparisons, typescript imports

outside src/semantics/, source-shaped discriminants, unclassified

Authority/Admission/Proof contracts, class declarations under

src/targets/, and any. It collects every violation before failing, so one

run reports everything wrong rather than one thing at a time.

node dist/cli.js test/fixtures/spread.tsruns the whole pipeline and prints the complete diagnostic set — never a top-N —

exiting non-zero when no capability certificate was minted. Add --preflight for

the full obligation census as canonical NDJSON.

node dist/cli.js coverage app/index.ts --plugin ../node-compat/plugin/v2.mjsanswers the porting question the diagnostics do not: which lines of my file are the problem, and what kind of problem is each? It joins every layer's outcome by source position and prints one row per statement with a stable code, a status and a one-line reason, then a summary and a by-code count. A carrier that BOXED is a row too -- the program compiles and runs slower than it says, and no other view places that on a line. Exit 0 iff a certificate was minted and nothing refused at lowering or emission.

The trailing digits index fixed tables in src/cli-coverage.ts, never a hash

of a message, so rewording a diagnostic keeps its code; x999 means the table

lacks a row. Options: --project/--no-project, --plugin, --plugin-option,

--json (rows + summary as one object), --no-derived (roots only),

--no-boxed (refusals only).

node scripts/probe-carriers.mjs test/fixtures/language.tsprints the carrier and C++ spelling selected for every declaration, and counts unresolved and boxed carriers. It is the view of the structural mapper and carrier selection, which nothing else exercises directly.

node dist/cli.js compile app/index.ts --out-dir build/generatedis the command the gea build pipeline drives (build-gea-vite-geatsc.mjs

passes it through --geatsc-bin). It writes the C++ into --out-dir together

with gea_runtime.h, generated_support.hpp, whatever the installed hosts

require beside the unit, geatsc-sources.txt -- the list of .cpp files the

build compiles -- and, for the per-file layout, geatsc-header.txt naming the

shared header the build should precompile. Options:

compile-module-graph <gea-module-graph.json> --entry <file> is the same

command over vite's module graph instead of files on disk, and is the path every

real application build takes; it accepts the same options.

Apache-2.0 (see LICENSE), the compiler and the runtime it combines into

generated programs alike. Programs you compile with geatsc are yours; their

license is decided only by what they link. The GeaStack framework and the

desktop, mobile and web targets are Apache-2.0 as well; the embedded board

support (targets, @geastack/chips) is GPL-3.0-only and needs a commercial

license for closed-source firmware. Contact contact@geastack.com for commercial terms.