01 — Architecture Overview

The compiler is a demand-driven, incremental query engine (salsa), not a batch pipeline. Everything downstream of source text is a query whose result is memoised and automatically recomputed when its inputs change. The CLI and the LSP are two front-ends over the same query database — the LSP is not a special case, it is the query engine with a different driver.

This shape is the direct answer to laws L1 (no globals — the db is the state), L2 (incremental for free), and L5 (queries compose along an explicit DAG).

Implementation status — the salsa engine IS the running engine. This banner used to say the opposite ("not yet the running engine … a spike with one input and one tracked query, line_count"), and it was badly out of date: line_count is gone, and the real build driver constructs skydb::SkyDatabase (rust/crates/project/src/build.rs:124) and demands skydb::go_program (:419) to produce the emitted Go — replacing the eager lower_program_cfg + emit_program pair it used to call directly.

skydb (rust/crates/skydb/src/lib.rs) is a real salsa 0.28 database with #[salsa::input]s (SourceFile, BuildConfig) and these tracked queries spanning the whole DAG:

QueryWhereGrain
parseskydb:482per SourceFile
module_exportsskydb:126per module
resolve_queryskydb:181per module
type_world_query / check_world_queryskydb:202 / :224whole program
record_result_sig_query / callsite_param_records_queryskydb:243 / :272whole program
infer_queryskydb:304per DefId
go_programskydb:434whole program

Two things below are still not what the code does, and are called out where they appear rather than blanket-disclaimed here:

The hand-rolled hir::db::SourceDb (rust/crates/hir/src/db.rs) still exists as a second backend with identical ModuleId semantics, and its RefCell exports cache is gone (db.rs:61). Remaining engine work is tracked in 12.

Data flow (target: all edges are salsa queries)

flowchart TD
    subgraph Inputs["Inputs (set by the driver)"]
      SRC["source_text(FileId)"]
      TOML["sky_toml / project config"]
      FFI["ffi_surface (pinned, deterministic)"]
    end
    SRC --> CST["parse(FileId) -> Lossless CST + parse diagnostics"]
    CST --> AST["ast(FileId) -> typed AST view (rowan)"]
    AST --> ITEMS["module_items(FileId) -> declarations, exports"]
    ITEMS --> RES["resolve(ModuleId) -> names -> DefId (imports, scopes)"]
    TOML --> GRAPH["module_graph(project) -> topo order"]
    ITEMS --> GRAPH
    RES --> INFER["infer(DefId) -> types, per-region type map, diagnostics"]
    FFI --> INFER
    INFER --> EXH["exhaustiveness(DefId) -> diagnostics"]
    INFER --> HIR2["typed_hir(DefId) -> lowering IR (typed)"]
    HIR2 --> GO["go_module(ModuleId) -> deterministic Go source"]
    GO --> WRITE["build(project) -> write sky-out/, run go build"]

    RES -. LSP .-> HOVER["hover / goto / completion / diagnostics"]
    INFER -. LSP .-> HOVER

The interner is the spine (L3)

Everything with identity is an integer id, allocated in an arena, compared by == on the int:

Interned thingIdReplaces (Haskell)
File pathFileIdad-hoc FilePath keys
Module nameModuleIdModuleName.Canonical
Definition (top-level/local)DefIdname-string map keys
Symbol nameName (interned str)String everywhere
TypeTy (interned)T.Type + structural Eq
Type variableTyVarId (arena)UF.Point pointer identity ← the one real typechecker design task, solved for free
Source spanSpan { FileId, TextRange }A.Region

Interning gives three wins at once (L3): O(1) identity comparison, arena allocation (no GC pressure, predictable memory — the user's TCO/memory concern), and deterministic iteration when you walk ids in allocation order (L4).

Controlled mutation, not purity theatre and not IORef soup

Haskell forced a false choice: pure-threading (verbose) or IORef globals (untraceable). Rust's idiom is the middle path the compiler actually wants:

Diagnostics as data (L7, L8)

Determinism, end to end (L4)

The Go backend stays (L10, L9)

The compiler still emits Go and reuses the existing runtime-go/rt runtime (goroutine-backed Tasks, the deploy story, SkyDeploy). The rewrite fixes the lowering — a typed IR with a well-specified type system so coercion is the rare, explicit exception rather than a pervasive rt.Coerce residual surface (L9). See 07 + 08.

Why this specifically fixes the AI-velocity problem