verona-coding
Skill3.7k starsChanged 3 months agoMITView on GitHub
Patterns, pitfalls, and idioms for writing Verona source code (.v files). Use when writing library code, _builtin types, or user programs.
Trending
Quiet this year.about the whole repository
Who's talking about microsoft/verona
- A Hacker News story“Microsoft Project Verona: Research programming language for concurrent ownership”Hacker News · Jan 17, 2020 · 142 points
- A Hacker News story“Project Verona FAQ”Hacker News · Feb 10, 2020 · 29 points
- A Hacker News story“Project Verona: Research programming language for concurrent ownership”Hacker News · Jan 16, 2020 · 7 points
- A Hacker News story“Microsoft/Verona”Hacker News · Jan 18, 2020 · 3 points
- A Hacker News story“Concurrent Ownership in Verona”Hacker News · Dec 14, 2022 · 2 points
The biggest 5 of 18 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 18
Talked about on GitHub and Hacker News (18 times).
On GitHub · 12
- Dec 31, 2023Check ideas from Verona language for concurrency — lambdaclass/concrete0 reactions
- Jul 21, 2023Add Verona — ChessMax/awesome-programming-languages0 reactions
- Jul 13, 2023Move the Verona compiler to microsoft/verona — microsoft/Trieste0 reactions
- Oct 24, 2022Optimise for waking an empty queue — microsoft/verona-rt0 reactions
- Oct 24, 2022Token source — microsoft/verona-rt0 reactions
7 more on GitHub
- Oct 20, 2022Small optimisations and refactors around message send and receive — microsoft/verona-rt0 reactions
- Jul 29, 2022Don't run CI on doc-only changes — microsoft/CCF0 reactions · 4 comments
- Aug 26, 2021Enable passthrough to an underlying allocator — microsoft/snmalloc0 reactions · 1 comment
- Jan 25, 2021Meta: Some interesting pointers to borrow ideas — flix/flix0 reactions · 1 comment
- Jan 4, 2021Meta: Some interesting pointers to borrow ideas — HigherOrderCO/Kind0 reactions
- Jun 18, 2020Refactor Pal and LargeAlloc interaction. — microsoft/snmalloc0 reactions
- Jan 27, 2020Automating keeping snmalloc up to date. — SchrodingerZhu/snmalloc-rs0 reactions · 2 comments
On Hacker News · 6
- Jan 17, 2020Microsoft Project Verona: Research programming language for concurrent ownership142 points · 16 comments
- Feb 10, 2020Project Verona FAQ29 points · 8 comments
- Jan 16, 2020Project Verona: Research programming language for concurrent ownership7 points
- Jan 18, 2020Microsoft/Verona3 points
- Dec 14, 2022Concurrent Ownership in Verona2 points
1 more on Hacker News
- Sep 17, 2023Microsoft Project Verona, a research programming language1 point
In this repository19 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- add-testSkill
- debugSkill
- docs-updateSkill
- reviewSkill
- testsuiteSkill
- vbci-memorySkill
- verona-conventionsSkill
- verona-type-inferenceSkill
- add-testSkill
- docs-updateSkill
- reviewSkill
- testsuiteSkill
- vbci-memorySkill
- verona-codingSkill
- verona-conventionsSkill
- verona-type-inferenceSkill
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 4 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 24
No operator precedence: All infix operators evaluate left-to-right.
- Distinctive: line 39
NOT field access + apply.
- Very specific: line 40
Zero-arg getters don't need
(): Write self.data not self.data(), self.size not self.size(). - Distinctive: line 58
Passing lambdas to methods: Use juxtaposition, NOT wrapping parens.
- Very specific: line 66
No trailing semicolon: when a lambda call is a statement by itself (the } ends the expression).
- Distinctive: line 121
Don't wrap expressions in unnecessary parens: only use parens when needed for grouping (e.g., operator precedence).
- Very specific: line 138
Don't use
()unnecessarily: if a type or value needs no arguments, omit the parens. - Very specific: line 145
No semicolons after closing braces of if/while/for.
- Very specific: line 153
Prefer paren-less syntax for clear zero-arg and single-arg calls: handle::signal, tty, self.init handler, pipe::open 0.
- Distinctive: line 161
Use bitmask accumulation for multi-check tests:
- Very specific: line 181
Synchronous setup failures need their own path: if a wrapper can fail before it becomes active (for example pipe.open(fd)), don't route the …
- Very specific: line 185
Capture sendable wrappers in FFI callbacks: when a callback must refer back to an owned state machine, capture the outer sendable wrapper …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Verona Coding Skill
Patterns, pitfalls, and idioms for writing Verona source code. Use this skill
when writing .v files — library code, _builtin types, or user programs.
Literal Types and Inference
- Avoid explicit literal constructors (e.g.,
u64 0,i32 3). Let type inference determine the type from context. If inference fails, that's a compiler bug to fix — report it rather than working around it. - Known inference gap: Union return types (e.g.,
usize | none) don't refine bare literals.return 0in a function returningusize | nonegivesu64, notusize. This is a compiler bug to be fixed. compare()returnsi64: comparing with bare0works — inference resolves from thei64return type ofcompare().
Operators
- No operator precedence: All infix operators evaluate left-to-right.
Operators, methods, and functions are all the same thing — you can use
non-symbolic names in the infix position too (e.g.,
a min b). - Consequence:
cap < n + 1evaluates as(cap < n) + 1. Use parens to group:cap < (n + 1). - Juxtaposition binds tighter than infix:
a(i)binds before any infix operator, sosum + a(i)works as expected. - Bool or is
|, bool and is&. Since there's no precedence, parenthesize each comparison:(c == 32) | (c == 9) | (c == 10). - Free functions need qualification:
string::is_space(c), notis_space(c). Unqualified names resolve as method calls on the first arg.
Field Access vs Method Call
- Dot consumes arguments:
self.data(i)calls methoddatawith argi, NOT field access + apply. - Zero-arg getters don't need
(): Writeself.datanotself.data(),self.sizenotself.size(). Parens are unnecessary for zero-extra-arg methods (onlyself). - Field-then-apply:
self.data()(i)— the first()is needed to disambiguate fromself.data(i)(which calls methoddatawith argi). But when chaining further:self.data.pairs ...— no parens needed ondatabecausepairsis consumed by dot, not by juxtaposition. - For local variables:
result(i)works directly (no field access ambiguity). refkeyword on functions:ref apply(...)returns aref[T], enabling both read and write through the result. Useref self.data()(index)to delegate ref access.
Lambda Syntax and Higher-Order Functions
- Lambda syntax:
(params) -> { body }. Examples:(x: i32) -> { x + 1 }(i, c) -> { ... }(types inferred from context){ body }(zero-arg lambda)
- Passing lambdas to methods: Use juxtaposition, NOT wrapping parens.
The lambda IS the argument:
NOTself.data.pairs (i, c) -> { ... }self.data.pairs((i, c) -> { ... })— the extra parens are unnecessary. - No trailing semicolon when a lambda call is a statement by itself
(the
}ends the expression). raisein a lambda is a non-local return — it exits the ENCLOSING function, not the lambda. The lambda's own return type is unaffected byraise.
String Literals and Immutability
- Verona has deep immutability via
freeze— any object can be mutable or permanently immutable. This is NOT like C++const. - String literals should be frozen, not copied. The compiler wraps ConstStr
in
string::create()and then freezes the result. The frozen string directly references the constant pool array — no copy. create()should NOT copy the input array. It just wraps it:create(data: array[u8]): string { new { data, len = data.size - 1 } }- Mutation on a frozen string is caught naturally — you can't mutate an immutable object. If you want a mutable string, explicitly create one.
- The copy-on-create approach is C++ thinking. Verona's model: keep the original, make it immutable, copy only when mutability is needed.
Character Literals
- Space literal
' 'causes parser issues in nested control flow. Use the numeric value32instead. Other char literals like'a'work fine. - Common ASCII values: space=32, tab=9, newline=10, carriage return=13.
Union Return Types
usize | noneis a union type. Callers consume it with match/else:match s.find("x") { (i: usize) -> i; } else { 99 }- Returning a loop variable from a union-return function can cause the
variable to become
dyn. Copy to a typedletfirst (see Literal Types section above).
Style
- Match expression syntax — format like control flow, not inline:
Notmatch expr { (pattern) -> body; } else { default }match expr { (pattern) -> body; } else { default }on one line. - Don't wrap expressions in unnecessary parens: only use parens when needed for grouping (e.g., operator precedence).
Performance
- Use bulk operations over byte-by-byte loops:
array.copy_from()wrapsmemmove(handles overlapping regions). Use it for shifting data within the same array instead of while loops. - Avoid double-moving data:
replaceshould shift the tail once to its final position and copy the replacement in, not callerasetheninsert(which shifts the tail twice). copy_fromfor self-overlapping copies:self.data.copy_from(dst, self.data, src, len)works correctly for overlapping regions — it'smemmove, notmemcpy.none— no parens needed. Writenonenotnone().- Don't use
()unnecessarily: if a type or value needs no arguments, omit the parens.none,true,false, notnone(),true(),false(). - Empty string:
string(array[u8]::fill(1))— a 1-byte array containing just the null terminator, withlen=0.
Syntax Reminders
- No semicolons after closing braces of
if/while/for. - Semicolons after statements and field definitions.
new { field = val }— no class name afternew.Type(args)is sugar forType::create(args).array[u8]::fill(n)allocates an array of sizen(zero-filled).self.lencalls the getter (zero-arg method, no parens needed).f()calls a zero-arg callable value. Don't drop the parens on lambda/function values just because zero-arg methods omit them.- Prefer paren-less syntax for clear zero-arg and single-arg calls:
handle::signal,tty,self.init handler,pipe::open 0. self.len = xcalls the setter.final(self: T)receives a read-only self. Don't call mutating helpers likeself.closefrom a finalizer; inline read-only-safe cleanup instead.
Testing Patterns
- Use bitmask accumulation for multi-check tests:
var result = 0; if cond1_fails { result = result + 1 } if cond2_fails { result = result + 2 } // ...powers of 2... result // exit code 0 means all passed - Tests must be self-contained — no external dependencies, no
use "_builtin".
FFI / libuv Wrapper Lifetimes
- Tie keepalive to the real external lifetime: for libuv-backed wrappers,
use timer-style
_activate(active)plus handler-safe deferred release (_finish_handler) soffi::pin/ffi::unpinandffi::external.add/ffi::external.removetrack active handles or pending requests. - Don't rely on incidental references: a callback closure or unrelated signal watcher may accidentally keep a wrapper alive for a while, but that is not a sound lifetime strategy.
- Synchronous setup failures need their own path: if a wrapper can fail
before it becomes active (for example
pipe.open(fd)), don't route the error through an active-only dispatch helper — use a separate ungated failure callback path. - Capture sendable wrappers in FFI callbacks: when a callback must refer
back to an owned state machine, capture the outer sendable wrapper (or another
sendable handle), not a cown-owned mutable
_statedirectly.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

