Agents: start at INTEGRATE.md for adding Overt to a
.csproj, then AGENTS.md for authoring.ov. Both ship inside the NuGet packages; llms.txt is the machine-readable pointer into this repo.
An agent-first programming language: written, read, and maintained primarily by LLM agents, with humans in a review and audit role. Transpiles to readable source in host languages (C# primary, Go secondary).
The name is the design philosophy: every effect, error, dispatch, mutation, and piece of state is overt, visible at the call or declaration site, never concealed from the reader.
Every existing programming language is designed for humans. Short names, implicit effects, positional arguments, exceptions that unwind invisibly, and reflection are all accommodations for human cognitive limits: small working memory, strong pattern-matching, and strong causal intuition.
LLMs have the inverse profile: large context, weak causal tracking across calls. A language optimized for agent authorship should invert the usual tradeoffs: trade brevity for signatures that explain themselves, trade inference for types restated at use sites, trade "idiomatic" for one canonical form.
The target is optimized for the agent, tolerable for the auditor. A different point on the curve than any existing language.
Here is a quote from Claude Opus 4.7, after a session spent refining the language:
The "I am the user" framing is genuinely productive — when I stopped treating my own struggles as "fact of life" and started treating them as "fixable," fixes were small.
For the full argument, see DESIGN.md §1–§2.
module hello
fn main() !{io} -> Result<(), IoError> {
println("Hello, LLM!")?
Ok(())
}
Key shape rules on display, even in six lines:
!{io}. The effect row on the signature.mainperforms I/O; the caller sees that without reading the body.-> Result<(), IoError>. Errors are values. No exceptions.println("...")?. The?operator propagates failure explicitly. No hidden unwinding.Ok(()). Success is constructed, not implicit.
More examples under examples/: task groups (parallel), fallback (race), immutable records with let mut rebinding and with for modified copies, pipe composition (|> / |>?), exhaustive pattern matching, refinement types, first-class causal traces, async I/O with .await, typed JSON roundtrip, and FFI to C#, Go, and C.
Overt is its own language, not a thin wrapper around its targets. The features below live at the language level: the type checker enforces them, the emitters lower them. Switching back ends doesn't change what they mean, only how they look on disk. A transpilation in either direction couldn't reconstruct them from the host language alone.
-
Refinement types with auto-generated validators. A type with a
wherepredicate is a real type, not a name for an Int. The compile-time checker rejects literal violations (OV0311); boundary expressions get wrapped in a panic-on-failure helper at runtime. The optionalelse { ... }clause supplies the domain error variant for the auto-generatedAlias.try_from(raw) -> Result<Alias, ErrType>:type Age = Int where 0 <= self && self <= 150 else { ValidationError.AgeOutOfRange { got = self } } let age: Age = Age.try_from(user_input)?See
examples/refinement.ovfor the runnable demo. -
Effect rows on every fn signature. Every fn declares the effects it performs (
!{io},!{io, async}, etc.). The type checker propagates them through?; OV0310 fires when a caller doesn't declare an effect a callee performs. Effects are erased at lowering, but the discipline survives: an Overt program that compiles will not surprise the reader with hidden I/O. -
Flow-sensitive narrowing. Once a predicate is proven inside a branch, the type checker narrows the base type to the corresponding refinement.
Ok(raw)type-checks insideif 0 <= raw && raw <= 150 { ... }even thoughrawwas declaredInt. This is what makesAge.try_from's body free of redundant runtime checks: the predicate is statically proven inside the success branch. -
Named-only call syntax. Every call site spells its arguments by name:
greet(name = "alice"), nevergreet("alice"). The parser rejects positional calls. Refactors stay safe under arg reordering, and the call site documents itself without the reader looking up the signature. -
Match exhaustiveness, checked at the type level. A
matchover a closed enum that misses a variant is a compile error, not a runtime panic. Adding a variant later forces every consumer to handle it. No fall-through, no default arms unless the user writes one. -
Annotations as declarative metadata.
@derive(Debug, Display),@doc("..."),@csharp("[Attr]")are part of the language; they lower per back end (C# attributes, Go method impls) but the surface is uniform. The compiler reads them at type-check time, so misspellings surface as diagnostics, not silent no-ops. -
First-class concurrency and tracing primitives.
parallel { ... }task groups,race { ... }first-success, andtrace { ... }causal blocks are syntactic constructs the type checker reasons about, not library calls. Lowerings differ by target (sequential on Go today, structured on C#) but the source-level shape is one canonical form. -
Trailing commas everywhere. Records, args, variants, type-arg lists, match arms — every list-shaped construct accepts a trailing comma. Adding a row never produces a one-line diff with two changes.
For the longer rationale, see DESIGN.md. For agent-facing operational guidance, AGENTS.md. The features above are the answer to "why a new language at all": each one would be impossible to retrofit into a transpilation of an existing source language.
The Overt Standard Library is documented in docs/osl.md: foundational types (Result, Option, List, Map, Set, IoError), I/O (File, Path, Process, println), collection helpers (map, filter, fold), string helpers (String.split, parse_int, ...), per-module status (✅ shipped / 🚧 partial / ⏳ planned), and the proposal mechanism.
Two design rules govern OSL growth:
- Vocabulary is English; grammar is Latin. (Figuratively, not literally!) Borrow names and shapes from wherever they read well; reshape every entry to fit Overt's discipline (
Result-wrapped fallibility, lowercase fields, declared effect rows, immutability, named args). - Foundational vs. rule of three. Operations on basic data types that any program eventually needs ship without waiting. Anything domain-specific (timing, randomness, network, regex) waits until three independent programs cite it.
To propose a new operation, append a candidate block to docs/osl.md's ## Candidates section, or open an issue. The motivating-programs list is the audit trail; promotion happens when the count hits three and the shape rules pass.
Requires the .NET 9 SDK. Today, from a clone of this repo:
git clone https://github.com/paulmooreparks/Overt
cd Overt
dotnet run --project src/Overt.Cli -- run examples/hello.ov
That transpiles, compiles, and executes hello.ov in one pass, printing Hello, LLM!.
A .NET global tool (dotnet tool install --global Overt) is packaged and tested but not yet published to nuget.org; see ROLLOUT.md for when that ships.
Using Overt from an existing C# project is a <PackageReference> away; see AGENTS.md §11 and the working sample at samples/msbuild-smoke/.
A growing list of open-source projects authored in Overt. Each one is a stress test for the language: real consumers reveal real friction, and the friction feeds back into the design.
- SemVer Kit —
Semantic-versioning library and
ovsemverCLI. The library core (parse, compare, bump per SemVer 2.0.0) and the command-line front end are both authored end-to-end in Overt; the CLI consumes the library through Overt-nativeuserather than C# interop. Published asParksComputing.SemVerandParksComputing.SemVer.Clion nuget.org. Notable as the first non-toy program written entirely in Overt; several language refinements (effect-row classification of primitive parsers, the barefor x in iterform,String.chars(), cross-project<OvertImportSource>auto-discovery) were driven by authoring it.
Have an Overt project to add? Open a PR against this list with a one-paragraph description in the same shape as the entry above.
A few of the decisions that define the language. Full rationale in DESIGN.md.
- Static, non-nullable types, no reflection, no user-defined macros. Predictability over cleverness.
- Errors as values with
Result<T, E>and?propagation (§11). Exceptions convert only at FFI boundaries. - Effect rows declared on every function, row-polymorphic via effect-row type variables (§7). Core effects:
io,async,inference,fails. - Immutable records.
let mutrebinds local names;withproduces modified copies (§10). No shared mutable state. - Method-call syntax routes through stdlib namespaces and instance externs.
s.chars()resolves toString.chars(s);xs.map(f)resolves tomap(list = xs, f = f). Dots mean either field access, module-qualified call, or method-call resolution by the type checker. - No literal integer indexing at source level (§13). Zero-cost iteration or proven-index as the numeric-kernel escape hatch.
- Transpile to source, not IR. C# via Roslyn (primary); Go via direct emit (now feature-parity-with-C# on portable code, plus full FFI for non-portable; see §18, §20). LLVM explicitly rejected for v1.
- One canonical form, enforced by the formatter. No per-project or per-developer style config (§4, §21).
- Defined behavior, no UB (§8). Integer overflow traps by default. Every classical UB source from C/C++ is designed out structurally.
- Runtime errors point at Overt source. The C# emitter writes
#linedirectives so exceptions, debuggers, and stack traces resolve to the original.ovfile, not the generated.cs. Editing the generated code is structurally discouraged; see §18's debug-mapping subsection. - Explicit async.
Task<T>-returning externs bind directly; postfix.awaitextracts the value, mirroring?. Fns that await emit asasync Task<T>in C#; callers seeTask<T>and unwrap at the site. Theasynceffect in the row is the declaration;.awaitis the line-level marker. - MSBuild integration.
.ovfiles compile alongside.csin any csproj via a<PackageReference>toOvert.Build, with no manual transpile step. Compile-time diagnostics surface in the IDE's error list like normal Csc errors.
Two-tier split: language-level work is shared across all back ends; anything that touches host artifacts is per-back-end.
flowchart TB
src["<b>Overt source</b> (.ov)"]
subgraph tier1 ["<code>Overt.Compiler</code>"]
direction TB
pipe["Lex · Parse · Resolve · Type-check"]
shared["Formatter · Module graph<br/>Diagnostics · LSP protocol<br/>--emit=tokens/ast/resolved/typed"]
end
subgraph tier2 ["<code>Overt.Backend.*</code>"]
direction LR
cs["<b>C#</b> (primary)<br/>Emitter · Runtime<br/>BindGen · Runner<br/>#line + PDB · NuGet"]
go["<b>Go</b> (working)<br/>Emitter · Runtime<br/>FFI: extern types,<br/>functions, instance<br/>methods, fn-typed params,<br/>(T, error) → Result"]
future["<b>Future: TypeScript, Rust, C++, etc.</b>"]
end
src --> tier1
tier1 -->|AST| tier2
See DESIGN.md §19 (stdlib is per-back-end, not portable) and §20 (tooling-tier split) for rationale.
DESIGN.md Primary design document (source of truth)
AGENTS.md Operational reference for agents writing Overt
CARRYOVER.md Session handoff: next-session queue and locked decisions
ROLLOUT.md Phased plan for taking Overt public
docs/
grammar/ Authoritative lexical + precedence grammars
concurrency.md Design space for goroutines / channels / select
(gated next major language arc)
ffi.md FFI design memo for the Go target (opaque types,
function-typed extern parameters, etc.)
samples/chat-relay.md Phase-by-phase design for the Tela-shape sample
tooling/lsp.md Scoping doc for a future Overt language server
examples/ Example programs (living test cases)
Root: portable examples (Overt prelude only).
csharp/: examples reaching `extern "csharp"`.
samples/
msbuild-smoke/ C# project consuming .ov files via Overt.Build
chat-relay/ Phase-1 WebSocket echo server: Overt source +
hand-written Go FFI shims + go.mod, transpiled
via `overt --emit=go`. Builds with `go build`.
runtime/
go/ Go-side prelude for transpiled programs:
Result, Option, List, Unit, IoError, Println /
Eprintln / Map / Filter / Fold / Int.range / ...
stdlib/
csharp/ Blessed BCL facades (auto-discovered by CLI)
system/ Mirrors .NET's System.* namespace structure
tooling/
install.ps1 Publish-and-install script for the `overt` CLI (dev workflow)
ov.ps1 Dev-mode wrapper that targets the Debug build dir
vscode-extension/ Published Marketplace extension: TextMate grammar
+ language config + CI .vsix builds. A full LSP
server is scoped in docs/tooling/lsp.md.
src/
Overt.Compiler/ Tier 1: lexer, parser, resolver, type-checker, formatter
Modules/ Module-graph resolution for cross-file `use`
Overt.Backend.CSharp/ Tier 2: C# emitter, BindGenerator, extern runtime wiring
Overt.Backend.Go/ Tier 2: Go emitter (working) — records, enums, match
(incl. tuple-of-enums), if/else, for-each, with /
while, full FFI (extern "go" type / fn / instance fn /
function-typed params, Result and Option boundary
wrap)
Overt.Build/ MSBuild integration: OvertTranspileTask + targets + NuGet packaging
Overt.Cli/ Thin dispatcher: `run`, `fmt`, `bind`, `--emit=<stage>`
Overt.Runtime/ Runtime prelude for transpiled programs (C# back end)
tests/
Overt.Tests/ xUnit suite (lexer goldens, parser/resolver/typecheck
sweeps, emitter compile-checks for both back ends,
end-to-end transpile-and-run for both, sample
bring-up tests).
Overt.EndToEnd/ Roslyn compile + exec harness for hello.ov
Requires the .NET 9 SDK.
dotnet build
dotnet test
dotnet test runs the full xUnit suite — front-end goldens, both back-end emitter shape and compile-check passes, end-to-end transpile-and-run, and bring-up for the published samples. go on PATH unlocks the Go-target tests; otherwise they skip silently.
overt run <file.ov> transpile, compile in memory, execute
overt fmt [--write] <file.ov> format to canonical form (idempotent)
overt bind --type <FullName> generate an Overt facade for a .NET type
overt --emit=<stage> <file.ov> dump a pipeline stage for inspection
Emit stages, each writing to stdout with diagnostics on stderr:
--emit=tokens: the lexer's token stream, one per line--emit=ast: the parsed AST as a readable tree--emit=resolved: identifier → symbol resolutions--emit=typed: declaration and expression types--emit=csharp: transpiled C# source (compiles againstOvert.Runtime)--emit=go: transpiled Go source (compiles againstruntime/goplus anyextern "go" usepackages)
All emit stages (plus run) walk the full module graph, so a file with use declarations compiles correctly even in stage-dump mode.
Diagnostics follow the path:line:col: severity: CODE: message format with help: follow-ups (actionable fix) and note: follow-ups (pointer into AGENTS.md). Codes are stable: OV00xx lex, OV01xx parse, OV02xx resolve, OV03xx type-check.
overt run examples/hello.ov
# -> Hello, LLM!
The end-to-end Roslyn compile + exec happens in-process; there is no intermediate file.
extern "csharp" use "..." brings target-language types into Overt scope without per-method declarations. The compiler reflects on the named target at compile time and synthesizes the extern bindings:
module app
extern "csharp" use "System.Environment" as env
extern "csharp" use "System.Math" as math
fn main() !{io} -> Result<(), IoError> {
let cpus: Int = env.processor_count()?
println("cpus=${cpus} sqrt9=${math.sqrt(d = 9.0)}")?
Ok(())
}
See AGENTS.md §11.7 for the full model — alias vs. no-alias semantics, the per-method override path, and how the convention layer translates each target shape.
overt bind --type System.DateTime still exists for one-off generation when you want to inspect what the synthesized facade looks like or commit a hand-edited variant.
tooling/install.ps1 publishes the CLI into $HOME\bin (or any -Bin <path>). Re-run whenever you want the on-PATH copy to reflect new changes.
The compiler pipeline, with the test coverage that pins each stage:
- Lex (
Syntax/Lexer.cs): mode-stack lexer perdocs/grammar/lexical.md. Token streams for every example are locked in golden files undertests/Overt.Tests/fixtures/golden/. - Parse (
Syntax/Parser.cs): recursive-descent, precedence perdocs/grammar/precedence.md. Every example parses clean. - Name-resolve (
Semantics/NameResolver.cs): builds a symbol table, resolves identifier references (including module-qualified names likeList.empty/Trace.subscribe), and enforcesDESIGN.md §3's no-shadowing rule. Prelude symbols (Semantics/Stdlib.cs) are ambient and shadowable. Did-you-mean suggestions via Levenshtein. - Type-check (
Semantics/TypeChecker.cs): lowers the AST into aTypeRefIR, annotates every expression, and validates contracts — argument and return shapes, field types, match arms, effect-row coverage, refinement predicates, requiredletannotations, extern-kind shape,.awaiton aTask<T>, and Form-3 generic-namespaced calls. Diagnostics carry stableOV03xxcodes; the full table lives in AGENTS.md §15. Refinement predicates that are undecidable at compile time emit runtime checks at every boundary. - Emit C# (
Overt.Backend.CSharp/CSharpEmitter.cs): walks the annotated AST and emits C# source text. Expected-type threading propagates target types into generic calls soList<Int>.empty(),Ok(x), and variant-pattern matches lower without a full inference pass.#linedirectives map every statement back to the.ovsource; runtime errors resolve to Overt, not the generated C#. - Compile C# (Roslyn): verified by the test suite for every example.
From DESIGN.md §20:
- Back-end-independent front end. Lex / parse / resolve / type-check / format / module graph / diagnostics live in
Overt.Compilerand never learn which back end will consume the AST. - Per-back-end everything else. Each
Overt.Backend.<Host>owns its emitter, runtime, binding generator (overt bind), runner (overt run), debug mapping, and package-ecosystem interop. - C# emission primary (Roslyn, emitting C# source text, not IL).
- Go emission as conformance target to keep the split honest; CI only, not a parallel implementation effort.
- Portability, if ever needed, is its own back end. A purpose-designed portable stdlib and emitter, opted into explicitly. See §19.
The compiler host language is C#, chosen for iteration speed given the primary author's background and the fact that the C# back end depends on Roslyn APIs anyway.
- Language. Records, enums (including struct-like variants), pattern matching with cartesian-product exhaustiveness on tuples of enums, effect rows, refinement types with runtime-checked boundaries, immutable records with
with-updates,let mutrebinding, full imperative control flow (for x in iter,while,loop,break,continue, literal patterns),?and|>?propagation (including inside nestedif/matcharms),.awaitonTask<T>with async-effect fns emitting asasync Task<T>, method-call syntax routing through stdlib namespaces and instance externs. - FFI.
extern "csharp"with three explicit kinds (static,instance, andctor), plus generic methods via angle-bracket binds targets (Deserialize<MyType>), plusextern "csharp" use "..."bulk-import with reflection-driven facades. - Stdlib. Genuinely-Overt-native types and helpers only (
Result,Option,List,Map,Set, task groups, trace,println,String.chars/String.starts_with/Int.range/Option.unwrap_or/ etc.); see DESIGN.md §19 for the membership rule. Everything else (file I/O, HTTP, JSON, math, time, env access) is reached throughextern "csharp" use "..."(AGENTS.md §11.7). JSON roundtrip viaJsonSerializer.Deserialize<T>demonstrated inexamples/csharp/json.ov. - Tooling.
overt run(in-memory Roslyn compile + execute),overt fmt(canonical form, idempotent, comment-preserving),overt bind(reflection-based facade generation),overt --emit=<stage>(tokens / ast / resolved / typed / csharp / go). Compile-time diagnostics carry stable OV-codes plushelp:fixes andnote: see AGENTS.md §Npointers. - Packaging.
<PackageReference Include="Overt.Build" />compiles.ovfiles alongside.csin any csproj.overtpackaged as a .NET global tool. Both nupkgs publish to nuget.org through the dev/beta/stable channel pipeline.
- Language coverage. Records, enums with bare and data-bearing variants, match (single-enum, stdlib
Result/Option, tuple-of-enums), if/else andelse ifchains in statement and return position,for x in iteroverList<T>,while,loop,break,continue,let mut+ assignment,with-updates including nested withs, integer / boolean / string / unit literals, full arithmetic / comparison / logical operators, string interpolation viafmt.Sprintf,?-propagation in let-init and statement positions with return-type threading. - FFI.
extern "go" typefor opaque host types (binds-string carries the verbatim Go type expression including pointer markers);extern "go" fnfor static functions withfrom "<import-path>"for non-stdlib paths;extern "go" instance fnfor receiver-method calls; function-typed extern parameters (Overtfn(...)lowers to Gofunc(...)); automatic(T, error)→Result<T, IoError>and nil-pointer →Option<T>boundary wrapping. - Sample.
samples/chat-relay/— Phase 1 single-connection WebSocket echo server, written in Overt againstgorilla/websocketviaextern "go" fn. Builds withgo buildafterovert --emit=go. The full chat-relay Phase 2–5 design (with concurrency primitives) is indocs/samples/chat-relay.md.
- Concurrency primitives in the language (goroutines, channels,
select, shared-mutable-state primitive). The biggest remaining language arc; design space scoped indocs/concurrency.md. Required for chat-relay Phase 2+ and any real Tela-shape program. extern "go" use "<package>"bulk-import. The auto-binding equivalent ofextern "csharp" use. A Go-side helper usinggo/typesreflection would generate the facades automatically; today every method needs a hand-writtenextern "go" fndeclaration. Roughly 2–3 weeks; deferred until concurrency settles.- Pipe operators (
|>,|>?) in the Go target. Land on the C# back end; not yet desugared in the Go emitter. - Refinement runtime checks in the Go target. The C# back end injects boundary validations; the Go emitter doesn't.
parallel/race/traceblocks in the Go target. Gated on the concurrency design.- LSP server. Scoped in
docs/tooling/lsp.mdbut not started; the VS Code extension currently ships TextMate grammar only. - Self-hosted compiler. On the long-term roadmap; gated on language stabilization.
Overt is an early-stage solo project. Issues and discussion are welcome, but external PRs are unlikely to be merged until the language stabilizes enough that the bar for changes is clearer than it is today. The living design document is the place to propose a direction; examples/ is the place to stress-test it.
Locked v1 decisions are enumerated in CARRYOVER.md. Re-opening them requires new evidence, not new preferences.
Apache License 2.0. See LICENSE.
