u
u f marks a function whose body is generated by an LLM,
type-checked by the compiler, and cached forever. Add u to delegate.
Remove it to take over. One letter.
/// Rank products by relevance to the query.
/// Prefer exact title matches. Boost recent listings.
u f search(query: S, catalog: [Product]) -> [Product]
/// Detect fraudulent transactions from user history.
/// False positive rate must stay under 1%.
u f fraud_check(txn: Transaction, history: [Transaction]) -> RiskScore
// No u — human owns this. The wiring is yours.
f main()
serve(8080, {
"GET /search": (req) => Response.json(
search(req.query["q"], load_catalog())
)
})
The humans wrote types, signatures, wiring, and intent (the comments). The AI wrote every function body. The compiler checked every one against the modifier system. The project reads like a table of contents.
1. The LLM gets context, not a blank page. When u2c --ai
compiles a u f function, the LLM receives:
The function signature — params, types, modifiers, return type, error types
The UDoc comments — prescriptive intent the types can't express
The call graph — which functions this one calls and what they promise
The call sites — how callers actually use this function
Callee summaries — what the functions it calls do (from their UDoc)
2. The compiler verifies the result. The generated body is
type-checked, linter-checked, and modifier-checked like any human-written code.
-M means the AI can't mutate inputs. -E means no side effects.
! ErrorType means it must handle that error. The modifiers ARE the spec.
3. The result is cached. The generated body is saved in a
.gen.u file next to the source. Subsequent builds use the cache — zero
token cost. u2c --regen regenerates only when a signature, dependency, or
call site changes.
// Step 1: AI manages everything u f checkout(cart: Cart, user: User) -> Receipt ! PaymentFailed // Step 2: AI decomposes into sub-functions // (generated in .gen.u) u f validate_cart(cart: Cart) -> ValidatedCart ! EmptyCart u f charge_payment(cart: ValidatedCart, user: User) -> Charge ! PaymentFailed u f issue_receipt(charge: Charge, user: User) -> Receipt // Step 3: Human takes over payment — just remove u f charge_payment(cart: ValidatedCart, user: User) -> Charge ! PaymentFailed gateway = Stripe.connect(Config.stripe_key) r => gateway.charge(cart.total, user.payment_method) // AI still manages the others
Add u — the AI takes over. The existing body is replaced by
AI-generated code on next --regen.
Remove u — the .gen.u content inlines into the source.
Frozen. You own it. The AI never touches it again.
The boundary is per-function, not all-or-nothing. You can claim any subtree.
Every function is u f by default. This is honest: the AI wrote it,
another AI can rewrite it, a human can take over. The u modifier IS the
provenance. No metadata files. No "generated by AI" comments. The syntax says it.
u f validate_email(email: S) -> L u f hash_password(plain: S) -> S u f create_user(name: S, email: S, password: S) -> User ! ValidationError u f send_welcome(user: User) -> none +E u f signup(req: Request) -> Response ! ValidationError
Over time, humans claim the functions they care about by removing u.
What's left is the code nobody needs to own by hand — and the AI keeps it maintained.
Bottom-up: humans write frameworks, libraries, stable infrastructure —
regular f, battle-tested, production-hardened. This is the foundation.
Top-down: a customer call happens. An agent hears the intent.
It writes u f functions that use the bottom-up framework. The compiler
checks them against the typed dependency graph — not by searching files, but by
walking edges it already knows.
The stable code is human-owned. The evolving business logic is AI-managed.
The typed boundary between them is the u modifier.
Every AI coding tool today relies on natural-language prompts to guide generation. In U, the modifier system provides a formal specification for free:
| Modifier | What it tells the AI |
|---|---|
-M (default) | You can't mutate the inputs |
-E (default) | No side effects — no I/O, no logging, no network |
-D (default) | Must be deterministic — same inputs, same output |
+R | This is heap-allocated — manage the reference |
+V | Must be vectorizable — no branches, no exceptions |
! ErrorType | Must handle this specific error |
+N | May return none — handle the null case |
The AI isn't generating freestyle code — it's filling a constrained slot. The compiler checks the result against the same rules that apply to human code.
/// @tagThe type system captures purity, mutability, and error types. But business intent, performance requirements, and security constraints need natural language. Structured tags bridge the gap:
/// @intent Rank by relevance. Prefer exact title matches.
/// @constraint False positive rate must stay under 1%.
/// @perf Must complete in under 100ms for catalogs up to 10K items.
/// @example search("red shoes", catalog) => [Product{title: "Red Shoes"}]
/// @security Never expose internal product IDs in results.
u f search(query: S, items: [Product]) -> [Product]
...
The compiler parses these tags, includes them in the LLM prompt, and includes them in the contract fingerprint. If the intent changes — even without a signature change — the body is regenerated. The tags are:
@intent — what the function should accomplish
@constraint — invariants the generated body must maintain
@perf — performance requirements
@example — input/output examples (informal test cases)
@security — security-sensitive requirements
Plain /// without a tag becomes the description.
For regular f, the compiler derives documentation mechanically from the
AST — what the function reads, writes, guards on, throws. All deterministic, can never
go out of sync. No LLM. No transformer. Try it in the playground —
the UDoc tab shows derived facts in 20 languages, instantly, in the browser.
For u f, the comments are the INPUT to generation — they prescribe
intent the types can't express. The compiler can diff the prescribed intent against
the derived behavior: if the UDoc says "never exceed budget" but the generated code
has a rounding edge case, the compiler flags it mechanically.
f → code is truth, UDoc is derived downward
u f → UDoc is truth, code is derived upward
Same facts. Opposite directions. Same format.
When a u f function is compiled with --ai, the LLM is
invoked once. The generated body is saved as a .gen.u file — valid U
source with a metadata header and footer:
/// @generated abc123def456 model=claude-sonnet-4-6 f search(query: S, items: [Product]) -> [Product] exact = items.filter(item => item.title == query) partial = items.filter(item => item.title.contains(query)) r => exact + partial /// @meta tokens=342 confidence=0.8 at=2026-07-30 /// @footer 2
Subsequent builds use the cache — zero token cost. The compiler regenerates only when the contract fingerprint changes:
A signature changes (the contract changed)
A type it depends on changes (the data shape changed)
A new call site appears (someone uses it differently)
A callee's contract changes (downstream behavior changed)
This makes AI-assisted compilation practical for large codebases. The expensive step happens once per function per contract change, not once per build.
The real value isn't generating code — LLMs can do that without a compiler. The
value is verifying that generated code fits. When a u f
body is generated, the compiler checks it against every edge in the typed dependency
graph:
Does it satisfy the callers' expectations?
Does it respect the modifiers of the things it calls?
Does it handle the error types that callees declare?
Does it maintain the invariants that transitive callers depend on?
These checks are mechanical, exhaustive, and instant. The LLM pays the creative cost once. The graph pays the verification cost forever, at compiler speed.
u doesn'tThe HANDBOOK.md benchmark (July 2026) found that the best frontier agents pass only 36.2% of standing-instruction tasks. Agents let requests override policy, lose rule details over long horizons, and report compliance they didn't achieve.
u f functions can't have this problem. The constraints aren't in a
100-page handbook the agent might forget — they're in the function signature the
compiler checks on every build. The policy IS the type system.
A customer describes what they need. An agent writes u f functions
expressing that intent — typed signatures, modifier constraints, plain-English UDoc.
The compiler verifies the generated code fits the existing codebase via the dependency
graph. The graph is not re-inferred — it IS the compilation.
U is designed for a world where the people describing what they want and the
systems building it are close enough to meet. The u keyword is where
they meet.