Chuks v0.0.9 — Final 0.0.x Patch
Chuks v0.0.9 closes out the 0.0.x line. The next release, 0.1.0, will bump the minor version as we move toward the first public-beta surface area.
This is a polish-and-stabilize release across the compiler, CLI, stdlib, and runtime. Nine commits since v0.0.8, all 298 tests passing on both VM and AOT.
Highlights
Section titled “Highlights”- CLI installs prefer the registry’s mirrored tarballs with transparent fallback to the upstream Git archive
- Multi-package AOT is more robust cross-module slice element conversion, sibling-subclass devirt, map-literal temp shadowing all fixed
- New repository methods:
createAndReturn,updateAndReturnsingle round-trip insert/update + read - Type-aware
.auto()primary key inherits its underlying column type instead of always beingINTEGER time.toISOis now UTC in both VM and AOTcrypto.sha256Raw/crypto.hmacRawin AOT now returnBufferIDs, matching the VM contract- Better diagnostics: runtime panics report accurate source positions; the typechecker flags class-as-instance and unbound-method mistakes earlier
- Cleaner shutdown with cancellable sleeps + launcher signal forwarding
CLI: registry-mirrored installs with fallback
Section titled “CLI: registry-mirrored installs with fallback”When you publish a package to the Chuks registry, the registry now mirrors the release tarball to its own immutable, CDN-fronted storage. Starting in v0.0.9, the CLI prefers that mirror when installing:
$ chuks add my_package Resolving my_package@^1.0.0... Found my_package@1.2.3 Downloading from https://packages.chuks.org/.../package.tar.gz ... Installed my_package@1.2.3If the mirror is missing or temporarily unreachable, the CLI transparently falls back to the upstream Git archive no manual intervention, no failed installs:
Mirror unavailable (connection refused), falling back to upstream Downloading from https://github.com/owner/repo/archive/refs/tags/v1.2.3.tar.gz ... Installed my_package@1.2.3This makes installs faster (CDN-cached, fewer GitHub round-trips), more reliable (mirror is immutable git tag -d && git tag -f can’t change what you installed yesterday), and backward-compatible with older registry deployments that don’t expose tarballUrl.
Multi-package AOT: three subtle fixes
Section titled “Multi-package AOT: three subtle fixes”If you’ve been compiling larger projects to AOT, you may have hit one of these.
1. Cross-module slice element conversion. When a function in package A accepted a []User and you passed a []map[string]any from package B (e.g. raw rows from a DB query), the AOT compiler emitted code that panicked on the first element access. We now use the same __chuks_map_to_struct_ptr helper that already worked for scalar arguments.
2. Sibling-subclass devirt import cycles. Devirtualization was emitting type-assertion branches for every class in the program. When two sibling subclasses shared a base class with the same method name (e.g. ProjectRepo and ScenePresetPackRepo both extending Repository), each devirt site would force its package to import the other’s, producing an import cycle. We now skip foreign-module classes in devirt; the existing reflection fallback handles cross-package dispatch correctly.
3. Map-literal temp shadowing. A user parameter named _m (or any reserved-looking name) could be shadowed by the AOT compiler’s internal map-literal builder, silently corrupting the function’s local state. Reserved temp names are now namespaced.
None of these have a workaround in v0.0.8, they all required changes in the transpiler. Upgrade if you’re hitting any kind of multi-package AOT weirdness.
std/db: createAndReturn, updateAndReturn, type-aware .auto()
Section titled “std/db: createAndReturn, updateAndReturn, type-aware .auto()”Three quality-of-life improvements to the repository API:
createAndReturn — insert + read in one round-trip
Section titled “createAndReturn — insert + read in one round-trip”// Before, two round-tripsvar result: any = await userRepo.create({"email": "alice@x.com", "name": "Alice"})var user: any = await userRepo.findById(result["lastInsertId"])
// After, one round-trip, RETURNING-basedvar user: User = await userRepo.createAndReturn({"email": "alice@x.com", "name": "Alice"})println(user.id) // 1println(user.createdAt) // populated by DB defaultOn Postgres, this uses INSERT ... RETURNING *. On SQLite/MySQL/MSSQL, it uses the equivalent native primitive (RETURNING on SQLite ≥3.35, LAST_INSERT_ID() round-trip on MySQL, OUTPUT INSERTED.* on SQL Server).
updateAndReturn — same idea for updates
Section titled “updateAndReturn — same idea for updates”var updated: User = await userRepo .where("id", 1) .updateAndReturn({"name": "Alice Smith"})
println(updated.name) // "Alice Smith"Returns the updated row(s). On dialects that don’t expose RETURNING for UPDATE, the repository transparently issues an update + select pair inside a single transaction.
Type-aware .auto()
Section titled “Type-aware .auto()”schema.pk("id").auto() historically forced INTEGER. v0.0.9 lets .auto() inherit the column’s declared type:
const UserSchema = db.define<User>("users", (schema) => { schema.pk("id").auto() // → BIGSERIAL on Postgres, INTEGER AUTOINCREMENT on SQLite})
const OrderSchema = db.define<Order>("orders", (schema) => { schema.bigint("id").primaryKey().auto() // explicit BIGINT auto-increment})This matters when an int (32-bit) auto-increment is genuinely too small for your domain .bigint(...) + .auto() now does the right thing instead of being silently downcast.
Stdlib alignment between VM and AOT
Section titled “Stdlib alignment between VM and AOT”A few drift points between the bytecode VM and the AOT runtime have been smoothed out.
time.toISO now emits UTC ISO 8601 (YYYY-MM-DDTHH:MM:SSZ) in both modes. Previously the VM used time.RFC3339, which embeds the local timezone offset, so the same code produced different output on different hosts. Audit logs, JWT iat/exp claims, and DB timestamp columns now agree across machines:
println(time.toISO(time.now()))// 2026-05-08T02:51:32Z ← always UTC, always Z-suffixedcrypto.sha256Raw and crypto.hmacRaw (AOT) now return Buffer IDs and accept Buffer inputs, matching the VM contract:
import { Buffer } from "std/buffer"import { crypto } from "std/crypto"
var key = Buffer.fromString("secret")var hash: Buffer = crypto.hmacRaw(key, Buffer.fromString("message"))println(hash.length()) // 32 works identically on VM and AOTIf you’ve been using these in mixed-mode pipelines (e.g. develop on the VM, deploy with AOT), the round-trip now actually round-trips.
Diagnostics & runtime polish
Section titled “Diagnostics & runtime polish”- Accurate source positions for runtime panics. When an AOT binary panics, the stack trace now points at the original
.chukssource line. Massively reduces the cognitive load of debugging production crashes. - Typechecker catches more class-shape mistakes using a class name where an instance is expected, or accessing an instance method as if it were unbound, now produce typed errors instead of cryptic runtime failures.
- Graceful shutdown uses a cancellable
sleep, and the AOT launcher forwards SIGINT/SIGTERM to the child process. Mid-request shutdown is now clean: in-flight requests complete, new requests are refused with a clean error, and the process exits with code 0. os.execin AOT runs commands via the shell, captures stderr separately, and returns the real exit code, bringing it in line with the VM’s behavior.
Everything you need from v0.0.7 / v0.0.8 still applies
Section titled “Everything you need from v0.0.7 / v0.0.8 still applies”No breaking changes. Drop-in upgrade.
Upgrading
Section titled “Upgrading”curl -fsSL https://raw.githubusercontent.com/chuks-programming-language/releases/main/install.sh | bashchuks --version # 0.0.9All 298 golden tests pass on both VM and AOT.
Looking ahead — the road to 0.1.x
Section titled “Looking ahead — the road to 0.1.x”v0.1.0 is where Chuks starts treating its public surface area as semi-stable. The themes:
- Phase 4 IR kind-tagged values, cross-module type tables, constant folding
- Public-beta package registry at
registry.chuks.org - Signed releases & reproducible builds every binary verifiable against a published manifest
- AST-level permission scanner in the registry, replacing the regex layer
- Capability diffs between versions, surfaced to package consumers at install time
The 0.0.x line was about getting the language to feel right. 0.1.x is about making the supply chain trustworthy enough to recommend Chuks to people you don’t know.
Thanks for following along. Next stop: 0.1.0.