A Review

GLM and Kimi read the whole project together: what is strong, what could be better, what to try, and what to leave alone.

This page is two readers' read of Vela: the language, the compiler, the runtime, the library, the tests, the docs, and Vela Studio. GLM wrote the first pass; Kimi revised it and added a second one. The first half is GLM's voice, kept mostly as it was. The second half is Kimi's. Nothing here changes the language; like the second notebook, these are voices to agree with or argue against.

How we read it. We built the compiler (cargo build), ran the whole suite (cargo test, about a minute and a half on this machine; every group passed), ran cargo clippy --all-targets (clean), built and ran example programs, and read the C the compiler writes (--emit-c). We did not build Vela Studio, which needs Node and the wasm32 target; we read its crates instead. Marks below: strong is where the project leads; watch is a cost to keep an eye on; idea is ours; on the table is already in a future doc, and we say where.

What this project is

Vela is a small, statically typed systems language that compiles to portable C11. The compiler is written in Rust and has no Cargo dependencies; the workspace also holds Vela Studio, which does. It has one kind of function (task), one record (shape), one sum type (kind), exhaustive match, maybe and T ~ E for what may be missing or fail, and memory in named regions: a pointer's type names the region it points into (^T@r), and a region frees everything in it when its block closes. Mutation is marked at both ends: an alters method, a flex& parameter, and the call's own &a. The library is written in Vela and held inside the compiler; the runtime is one C header. There is an editor, Vela Studio, sharing the compiler as a library.

The scope is unusual: most new languages chase size (bigger std, bigger type system, bigger ecosystem). Vela chases auditability. Every part is small enough to read in an evening, and the parts that can't be small are documented as not small: Safety lists every concern the checker leaves open, and May Waste lists features that may not earn their place. A language that keeps a list of its own possible mistakes is rare, and it is the strongest sign of the whole design.

What we verified

What What we found
cargo build Clean, fast; the compiler crate has no dependencies.
cargo test All groups pass in about 90 seconds: 35 CLI tests, the driver, the lexer, internal errors, the runtime's C tests, and every program in tests/run, tests/fail, tests/trap, and examples/.
cargo clippy --all-targets Clean. The Cargo.toml lints deny unwrap, expect, panic!, and unchecked indexing, so a crash in the compiler is a build failure, not a user's surprise.
Generated C Readable: shapes as structs, kinds as tagged unions, one function per task, names kept close to Vela's. The suite also compiles it as strict ISO C11 (-pedantic-errors -Wall -Wextra -Werror) and runs it under AddressSanitizer and UndefinedBehaviorSanitizer with leak checks.
Constant folding show(2 + 2) becomes (INT64_C(2) + INT64_C(2)); only values worked out at run time go through the checked calls, and a constant that would overflow is refused while compiling.
Examples Every one we built ran and printed its .out.

The test suite deserves its own line: the programs in tests/fail/ don't just fail to compile, each names the exact message the compiler must give, which makes them a specification of the compiler's words, not only of its rules. And the programs in the regions guide run against the output the page shows, so the tutorial can't quietly rot. Docs tested as code is something most large languages still haven't managed.

What is strong

One word for one idea, and the words say what they mean strong

fixed never changes and flex may; -> names what a task gives and <- gives it; maybe T and T ~ E make absence and failure types a caller must face; fi closes every block so nesting is visible; a plan B (x { fallback }) reads as what it is. The reserve is the real achievement: there is no else if beside else when, no struct beside shape, no second way to write anything except where May Waste has already opened the question. Even the operators are audited: == compares by where a value is when that is the honest answer, and ~= says item by item when that is what's meant.

Regions: lifetimes you can see strong

