Skip to content

Incan 0.6 — in development

Development release note. Incan 0.6 has not shipped. This page records the release contract and the user-facing direction of the active development line; the tagged release note will distinguish delivered behavior from work that was deferred or explicitly migrated.

The release in one sentence

0.6 makes Incan's own compiler facts and Oven project model the normal authority for compilation, packages, build artifacts, and inspection—so generated Rust is an optional projection, not the semantic handoff.

Why this release exists

0.5 established compiler-owned foundations, checked project boundaries, and the first Oven Alpha evidence. It still retains generated Rust in the normal backend path and leaves Cargo-shaped build behavior too close to the centre of the system.

0.6 is the architectural cutover. Its purpose is not to rewrite every compiler component in Incan immediately. It is to put Incan in a position where large parts of its internals can begin moving into Incan source deliberately, while Rust stays a bounded host capability rather than a second semantic authority.

Features and enhancements — in development

The compiler owns source meaning end to end

The replacement backend will consume direct, compiler-owned lowering facts through Body IR. Backend selection and execution will be explicit and receipted, with no silent fallback to the legacy route. A corpus-based parity system will show which behavior is verified, which is intentionally migrated, and which is not yet acceptable.

  • Packages: Library builds publish versioned executable content for covered public declarations. Replacement consumers execute supported calls through package aliases and facades without producer source, using the original declaring identities and selected public type context. Missing, incompatible and uncovered requirements refuse before output or a new execution receipt. Native linking remains available for packages without executable coverage. (#1339)
  • Tooling: incan inspect representation reports a published package's executable-representation version and the coverage it declares for each public declaration, with refusals carrying their stable reason. A package that publishes none, and a representation this build cannot interpret, are both reported rather than refused. (#1339)
  • Packages: .incnlib manifests carry anonymous union types in checked signatures, and declare manifest format 4. A reader without support for the new type reference refuses the manifest by format number rather than failing to parse it, so an artifact from a newer compiler names the reason it cannot be read. Comment- and order-preserving manifest editing is unaffected. (#1339, #1453)
  • Standard library: std.toml reads typed manifest values and declared models, reports source locations for parse and structural errors, and writes generated lock documents while retaining TOML date/time kinds. Comment- and order-preserving manifest editing remains deferred. (#1409)
  • Tooling: A direct-rustc store entry retains the complete receipt of the compilation that produced its bytes, admitted against the entry's own receipt, build unit and intent, and re-checked whenever a held payload is revalidated. incan oven store inspect reports it, so a reused artifact can say what made it rather than only naming a receipt. (#1037)
  • Tooling: A consumer of an admitted Incan package no longer needs the producer's private Rust path sources to resolve it: the package is identified by its sealed artifact, never by walking the producer's private Cargo edges. An explicit bake of a consumer that declares no registry roots of its own composes the provider's sealed closure and links it once. The one shape that still refuses is a diamond over two sealed providers that each compiled the same shared registry unit: Oven names the crate and the collision at its own boundary, never falling back to Cargo, until #1241 reconciles shared units to one compiled artifact. (#1469)
  • Tooling: A package diamond that names one provider under one alias from both sides links it once instead of refusing a duplicate extern. (#1459)
  • Tooling: An explicit bake treats a cached output whose release Loaf the active toolchain no longer ships as a cache miss and rebakes; a consumer facing project extensions from two retained families selects the one whose base the toolchain still ships. (#1444)
  • Tooling: A normal incan build, run, or test never launches Cargo. The two remaining silent detours — an executable whose caller-owned provider resolved a shared registry package to a different compiled artifact than the project's own closure, and a library whose assembled closure rustc could not load — are now refusals. The first names the package and the provider artifact that pins it; the second names the library and rustc's crate-loading report, including a StableCrateId collision, which carries no error code. Both point at the Oven-native reconciliation still owed (#1241). (#1141)
  • Tooling: Two large interop projects can share one Oven home. An explicit bake reserves a 4 GiB staging floor before it runs, reclaiming inactive store entries oldest-first to reach it instead of failing with a demand to prune by hand, and prints a note: naming what it reclaimed; entries under a live lease are never touched. The everyday store policy grows to 12 GiB aggregate and per-domain physical allocation so a Bevy-scale and an IncQL-scale project coexist instead of evicting each other. (#1230)
  • Tooling: Editing a baked project no longer stops incan build and incan run with a demand to bake again. The sealed project output is set aside with one warning and the edit compiles from source against the dependency closure the bake published; reverting the edit picks the sealed output back up. (#1141)
  • Tooling: A no-change incan build on a starter project went from 529 ms to 357 ms on the reference machine, and a cold one from 721 ms to 582 ms: Loaf selection materializes only the candidate it picks instead of every compatible family, the compiler is probed once per process with rustc -vV instead of twice, and a packaged provider's sealed digest is served from a tree-stamp memo. incan build --report json now attributes every preparation step under timings_ms. (#1111, #1556)
  • Tooling: A sealed closure's shape check is written down once. Every command that selected the standard-library Loaf re-checked its 9,500 files for presence, regularity and containment; the first command now records a closure proof beside the Loaf envelope (or the Oven store, for a leased project plan) and later ones read that record. Warm no-change build 357 → 277 ms, cold 582 → 416 ms on the reference machine. incan inspect oven still rehashes what it audits. (#1546)
  • Tooling: Oven validates caller-owned native output bytes against the digest recorded after compilation before reusing them. Changed outputs and old or malformed reuse evidence trigger a rebuild. (#1463)
  • Tooling: Native package imports read published Oven stores without changing access bookkeeping or cache files inside the package artifact. This keeps recorded dependency digests stable during import while retaining ordinary consumer-store reuse. (#1458)
  • Compiler: Generated Rust accepts a released stdlib within the declared compatibility range, including a patch release after a prerelease requirement. A new major is rejected; before 1.0, a new minor is rejected, and 0.0.x keeps its patch boundary. Linked prerelease stdlibs still require an exact match. (#1481)
  • Compiler: Source traits can inherit imported Rust trait bounds without synthesizing conflicting implementations of foreign parents. (#1427)
  • Compiler: Qualified Rust enum patterns work through shared and mutable references without cloning the matched value. (#1448)
  • Compiler: Checked SDK artifacts retain derive-provider membership, so @derive(toml) remains available through compiled standard-library imports and re-exports. (#1449)
  • Compiler: Imported Rust generic trait bounds accept native scalars and collections, with the actual trait obligation checked by Rust during native compilation. Same-spelled Incan traits still require explicit adoption. (#1451)
  • Tooling: Declared scripts that resolve to src/lib.incn fail with a located manifest diagnostic naming the script and library path, before Oven generates executable code. (#1068)
  • Tooling: Experimental replacement execution admits compiler-selected str, int, and float scalar conversions with receipt-bound normal output and classified parse failures. Source literals and runtime numeric strings share one language-owned underscore-separator policy. Malformed source literals produce compile-time diagnostics, while failed runtime conversions retain the original spelling in the canonical ValueError. #988 retains the broader numeric-operation and entrypoint profile. (#1249, #1278)
  • Tooling: Exact signed and unsigned widths, f32, f64, aliases, and checked fixed-scale decimals now retain their compiler-selected carrier through literals, locals, lossless widening, source-local calls, direct entry arguments/results, Display output, receipts, the replacement JSON report's result_type, and bounded two-route comparison. Exact f32/f64 carriers are finite-only: native exact arithmetic validates each result before it can be stored, returned, compared, or printed, and runtime exact-carrier boundaries use the same canonical ValueError; ordinary float retains IEEE non-finite values until code attempts to cross into an exact carrier. The replacement profile still refuses arithmetic on these exact carriers, their unary and resize operations, Debug formatting, aggregates, matching, and decimal scalar casts before effects under #988; package/import execution remains under #989. (replacement-body-v0-029, #1279)
  • Tooling: The experimental direct replacement profile now executes its admitted selected entry through one session-owned package-feature projection and records matching semantic-module provenance in its JSON report and backend receipt. That initial profile did not admit package/public imports; published package coverage is described above, and broader unsupported source remains outside the profile. (#1254)
  • Compiler: The experimental replacement profile executes source-local hashed set and dictionary membership with checked int, bool, str, or unit keys, including typed-empty constructors. A same-source comparison covers exact program output and a separate boolean result; iteration, mutation and general collection parity remain outside this profile. (#1247)
  • Tooling: The experimental direct replacement profile recognizes compiler-selected global enumerate(list) and zip(list, list) over retained structural list shapes, preserving zero-based enumeration and ordered shortest-side pairing. Receipt-backed comparisons cover the selected list cases; this does not grant general iterator support. (#1249)
  • Compiler: Native compilation materializes stored enumerate results as checked list values and preserves later-used values when introducing aliases, including the required generic Clone bounds. (#1249)
  • Compiler: Generic callers now inherit implementation-only bounds from the exact checked trait implementation, including across compiled-library metadata, without imposing those bounds on every use of the owning type. The manifest retains the selected trait identity, arguments, associated types, bound origin, and implementation header; private same-program implementation details remain absent from the public artifact. (#1280)
  • Compiler: Dependency-interface predeclaration preserves concrete public result types across cyclic and transitive local imports, so chained generic method calls no longer degrade to unknown placeholder types merely because their modules depend on each other. (#1280)
  • Tooling: Experimental replacement execution delivers program output during execution and preserves accepted bytes if execution or receipt persistence later fails. JSON reports require a separate --report-output file. The bounded named-function shadow comparison transports typed results separately from stdout/stderr and compares each program stream exactly; unavailable comparisons and diagnostic differences remain non-green. (#1249)
  • Compiler: Provider-aware replacement preparation checks missing hosts inside deferred computations and reachable same-module callees before program output or provider invocation. Host discovery uses retained compiler identities; invocation-time authority checks and operation receipts remain unchanged. (#1249)
  • Compiler: Compiler-selected integer abs and builtin sum now fail on overflow in every build profile. Replacement execution preserves the original call span and prior output, while generated Rust uses explicit checked operations instead of inheriting Rust debug/release overflow behavior. This does not yet define overflow for ordinary integer operators. (#1249)
  • Compiler: The experimental replacement profile executes the selected upper, lower, strip, replace, join, split, and contains string helpers through checked compiler identities and the shared runtime. A dedicated same-source comparison covers those helpers; arbitrary methods and general formatting parity remain outside this claim. (#1256)
  • Compiler: String len(value) and value.len() count Unicode scalar values consistently in generated Rust and the experimental replacement profile. The replacement path keeps checked builtin/helper identity, and a dedicated same-source corpus row compares exact program streams and the returned result; other Len operand profiles remain bounded. (#1249)
  • Tooling: The experimental replacement profile executes compiler-selected json_stringify for directly represented integers, booleans, strings, and None, evaluating the operand once and preserving the shared runtime's exact JSON bytes. A same-spelled source declaration keeps its lexical identity; floats, collections, nominal values, and broader serialization remain explicit refusals. A dedicated same-source corpus row compares the exact returned bytes and empty program streams through independent receipts without claiming general JSON parity. (#1249)
  • Tooling: The experimental replacement profile executes compiler-selected len over its source-local hashed set/dict carriers, returning the distinct element/key count after duplicate collapse, including typed-empty constructors. A dedicated same-source comparison covers exact streams and the integer result; iteration, indexing, projection, mutation, equality, ordering, printing, and formatting of these containers remain outside this bounded claim. (#1249)
  • Tooling: The experimental replacement profile executes compiler-selected bool for its directly represented booleans, integers, strings, lists, sets, and dictionaries. Zero and empty values are false; nonzero and nonempty values are true. A same-spelled source declaration keeps its own identity, and floats, tuples, bytes, frozen collections, options/results, arbitrary objects, and custom truthiness remain outside this bounded claim. (#1249)
  • Compiler: isinstance(value, Target) now retains the typechecker-resolved value and target types, any proven nominal target identity, and the target's exact source span in a dedicated Body IR operation. The experimental replacement profile executes the bounded int, bool, str, and ordinary binary float target set when the checked value type is one of those scalars or a nonempty union containing only them. Ambient and explicit std.builtins.isinstance(...) calls consume the same compiler-owned identity, while a source declaration with that spelling remains an ordinary direct call. A same-source comparison covers true and false union-member branches, direct expression use, exact streams, and the typed boolean result. Unsupported value or target shapes refuse before effects; this does not add arbitrary runtime type values, general reflection, nominal execution, or package/import execution. Closed #1154 supplied the current direct nominal/value substrate; open #988 owns broader replacement execution, and #989 owns package/import execution. (#1281)
  • Tooling: The experimental replacement profile executes compiler-selected sorted for nonempty represented integer lists, returning a fresh ascending list while retaining negative values, duplicates, and the source list's original order. Empty lists and other accepted ordering domains remain explicit refusals until checked element-type/order facts reach this runtime seam. (#1249)
  • Tooling: Experimental replacement execution now runs calls that leave the entry module. A call into a sibling module executes against a graph spanning the session's reachable modules, resolving the callee by canonical identity rather than by a same-module span identity; a module-qualified call such as helper.bump(41) executes as a direct call to the declaration its qualifier names, and a local sharing an imported module's name keeps its ordinary meaning. Refusals report against the module whose span they carry rather than the entrypoint, so a diagnostic names the file a reader has to open. That initial module-execution change left package (pub::) imports outside its scope; published package execution is described above. (#1260)
  • Tooling: A facade chain executes on the experimental replacement route with its direct, aliased, and re-exported bindings proven to resolve to one declaration. An alias is admitted as a binding to a declaration rather than a declaration of its own, so refusing it would refuse a name rather than any behavior. (#1261)
  • Compiler: A Rust or Python interop boundary the replacement route cannot cross now refuses as a missing host rather than as a construct the profile has not reached, naming the crate a call would have entered. Previously import rust::serde_json and import std.io reported the same text, which sent a reader to the language when the problem was a host. An ordinary standard-library import still reports as an unreached construct and never claims a missing interop host. (#1262)
  • Dependencies: The locked Wasmtime and Cranelift patch releases advance to the 36.0.14/0.123.14 family, clearing RUSTSEC-2026-0269 from the repository security gate without changing Incan's declared dependency range or public language surface.

Verified means verified by execution. A source profile counts as parity only when both routes actually ran over the same source and agreed on what the program did — the replacement backend executing Body IR directly, and the legacy backend building and running the program it emits through Oven, under a receipt that records which build authority produced the answer. The backend-selection receipt records that outcome explicitly as matched, diverged, or unavailable, and only a comparison that ran and agreed is green; a legacy program that merely compiled proves nothing about meaning. A comparison that could not run keeps whatever evidence the route that did run produced, so an unstaged environment stays distinguishable from a backend that cannot execute the source. Because an environment without a staged build authority is non-green everywhere, a dedicated CI job stages one and requires the comparison to run and agree, so "verified" always names evidence that was actually produced. See Backend selection & execution receipts.

Source identity is part of that contract. Imports, aliases, re-exports, locals, members, and generic binders should resolve to one canonical compiler identity across diagnostics, LSP features, graph tooling, and backend facts. This removes the backend-emitted Rust name as an accidental source of semantic truth.

Loaf and Oven become the opted-in project authority

For a project that adopts loaf.toml, Loaf expresses authored project intent and Oven owns resolution, targets, provider planning, cache identity, artifacts, receipts, and publication-facing build evidence. oven build and oven bake will provide the build and target-bound asset surfaces; in-Loaf incan run and incan test will use those same plans and receipts.

Cargo remains valid as a legacy format and explicit compatibility/adoption mode. It does not become invalid, and a Rust-only project can choose Oven without adding Incan source. But once a project is Loaf-native, Cargo cannot silently retake authority over its project graph or provider effects.

The authored project manifest is now loaf.toml. incan.toml is not read as a compatibility format — RFC 117 lists preserving it among its non-goals — so a directory holding one is reported as not being a project manifest, naming the file and saying to rename it once its tables satisfy the Loaf schema. Discovery stops at such a directory rather than walking past it to an ancestor project, because whoever put the file there meant it as a project root. [oven.interop] moves in the same transition to [interop.c], under an [interop] root that names each binding kind; its contents are unchanged.

The generated project lock is now oven.lock. It records the same resolved dependency, provider, and interop graph that incan.lock did, under the name RFC 117 gives it, and both authored and generated filenames are lowercase so a case-only difference never means one thing on Linux and another on macOS or Windows. incan.lock is not read: a project that still has one should run incan lock and delete the old file, which no longer contributes to any build. Committed example locks in this repository are renamed with it.

Incan-only, Rust-only, and mixed projects will have deliberate, non-overlapping source roots. Rust facets, direct rustc planning, build scripts, and proc macros remain supported through governed provider contracts. C and other foreign runtimes stay behind explicit interop boundaries rather than being inferred from a source directory.

  • Tooling: The toolchain is three Cargo packages, incan-cli (the incan binary), incan-lsp (the language server) and oven-cli (an oven binary over the same handlers incan oven … and incan lock run; built, not yet shipped in the release archives); the lsp Cargo feature is gone. A source build installs each on its own — cargo install --git https://github.com/encero-systems/incan.git --locked incan-cli, and the same command with incan-lsp — and the prebuilt archives still ship both binaries. (#1478, #1481)
  • Compiler: Generated Rust links the standard library as one runtime crate per component — incan_std_core always, and incan_std_data, incan_std_async, incan_std_web or incan_std_testing when the program's namespaces reach them — in place of one incan_stdlib crate selected by Cargo features. incan inspect rust and build reports name those crates. (#1481)

Runtime effects become governed and inspectable

The runtime and embedded-language work in this release is there to make real programs and the new backend prove one another. Accepted embedded fragments have typed descriptors, diagnostics, LSP behavior, and a safe formatter contract: structured fragments format structurally; opaque fragments are preserved unchanged.

Authority declarations, grants, execution receipts, redaction, replay, and policy inspection make runtime effects explainable. Source and packages state requirements; Loaf applies project policy and target selection; Oven enforces and records the resulting execution. Source code cannot grant itself host authority.

  • Stdlib: std.hash adds keyed authentication with hmac_sha256, covering one-shot tags, an incremental signer, and constant-time verification. An unkeyed digest can only prove a value is self-consistent, since the hash formula is public source; a keyed MAC is what lets a process prove a value it received across an untrusted boundary was one it produced earlier. Verified against the RFC 4231 vectors (#1075).
  • Compiler: The nine reserved host.* runtime capabilities are declared in the compiler's own bundled std.runtime source, using the same capability declaration a package uses rather than a separate built-in list. A requires entry can now name one — from std.runtime import host, then requires = [host.fs.read] — and a misspelled host capability is an unresolved-symbol compile error instead of a runtime denial reported somewhere else. Granting and enforcing this authority is not wired yet; this is the declaration and reference half. (RFC 104, #1029)
  • Compiler: @provider_operation can name a host capability, so an operation declares the authority it needs the same way it declares a package capability. The decorator resolved its capability reference only through package dependencies, which cannot see the compiler's own bundled std.runtime, so @provider_operation(host.fs.read) was unresolvable. (RFC 104, #1029)
  • Compiler: A capability declaration no longer fails compilation. It declares authority rather than code, so it emits no Rust item, but lowering treated it as an unhandled declaration and failed any module containing one — which meant std.runtime typechecked while refusing to build. (RFC 104, #1029)
  • Tooling: incan inspect codegraph publishes RFC 104 capability declarations, including each one's description, typed scope dimensions, and the resolved identities of the capabilities it requires. A policy, CI job, editor, or agent can read what a package declares it can do without executing source or parsing a capability block. (RFC 104, #1027)

Inspection becomes a first-class product surface

The CLI, LSP, Architect, MCP tools, and Rust/Oven views will consume the same source and build facts. They should agree about a symbol's identity and range, a package or artifact's provenance, the selected target and provider, and whether information is stale. Rust-aware inspection is deliberately bounded to the workspace, package, target, artifact, and explicit interop edges that Oven needs—it is not a separate compiler.

What must be true before 0.6 ships

  • The replacement backend is the default only when the complete v0.6 matrix is verified or explicitly migrated.
  • Every backend run records both the selected route and the route that actually executed; incompatible, unavailable, skipped, or failed parity comparisons are non-green.
  • Generated Rust remains inspectable, but normal compilation, package contracts, and Oven do not rely on it as a semantic handoff. Reading it now takes a decoding step: every linker-visible Incan-origin declaration is emitted under a reversible incan-v1 identifier that encodes its canonical identity, and a private function carries no source-named alias at all.
  • Rust-only, Incan-only, and mixed Loaves can bake without Cargo acting as the project authority; Cargo compatibility remains explicit and well-described.
  • Canonical source identities, provenance, source ranges, and stale-state behavior agree across compiler and inspection consumers.

Bugfixes

0.6 is not released yet, so this list carries only fixes that are merged, regression-tested, and part of the release branch's supported behavior.

  • Tooling: SDK provider identities stay stable when a consumer uses only part of a compiled standard-library provider. Nested commands no longer reject a matching provider solely because its unused runtime facets were absent from the consumer's identity catalog. (#1481)
  • Compiler: Native package consumers retain compiler macro dependencies used only in a provider's child modules, including function-only facades. (#1467)
  • Compiler: Loops over nested literals such as [[], ["x"]] infer the string element type without an extra caller annotation. (#1471)
  • Compiler: import module::item compiles to the same canonical call as from module import item. The Rust-style spelling typechecked but native compilation named the item by its source name with no matching import in scope, so the generated crate did not compile. (#1441)
  • Compiler: A local function called inside a lambda that is passed to a Rust method now keeps its incan-v1 identity. The lambda body was skipped entirely while the Rust signature was pending, which discarded the resolved callee along with the diagnostics, and the bare source name reached the generated Rust as an undeclared symbol. (#1492)
  • Compiler: Deque[str].from_iter(...) and every other type application keep their arguments on the receiver. The argument list was dropped at resolution, so the element type reached emission as unknown and a string literal appended to the result was emitted as &str against a String parameter. (#1494)
  • Tooling: A command that has to wait for the SDK provider store lock says so, naming the store and the fact that another Incan process holds it, instead of blocking silently. A three-file incan inspect codegraph that sat in flock for half an hour looked like a compiler hang. (#1514)
  • Tooling: A Loaf project that also holds a Cargo.toml builds with one warning naming the ignored file; a directory holding only the retired incan.toml stops project discovery with an error asking for the rename rather than being stepped over. (#1008)
  • Language: {{ and }} in an f-string render one literal brace, as in Python, so f"{{{name}}}" prints {x}; both characters were reaching the output. (#1562)
  • Tooling: A workspace member that carries a feature-selecting dependency edge can be baked inside its workspace. A command's --features selection no longer rewrites the shared root lock, an explicit provider bake publishes the root lock with every member that can already resolve, and a member's sealed authority binds only its own lock entry, so baking providers leaf-first no longer invalidates each other. (#1414)
  • Compiler: Source-backed standard-library module imports retain the trait metadata required by their qualified codec functions. Models using @derive(toml) satisfy TOML codec bounds with either module import spelling and with aliases. (#1473)
  • Compiler: Equality assertions accept inline model constructors on either side of the comparison without requiring an intermediate local binding. (#1470)
  • Compiler: Reference-aware assignments preserve an existing borrow and materialize known borrowed values at owned destinations. Read-only nominal helpers and tree cursors can infer shared borrowing from complete local use and checked Rust receiver lifetimes, avoiding copies of ancestor subtrees. Crate-visible and inherent method entry points retain their callable ABI; mutation, escapes, overlapping call arguments, and unknown contracts keep owned behavior. (#1455)
  • Language: Plain assignment inside a nested block now reassigns the nearest enclosing binding — requiring mut and a compatible type — instead of silently creating a new block-local; let and mut remain the explicit shadowing forms, and mut name = value now declares a new binding over an active name rather than being rejected as mutation of an immutable one. This brings assignment behavior to the documented scoping contract. (#1072, #1248)
  • Language: print and println now render every argument, space-separated. Previously every argument after the first was silently dropped in generated Rust, with no diagnostic. (#1248)
  • Language: print and println are protected builtin bindings: source declarations, imports, parameters, and local bindings cannot replace them. Fields and methods with these names remain valid. (#1249)
  • Language: Duplicate declarations and same-spelling imports are now rejected by one frontend binding registry instead of silently replacing whichever declaration was seen first. Imports are reported as ambiguous when their canonical targets differ or cannot be proven equal; an explicit alias resolves intentional conflicts. The immutable line-output spellings print and println cannot be reused for ordinary lexical declarations or imports, while member names and ordinary builtin spellings such as len remain available under their normal namespace rules. (#1042)
  • Compiler: Unreachable code after an unconditional return is reported. (#1117, #1134)
  • Compiler: A package that calls between its own modules again projects the callee's emitted name. A package origin identifies which library declares a method; it does not make that method foreign to the build producing it, and reading it as foreign made a package decline to name a wrapper it was itself emitting. (#1174)
  • Compiler: A Result-returning main retains ordinary runtime panic diagnostics and requested import this output, matching the existing setup in other entrypoint forms. (#1249)
  • Language: A match written as a function's last statement now returns its value instead of being discarded, and every arm converts to the type the match produces. The documented spelling for pattern alternation previously emitted let _ = match ...;, so a value-returning function built from it produced Rust that would not compile, and str arms stayed borrowed where an owned String was required. (#1386)
  • Tooling: A vocabulary companion may bind a helper to any callable spelling on its package's public surface, including a public partial and a reexport alias, and its own build now rejects a binding that resolves to something uncallable through a chain of aliases. The provider's build and every consumer's frontend read one export authority, so a helper the provider published can no longer be rejected as missing by the consumers that import it. (#1031)
  • Editor integration: Signature help, scoped-symbol resolution, completion context, and call-site type arguments now reach inside an embedded fragment's expression holes. A hole is ordinary Incan that the compiler already typechecks, but the editor treated the whole fragment as opaque, so a call written inside one silently lost tooling that works everywhere else. One shared traversal now answers which expressions a fragment owns, for the compiler and its tooling alike. (RFC 081, #1022)
  • Tooling: incan fmt renders an embedded fragment from its structured tree, and preserves the original source verbatim only when the claiming descriptor declares itself layout-sensitive. The formatter previously preserved every fragment verbatim regardless, which is the third fallback state RFC 081 rules out; a descriptor's layout_sensitive declaration was recorded and never read. (RFC 081, #1022)
  • Editor integration: Hover and go-to-definition now stop at an embedded fragment's ownership boundary. Both resolved names by scanning source text, so a markup tag name or a style declaration property — perfectly good ASCII identifiers — resolved against ordinary Incan scope and answered with whatever unrelated local happened to share the spelling. DSL-owned syntax now reports which submode and which library own it; expression holes, being ordinary Incan, keep every tooling path they already had. (RFC 081, #1022)
  • Tooling: incan fmt no longer rewrites a RegexTemplate fragment into source that will not parse, and no longer grows a file by a blank line on every run. A template string's backticks and ${...} delimiters are consumed while parsing, so reformatting `hello ${name}!` emitted hello {name}! — a shape the submode rejects outright. Separately, both modes that preserve a fragment's text verbatim also emitted the newline the enclosing block supplies, so formatting was never a fixed point. All six accepted submodes now round-trip. (RFC 081, #1022)
  • Editor integration: The language server now answers textDocument/semanticTokens/full, so editors highlight Incan from the compiler's own reading of a file rather than from a regex grammar. Declarations take the kind of the thing they declare, type positions come from the parsed program instead of from capitalisation, member access separates a called method from a read property, and an f-string's interpolated expressions are highlighted as code rather than as string content. Embedded fragments are highlighted as their own submode, so a markup tag or a style selector never renders as an Incan local, while the expression holes inside a fragment do. A file that does not currently parse keeps its highlighting, losing only type positions and fragment ownership. (RFC 081, #1400)
  • Compiler: import module::item now binds the item with its declared signature. The last path segment was registered as if it named a module, so the name resolved and nothing reported an error, but every call through it inferred an unknown type — the failure surfaced later and elsewhere, as expected 'numeric', found '? + ?' on the first arithmetic using the result. Both import spellings now route through one symbol definition, so they cannot disagree about what an item is. examples/advanced/multifile typechecks again. (#1407)
  • Tooling: A vocabulary companion no longer has to declare a helper binding for every helper it emits. An unbound helper key resolves directly against its package's checked public surface, the same surface an ordinary consumer imports through; an explicit binding remains the override for a key whose export spelling deliberately differs. A companion that listed its own package's export names was maintaining a second copy of that surface, kept honest only by a test. (#1032)
  • Tooling: incan fmt no longer rewrites valid source into different or broken source. An enum's with <Trait> adoption was dropped entirely, a byte literal's escaped quote and backslash were unescaped so the literal no longer terminated, and a guarded match arm was rewritten into an arrow form the parser rejects. Every committed example is now round-tripped by a property test that asserts the result still parses and is a fixed point. (#1401)

What this does not claim

0.6 makes self-hosting work possible; it does not claim that Incan has already rewritten its compiler wholesale. It also does not introduce a broad GPU API or a general foreign-interop plugin system. Those need real runtime consumers and separately governed follow-up work.

Follow the work

  • #652 and #653: replacement-backend cutover and Body IR.
  • #655 and #654: compatibility reporting and final removal of the Rust-source handoff.
  • #1042: RFC 120 and canonical source identity.
  • RFC 118 and #1010: Incan and Oven command surfaces.
  • RFC 119: Rust facets, providers, and Cargo adoption.
  • RFC 106 and #573: compiler-backed codegraph and inspection.
  • 0.6 delivery map: delivery sequencing, slice evidence, and the current issue graphs.