A region is declared inside a block; the block's end frees it. There are no hidden lifetimes — the only annotation is @r, and a block can name one region default so @r can be left off. What it buys: no null pointers, no dangling pointers, no use-after-free, no memory leaks past a block, allocation that costs a bump, and freeing that costs a free of a few chunks. What it costs is honestly listed in the guide: one region per value, no younger data pointing at older data, and region parameters threading through call chains. On the evidence of the examples, the model fits the language's intended work (compilers, batch tools, request-shaped programs) exactly as the guide claims.

The runtime is a pleasure to read: chunks double from 4 KB to 1 MB; an allocation too big to fit half a chunk gets a chunk of its own placed behind the newest so small allocations keep their room; text grows at the chunk's tip so a join can grow in place; files opened in a region are tracked by it and close when it closes. Someone thought about each case.

Mutation marked at both ends strong

alters grow(...) at the definition and c.grow() on a fixed refused at the call; flex& n in a header and f(&n) at the call site; a call that gives one place twice where it changes it, refused. Reading a call tells you what may change, without looking at the callee. C++const and Rust &mut both put the burden on one end or the other; Vela's two-sided marks are the cleanest version of this idea I've seen in a small language.

Errors that teach strong

The messages say what is wrong, where, and what to write instead: '<-' sends a value and must start a line; to compare with a negative number, write '< -'; 'each i, x' names a key and its value, which only a map gives; this gives one item at a time, so name one. The line, the caret, and the suggestion make the compiler a teacher rather than a gate. Keeping those messages as tests/fail/ programs pins them forever, which is why they stay good.

The library is the language strong

std/files and std/math are Vela source compiled into the compiler; only what Vela can't say (ask the system about this file) is a native task with its body in the runtime header, and a program may not write one. So the library works in the command, in Studio, and in the web editor with nothing installed, and a program can't use it as a hatch into arbitrary C. That is a principled FFI story in miniature.

Generic words instead of traits strong

<T: ordered>, shown, same, similar, frozen: small structural promises instead of declared interfaces. A type has them by what it is, no impl blocks, no coherence rules, no orphan instances to argue about. For a language this size it is the right trade, and the project is already auditing the words in case same is too cheap to have to say.

What could be better

Nothing below is a defect: the build is clean, the suite passes, and every design cost we found is already written down by the project itself. These are the places where we think the next effort pays best.

The checker and the C writer have grown past one file watch

src/check.rs is about eleven thousand lines and src/codegen.rs about five thousand; the parser is near four thousand, and the lexer and AST near one and two thousand, which reads well. The pipeline (lexer → parser → checker → C) is the right shape; the passes themselves could now be split the way the checker already splits its work (headers, statements, expressions, regions, generics, monomorphization), as private modules behind the same public functions. Nothing about the language changes; it's a filing task, and it would keep the "read a pass in an evening" property the project values as the checker keeps growing.

The language's own names live in several places watch

The reserved words are in lexer.rs (KEYWORDS), the builtin types and tasks in ast.rs (BUILTIN_TYPES, BUILTIN_TASKS, BUILTIN_KIND_NAMES), the natives in library.rs, Studio's scanning in ide/analysis/src/scan.rs, and the tables in the docs. Each is right where a reader wants it, which is the point, but nothing asserts they agree. One test that walks every list and checks each entry against a single builtins.rs (or just against each other) would turn a quiet drift into a red build. The pieces to build it from already exist, since Studio imports the compiler's lists.

Every checked op carries its place as a string watch

In the generated C, each checked operation passes where it is as a literal: vela__rt__add(a, 2, "3:16 in task 'main'"). The checks are already cheap (the overflow builtins fold to a jumped jo, and constant arithmetic is folded at compile time), but a program with many operations embeds one string per site and pushes a pointer for each. An interned table — a static array of the place strings, each site passing a small index — would make binaries smaller and the instruction stream shorter, with the same messages. It is a contained change in the C writer and the runtime's trappers alone.

; today
vela__rt__add(a, 2, "3:16 in task 'main'")
; with an interned table
vela__rt__add(a, 2, 17)   ; site 17 is "3:16 in task 'main'"

Floats print with six digits watch

show and str print floats with %g: six significant digits, and 1e+06 for large numbers. A shortest-round-trip printer (Ryu or Grisu) would let x.str() at r read back equal to x every time — the property a program that writes and reads its own data wants — while show could keep today's shape. The runtime already has exact integer-to-text conversion for its overflow messages; a float shortest-round-trip printer would sit naturally beside it.

The docs' code blocks are colored by hand watch

Every example in every page is highlighted as <span class="keyword"> by hand, and the programs in the regions guide already run against their shown output. The compiler already offers the tool: vela::lexer::highlight splits source into tokens without stopping at errors. A small checker that takes each <pre> block marked as a program, re-renders it with the lexer, and reports a difference would keep ten pages of hand-work honest for the price of one script — the same trick the tests/fail/ suite uses on the compiler's own words.

The README opens with a wall watch

The guide pages are a model of short declarative prose, and the README's first section is one enormous paragraph covering the whole language. It is a statement of intent — everything is there — but it is the one page a new reader meets first, and the only one that works against scanning. Three or four short sections (what it is, what memory does, what failure is, with the rest staying as it is) would keep the voice and lose the wall.

What GLM would try

Each idea below says what it adds, what it costs, and how it fits the rules the language already has. Two are already on the table in another doc; those say so and take a position. None needs a borrow checker, a trait system, or a second way to write something that already has one.

A guard build: vela --guard idea medium

Safety lists, for every open concern, the check a running program could do; they are written as separate "ways it could go". One flag could turn them all on at once:

  • a call-depth counter, catching the runaway recursion that today is a bare segmentation fault;
  • where a call gives a place behind a pointer beside another pointer that may reach it, a check at the call that the two addresses differ, trapping when they don't;
  • a generation number on each slice, raised by add and del, and a view (xs[a..b], a loop's own copy) that reports when it outlives one.
What it adds
The open concerns stop being reading material and become a mode a program can run in while hunting a bug, the way the project's own suite already runs everything under the sanitizers. Nothing changes in the language; a trap in a guard build is a message saying where, like every other stop.
What it costs
A second runtime path to keep honest, and slower programs — the same trade --quick already asks about, in the other direction. The checker is untouched, so the guard build is a runtime and C-writer matter alone.

A bigger library, written the way the library is written idea small

Today a program can't read its own command line or environment (we checked: nothing in the language or std/ names them), the examples hand-write a sort, and the guide's own Current Limits list text search, trimming, and case changes as missing. All of it is Vela-shaped work:

include std/sys {args}
include std/slices {sort}

task main()
    each a in args
        show(a)
    fi
fi
  • std/sys: args (the command line as a slice of text), env(name) at r, exit(n). Small native tasks, like the files'.
  • std/slices: sort, find, sum, min, max, over <T: ordered> and <T: same> — the generic words already say all of it.
  • std/text: find, split, trim, upper, lower, each returning text of the region it's given, as the guide's own limits page sketches.
  • std/random: a seeded generator with next(r) -> int and below(n), so tests can be made repeatable.
What it adds
The parts every program outside the examples actually reaches for, without one new language rule. And since the library is held by the compiler, every tool gets it at once.
What it costs
Pages in the docs and tests in the suite, and a decision the project has already learned to make (see how std/files was cut): which parts belong in Vela and which are natives.

Bitwise work as methods on the table small

A systems language with no way to and, or, xor, or shift a bit (we looked; there is none) leaves a gap between what it means to be — bytes, units, chars — and what it lets a program say. New symbols would fight the ones already earning their place (& marks a place, ~ is the error side, ^ points). Future Directions has already chosen C's symbols, &, |, << and >> (2026-09-23), for reading as C does, and lists what they must settle (the >> that closes nested types, the | error message); this is the case for the other way. Methods fit the language's own rule, that a member of a value is written after a dot:

fixed flags = 0b1010
flags = flags.bor(0b0110)          ; 0b1110
show(flags.band(0b0010), flags.shl(2))
flex c: unit = 0xff
show(c.shr(4), c.bnot())            ; 15 0
What it adds
Flags, hashes, packings, and masks, on int, unit, and char alike. A shift past the value's bits stops the program with a message, as arithmetic does; a result that can't fit (an int shifted left past 63) stops it too.
What it costs
Six methods on three types, in the builtin list the compiler already keeps, and the choice of a result type per operation — the same choice + already makes between int and float. No grammar changes at all.

An index beside the item: each i, v in xs idea small

A map's loop gives a key and its value together; a slice's gives one item and points at the refuse a program gets today ('each i, x' names a key and its value, which only a map gives). The examples pay the tax everywhere, walking 0..len just to count:

; today
each i in 0..xs.len
    when xs[i] > 0
        seen++
    fi
fi
; the idea
each i, x in xs
    when x > 0
        seen++
    fi
fi
What it adds
The index beside the item, checked once at the loop's start, the way a map's loop already works. The error message the compiler gives today is practically asking for it.
What it costs
One more form of each, and the rule that each v in &xs (as it is at each pass) gives the index too, which it would.

Ranges in case forms: when c is 'a'..'z' idea small

match stays on kinds, and the guide refuses a plain number in a case; but is already opens a maybe or a variant in a condition, and ranges already live in slices and loops. Letting a range stand in is, and in a case of a kind whose payload is an int or a char, would compress the chains that grade and classify:

when c is 'a'..'z'
    letters++
fi
What it adds
One condition where today a program writes an else when chain, and one case where it writes several. The bounds would be constants, as an array's count is.
What it costs
A case form that isn't a single value, which the checker's code for case forms must carry, and the rule that a range's ends are constants so the compiler can order them. Exhaustiveness is untouched: a range never covers a kind's variants by itself, so the anything case still does its work.

A formatter: vela fmt on the table medium

Future Directions lists a formatter among its tools; this is how it could go. The language is nearly canonical already: one statement a line, blocks closed with fi, four-space steps, expressions on one line. Every example, test, and doc page agrees on one layout — by hand. A formatter would mostly be a checker: it can't break a line the grammar won't, so its decisions are few (where the => of an include goes, how a long shape literal or a long header wraps, whether to keep else on the when's line, as the docs do).

What it adds
Ends the layout question for every program, forever, and keeps examples, tests, and the docs' hand-highlighted blocks in step. Written against the parser the compiler already has, it is the one tool that gets cheaper as the language stays small.
What it costs
A decision for each form, taken once, and a rule for the few forms the grammar leaves open today (a long header, a long literal) — which wants the multi-line forms decided at the same time, a small piece of future work the guide already points at.

A fuzzer for the invariant that matters idea small

The project states its own deepest rule: an internal compiler error is a report, not a crash, and the lints already deny the panics. The corpus to break it with already exists: a thousand refused programs in tests/fail/, each pinned to its exact message. A coverage-guided fuzzer over front_end_partial and check_program — whatever bytes go in, a rendered error or a checked program comes out — would take the invariant from "the tests say so" to "nothing found a counterexample today". A nightly job that files each new finding as the next tests/fail/ program would make the corpus grow itself.

Debug builds with the map back to Vela on the table small

The second notebook already proposes #line directives so C compiler errors and debuggers point at Vela source. I would take that position and add the other half: a vela --debug that passes -g to the C compiler and keeps the generated C in the build dir, so gdb steps a program and lists the .vela file it came from. The readable-C design makes this a short walk: the names in the C are already the names in the program, and every trap already knows where it is. This is the piece that turns "readable C" from a comfort into a tool.

Testing in the language: vela test on the table medium

Future Directions already lists built-in testing as an idea, and the shape of it is sitting in this repository: tests/run/ programs are named, they print their output, and the harness compares it. The language half is small from there — a task whose name starts test, run by vela test beside main, with a failure rendered the way every other stop is (file, line, caret, and what was expected). My addition to the existing idea is only this: the runner should reuse the whole existing harness, because it already knows how to run programs, feed them input, and diff their output, and a test runner is mostly that.

A lint for the recursion that looks like a loop idea small

The examples walk lists and recurse, as idiomatic Vela does; the guide says plainly that a deep call chain stops the program with the system's own crash and no message. C compilers often turn a self-recursive tail into a jump, but never promise to, and the checked calls between caller and callee can block the optimization. A lint that names a task whose every path ends in a send that only calls the task itself — a tail that reads as a loop but isn't promised to be one — would point writers at the loop that is guaranteed, and at the guide's own open concern, without adding one rule to the language.

Type macros, the smallest step toward compile time on the table small

The second notebook reaches for full comptime; before that there is a smaller stone to step on. Today a macro names a value the compiler works out (#PI = 3.14159). Letting one name a type — #Vec2 = (float, float), #Grid = [int#64] — would give tuples and arrays the short names they now lack, with no new grammar: the # line is already there, and a use site already says fixed of what type it wants. The one honest cost is that a name could then be a value or a type, which today it never is; the rule "a macro is what its declaration says" answers it.

What GLM would leave alone

The future docs together hold a shelf of ideas: borrowing on top of regions, algebraic effects, typestate, SIMD, comptime, pipelines, events, channels and actors, an LLVM backend, self-hosting. My read of the project says the discipline is the product. In particular:

GLM's order

# What Why here
1 Split check.rs and codegen.rs into private modules Health of the one codebase every other change lands in; nothing moves but the files.
2 A test that the builtin lists agree everywhere One evening's work, and every future change stops having a second place to forget.
3 Intern the site strings in the generated C Small, measurable, and it touches only the C writer and the trappers.
4 std/sys and std/slices Real programs need their own arguments and a sort; both are pure Vela plus two natives.
5 each i, v, range case forms, bitwise methods Three small language answers to costs the examples pay on every page.
6 vela fmt Locks the layout the project already agrees on, and keeps ten docs pages honest with it.
7 vela --guard The safety page becomes a mode; also the groundwork for whatever concurrency comes.
8 The fuzzer, and --debug with the #line map Protects everything else, then makes it inspectable — in that order.

If only one of these is taken, take the guard build. Everything else makes the language or the compiler better; that one makes the project's own honesty — the safety page that says where it can't check — into something a program can ask for at run time. It is the idea most in this project's spirit, because it adds no syntax at all.

What Kimi adds

GLM read the project for its mechanics: the files, the tests, the generated C, the places where the code has grown thick. I read it again for what it could become — the product, the voice, the bridge from a compiler to an ecosystem. The notes below are mine; where they overlap with GLM's, I try to push further.

Kimi's lens. I care about whether a language is adoptable as well as correct: the first hour, the first bug, the first shared library. Vela's correctness is already unusual; the question that remains is how many people will find it before they need something bigger.

The voice is a feature

GLM is right that the prose style is distinctive, but I would go further: it is a competitive advantage. The docs read as if one careful person is speaking, and that voice creates trust the way a polished website never does. Most languages sound like committees; Vela sounds like a person who has made up their mind. I would formalize it:

The result is not vanity. When a reader hits a hard idea like regions, the clarity of the surrounding prose is what carries them through. The project has already done the hard part; writing it down as a rule keeps it.

The test harness is a product

GLM praises the tests/fail/ suite, and it is the right thing to praise. I would expose it to the user. Today the harness is internal; a vela test command could treat every program the same way the project's own suite does:

This is not a new idea — Future Directions already lists built-in testing — but the shape is already finished in tests/programs.rs. The work is mostly plumbing: read a tests/ folder beside the user's program and call the same functions the compiler's own tests call. A user who writes twenty tests/fail/ cases has a specification of their library's error contract, not just a test suite.

Literate programs: .vela.md

The project already tests the programs inside the regions guide. The next step is to make that relationship general: a file ending in .vela.md is Markdown whose fenced ```vela blocks are the program, and the prose between them is the documentation. Running vela run tutorial.vela.md extracts the blocks in order and compiles them.

```vela
task main()
    show("Hello from the guide")
fi
```

What it adds: tutorials, papers, and notebooks become first-class Vela artifacts. What it costs: a small extractor and the rule that prose blocks are comments. It fits the project's obsession with docs-as-code, and it gives Vela a format no mainstream systems language has.

Error theater and region-colored editing

Vela Studio already has diagnostics, completion, and hover. The obvious next step is to make the hard errors visual:

These are not gimmicks. They are the teaching tools the error messages already are, extended to the one place a learner actually needs them: the editor, at the moment of the mistake.

LSP and a web playground

The analysis crate (ide/analysis) already implements highlighting, completion, hover, diagnostics, and outline. Wrapping it in the Language Server Protocol would give VS Code, Neovim, and every other editor the same support Vela Studio has, without asking users to switch editors. The work is a thin adapter: the analysis crate is the real engine.

The same crate is compiled to WebAssembly for the Studio web client. A standalone Vela Playground — paste code, see errors, run it in the browser — is a natural sibling. It is the fastest way for a curious programmer to spend their first hour with the language, and the wasm target is already built.

Doc comments and vela doc

Today comments start with ; and no comment is a doc comment. A second form — I would use ;; — marks text that belongs to the declaration below it:

;; Count how many items equal wanted.
task countOf<T: same>(xs: [T]@r, wanted: T) -> int
    flex seen = 0
    each v in xs
        when v == wanted
            seen++
        fi
    fi
    <- seen
fi

A vela doc command would collect these, the task headers, the shape fields, and the kind variants, and emit the same dark HTML the project already writes by hand. The docs' existing style becomes the generated style. This is a small tool with a large effect: it makes the library self-documenting the moment std/ grows past two modules.

Kinds that take types, and closures that capture

These are both already on the table (Future Directions), and I would put them near the front of the queue. They are not eye-catching in isolation, but they unlock the idioms a reader expects:

kind Result<T, E>
    Ok(value: T)
    Err(error: E)
fi

task firstOk<T, E>(xs: [Result<T, E>]@r) -> maybe T
    each x in xs
        when x is Ok {value}
            <- value
        fi
    fi
    <- none
fi

And a lambda that captures a value by copying it into its own region, as the second notebook sketches, would turn the current "lambda with no context" into the closures the examples already want (counters, callbacks, comparators with state). Both fit the existing machinery: generic kinds are monomorphized the same way generic tasks are, and a captured closure is a shape with a function pointer and fields.

Named and default arguments

Also already on the table, and the syntax practically designs itself: Vela already writes every parameter as name: T, so a default is name: T = value and a call can name an argument when it wants to skip earlier ones:

task open(path: text, mode: FileMode = FileMode.Read)
    ...
fi

file.open(mode: FileMode.Write) at r

This is the single most requested feature in almost every young language, and Vela's parameter syntax is already halfway there. It would also make the growing library more pleasant: math.log(x, base: 10.0) reads better than remembering the order.

Match on numbers and characters

GLM proposed range case forms in is and in cases of a kind holding an int. I would go one step further and let match itself work on int and char, with ranges and a required anything case:

match grade
case 90..100 = "A"
case 80..89  = "B"
case 0..79   = "C"
case _        = "?"
fi

The checker already knows how to insist on a complete match; ranges just become a compact way to cover contiguous values, with the same constant-bound rule arrays have. It is a bigger change than GLM's range case forms, but it is the one that makes match feel universal rather than kind-specific.

Format strings inside interpolation

Text interpolation is already one of Vela's nicest features. A small extension to the braces would cover the cases where .str() is not quite right:

show("{n:04} {x:.2f}" at r)   ; 0042 3.14

The cost is a tiny parser inside the string parser and a few runtime helpers. The benefit is that most everyday formatting needs never leave the string. For a language that values readable syntax, keeping the format close to the text is the right place.

Shape layout control

The second notebook proposes controlled shape layout, and I would add it early because it is small and C-shaped:

shape Header
    packed
    magic: unit
    version: unit
    length: int
fi

A packed keyword (or align N) tells the compiler to generate a struct with no padding, which is exactly what file formats and network protocols need. Since Vela already compiles to C, this is mostly a matter of emitting __attribute__((packed)) or _Alignas directives. It would make Vela credible for the lowest-level parsing work without adding a type system feature.

Package manager as plain files

Future Directions knows Vela needs packages. I would avoid a central registry for as long as possible and use git URLs:

; vela.toml
name = "mytool"
version = "0.1.0"

[dependencies]
cli = { git = "https://github.com/example/vela-cli", tag = "v1.2.0" }

vela init creates the file; vela add cli appends a dependency; vela build clones missing dependencies into a local cache and treats them as modules. No registry, no semver solver, no ecosystem politics — just files and tags, which matches the rest of the project's minimalism. A central registry can come later, once the community actually needs it.

Codegen: deduplicate and evaluate early

GLM's interned site table is a good small win. I would add two more, both visible in the compiler today:

What Kimi would do first

GLM's priority list is sound, but my order differs where adoption is the goal:

  1. Kinds that take types and closures that capture. These unlock the patterns a new user expects; without them, Vela feels artificially small.
  2. vela doc with doc comments. The docs are already the project's crown; making them generatable keeps that crown polished as the library grows.
  3. LSP adapter and a web playground. The analysis crate and the wasm build are already there; the gap is packaging. This is the fastest way to put Vela in front of people who will not install Studio.
  4. std/sys, std/slices, std/text. GLM has these right; they make real programs possible.
  5. Named/default arguments and match on numbers. Both remove friction the examples already show.
  6. The guard build. GLM puts this first, and it is the most principled idea; I put it sixth only because I would rather make the language worth guarding first. Both orders are defensible.

Together: a final list

GLM and I agree on the diagnosis: Vela is unusually coherent, and its biggest risk is that it stays too small to be reached for. We differ in emphasis — GLM favors compiler health and runtime honesty first; I favor expressiveness and adoption first — but the union of our lists is a reasonable roadmap. If the project wanted one ordered pile, I would stack it like this:

# What Voice
1 Split check.rs and codegen.rs into private modules GLM
2 Kinds that take types; closures that capture by copy Kimi
3 std/sys, std/slices, std/text GLM
4 Doc comments and vela doc Kimi
5 Named/default arguments Kimi
6 Bitwise methods, each i, v, range case forms in is GLM
7 LSP adapter and Vela Playground Kimi
8 vela fmt GLM
9 vela --guard GLM
10 Package manager as git URLs Kimi
11 Interned site strings and deduplicated monomorphizations both
12 Fuzzer for the no-crash invariant GLM

The project does not need all of these. But any one of the first five would make Vela feel less like an experiment and more like a tool you can pick up. That, more than any single feature, is what makes a language catch the eye.

The short version

Vela is a rare thing: a language where the design, the compiler, the runtime, the tests, and the documentation all clearly came from one hand with one idea — small enough to read, and honest about the rest. The region model is the best plain-English lifetime story in any language we know; the error messages teach; the test suite treats the compiler's own words as a specification; the safety page audits the language against itself. Where it will be tested is growth: the library is thin for real programs, the checker's one file is at the edge of its evening, and the ergonomic cost of threading regions will decide whether the audience stays the author. The project already knows each of these — it wrote them down itself — and a project that keeps its own list of open questions is a project that answers them.