Introduction
Overview
Gent is a domain-specific language designed for building AI agents with type-safe outputs, radical transparency, and first-class support for agents, tools, and structured data.
This document is the definitive reference for the Gent programming language. It describes the syntax and semantics of Gent programs in precise detail.
Notation
The syntax is specified using a variant of Extended Backus-Naur Form (EBNF):
Production = production_name "=" Expression .
Expression = Term { "|" Term } .
Term = Factor { Factor } .
Factor = production_name | literal | "[" Expression "]"
| "(" Expression ")" | "{" Expression "}" .Productions are expressions constructed from terms and the following operators:
|alternation( )grouping[ ]option (0 or 1 times){ }repetition (0 to n times)
Source Representation
Source code is Unicode text encoded in UTF-8. Each code point is distinct; for instance, uppercase and lowercase letters are different characters.
character = /* any Unicode code point */ . letter = "A" ... "Z" | "a" ... "z" . digit = "0" ... "9" .
Lexical Elements
Identifiers
Identifiers name program entities such as variables, types, and functions. An identifier is a sequence of letters, digits, and underscores, beginning with a letter.
identifier = letter { letter | digit | "_" } .myVariable
_private
camelCase
snake_case
Agent1Keywords
The following keywords are reserved and cannot be used as identifiers:
agentbreakcatchcontinueelseenumfalsefnforifimportininterfaceletmatchnullparallelreturnstructtooltruetrywhileLiterals
String Literals
String literals are character sequences enclosed in double quotes. They support escape sequences and string interpolation with {expr}.
string_literal = '"' { string_char | interpolation } '"' .
multiline_string = '"""' { any_char } '"""' .
interpolation = "{" expression "}" .
escape_sequence = "\" ( '"' | "\" | "n" | "r" | "t" | "{" | "}" ) ."Hello, World!"
"Value: {x + 1}"
"Line 1\nLine 2"
"""
Multi-line
string literal
"""Number Literals
number_literal = digit { digit } [ "." digit { digit } ] .42
3.14159
0.5Boolean Literals
boolean_literal = "true" | "false" .
Null Literal
The null literal represents the absence of a value.
Array Literals
array_literal = "[" [ expression { "," expression } ] "]" .[1, 2, 3]
["a", "b", "c"]
[]Object Literals
object_literal = "{" [ object_field { "," object_field } ] "}" .
object_field = ( identifier | string_literal ) ":" expression .{ name: "Alice", age: 30 }
{ "key-with-dashes": value }Duration Literals
Duration literals specify time spans, used in parallel execution timeouts.
duration_literal = digit { digit } duration_unit .
duration_unit = "ms" | "s" | "m" .100ms // 100 milliseconds
30s // 30 seconds
5m // 5 minutesTypes
Primitive Types
Gent provides the following primitive types:
stringUnicode textnumber64-bit floating pointbooleantrue or falsenullAbsence of valueComposite Types
arrayOrdered collection of valuesobjectKey-value mappinganyAny type (escape hatch)Struct Types
A struct is a named composite type with typed fields. Structs define the schema for agent outputs and tool parameters.
struct_decl = "struct" identifier [ implements ] "{" struct_body "}" .
implements = "implements" identifier { "," identifier } .
struct_body = { struct_field [ "," ] } .
struct_field = identifier ":" field_type .
field_type = type_name | type_name "[]" | "{" struct_body "}" .struct User {
name: string,
email: string,
age: number,
roles: string[],
metadata: {
createdAt: string,
updatedAt: string
}
}Enum Types
Enums define a type with a fixed set of named variants. Variants can optionally carry associated data.
enum_decl = "enum" identifier "{" enum_body "}" .
enum_body = { enum_variant [ "," ] } .
enum_variant = identifier [ "(" enum_fields ")" ] .
enum_fields = enum_field { "," enum_field } .
enum_field = [ identifier ":" ] identifier .enum Status {
Pending,
Active,
Completed(result: string),
Failed(error: string, code: number)
}Declarations
Variable Declarations
Variables are declared with let and are immutable by default.
let_stmt = "let" identifier "=" expression .
let name = "Alice"
let count = 42
let items = [1, 2, 3]Function Declarations
Functions are pure computations that take parameters and return a value. They cannot access agent state or call tools.
fn_decl = "fn" identifier "(" [ param_list ] ")" [ return_type ] block .
param_list = param { "," param } .
param = identifier ":" type_name .
return_type = "->" type_name .fn add(a: number, b: number) -> number {
return a + b
}
fn greet(name: string) -> string {
return "Hello, {name}!"
}Tool Declarations
Tools are functions that can be called by agents. They define capabilities that extend what an agent can do—accessing APIs, reading files, performing calculations, etc.
tool_decl = "tool" identifier "(" [ param_list ] ")" [ return_type ] block .tool fetchWeather(city: string) -> object {
// Implementation that calls weather API
let response = http_get("https://api.weather.com/{city}")
return response.data
}
tool calculateTax(amount: number, rate: number) -> number {
return amount * rate
}Agent Declarations
Agents are the core abstraction in Gent. An agent declaration defines an AI agent with a system prompt, available tools, optional knowledge base, and a typed output schema.
agent_decl = "agent" identifier "{" agent_body "}" .
agent_body = { agent_item } .
agent_item = tools_field | knowledge_field | output_field | agent_field .
tools_field = "tools" ":" expression .
knowledge_field = "knowledge" ":" expression .
output_field = "output" ":" output_type .
agent_field = identifier ":" expression .agent Researcher {
model: "gpt-4",
temperature: 0.7,
system: """
You are a research assistant. Use the provided tools
to gather information and synthesize findings.
""",
tools: [search, summarize, cite],
knowledge: ["./docs/*.md"],
output: ResearchReport
}Struct Declarations
See Struct Types.
Enum Declarations
See Enum Types.
Interface Declarations
Interfaces define contracts that structs can implement. They specify required fields and methods.
interface_decl = "interface" identifier "{" interface_body "}" .
interface_body = { interface_member } .
interface_member = interface_field | interface_method .
interface_field = identifier ":" type_name .
interface_method = identifier "(" [ param_list ] ")" [ return_type ] .interface Serializable {
toString() -> string
}
struct User implements Serializable {
name: string,
email: string
}Expressions
Operators
Arithmetic Operators
+ addition- subtraction* multiplication/ division% moduloComparison Operators
== equal!= not equal< less than> greater than<= less or equal>= greater or equalLogical Operators
&& logical AND|| logical OR! logical NOTOperator Precedence
Operators are listed from highest to lowest precedence:
( )Grouping! -Unary* / %Multiplicative+ -Additive< > <= >=Comparison== !=Equality&&Logical AND||Logical ORCall Expressions
call_expr = expression "(" [ arg_list ] ")" .
arg_list = expression { "," expression } .add(1, 2)
greet("World")
agent.run("What is 2 + 2?")Member Access
member_expr = expression "." identifier . index_expr = expression "[" expression "]" .
user.name
response.data.items
array[0]
map["key"]Lambda Expressions
Lambdas are anonymous functions, useful for callbacks and higher-order operations like map, filter, and reduce.
lambda = "(" [ lambda_params ] ")" "=>" lambda_body .
lambda_params = identifier { "," identifier } .
lambda_body = block | expression .// Single expression
(x) => x * 2
// Multiple parameters
(a, b) => a + b
// Block body
(x) => {
let doubled = x * 2
return doubled + 1
}
// Usage with array methods
let doubled = numbers.map((n) => n * 2)
let evens = numbers.filter((n) => n % 2 == 0)Match Expressions
Match expressions provide pattern matching on enum values.
match_expr = "match" expression "{" { match_arm } "}" .
match_arm = match_pattern "=>" match_body [ "," ] .
match_pattern = "_" | enum_pattern .
enum_pattern = identifier "." identifier [ "(" pattern_bindings ")" ] .match status {
Status.Pending => "Waiting...",
Status.Active => "In progress",
Status.Completed(result) => "Done: {result}",
Status.Failed(error, code) => "Error {code}: {error}",
_ => "Unknown status"
}Statements
Blocks
block = "{" { block_stmt } "}" .
block_stmt = let_stmt | assignment_stmt | return_stmt
| if_stmt | for_stmt | while_stmt
| try_stmt | break_stmt | continue_stmt
| expr_stmt .If Statements
if_stmt = "if" expression block [ "else" block ] .
if count > 10 {
print("Many items")
} else {
print("Few items")
}For Loops
For loops iterate over arrays and ranges.
for_stmt = "for" identifier "in" expression block . range_expr = number ".." number .
for item in items {
print(item)
}
for i in 0..10 {
print(i)
}While Loops
while_stmt = "while" expression block .
while count < 100 {
count = count + 1
}Try-Catch Statements
Error handling uses try-catch blocks. The catch clause binds the error to an identifier.
try_stmt = "try" block "catch" identifier block .
try {
let result = riskyOperation()
print(result)
} catch error {
print("Error: {error}")
}Return Statements
return_stmt = "return" [ expression ] .
return 42
return { name: "result", value: x }
return // returns nullAgents
Agents are the central abstraction in Gent. They encapsulate an LLM with a system prompt, available tools, optional knowledge, and a typed output schema.
Agent Declaration
An agent declaration creates a new agent type. The agent body contains configuration fields and special fields for tools, knowledge, and output.
agent CodeReviewer {
// Model configuration
model: "gpt-4",
temperature: 0.3,
max_tokens: 2000,
// System prompt - what the LLM sees
system: """
You are an expert code reviewer. Analyze the provided code
for bugs, security issues, and style improvements.
Be thorough but constructive in your feedback.
""",
// Available tools
tools: [analyzeAST, checkStyle, findVulnerabilities],
// Knowledge base for RAG
knowledge: ["./style-guide.md", "./security-patterns.md"],
// Typed output schema
output: ReviewResult
}
struct ReviewResult {
summary: string,
issues: Issue[],
score: number
}
struct Issue {
severity: string,
line: number,
message: string,
suggestion: string
}Tools Field
The tools field specifies which tools are available to the agent. Tools appear in the LLM's function calling interface.
tools: [search, calculate, fetchData]
tools: [] // No tools availableKnowledge Field
The knowledge field enables Retrieval-Augmented Generation (RAG). It accepts an array of file paths or glob patterns. Matched documents are indexed and relevant chunks are injected into the agent's context.
knowledge: ["./docs/api.md"]
knowledge: ["./knowledge/**/*.md", "./examples/*.gnt"]Output Field
The output field specifies the agent's return type. The LLM is constrained to produce valid JSON matching this schema. This provides compile-time type safety for agent outputs.
output: UserProfile // Named struct
output: { // Inline struct
success: boolean,
message: string
}Agent Execution
Agents are executed by calling them as functions with a prompt string. The agent runs to completion and returns a typed result.
let result = CodeReviewer("Review this Python code: {code}")
// Parallel execution
parallel ReviewTeam {
agents: [SecurityReviewer, StyleReviewer, PerfReviewer],
timeout: 30s
}Modules
Import Statements
Import statements bring declarations from other Gent files into scope.
import_stmt = "import" "{" import_list "}" "from" string_literal .
import_list = identifier { "," identifier } .import { UserAgent, fetchUser } from "./agents/user.gnt"
import { validateEmail } from "./utils/validation.gnt"Exports
All top-level declarations (agents, tools, functions, structs, enums) are automatically exported and can be imported by other modules.
Comments
Gent supports single-line comments starting with
//. Comments extend to the end of the line.comment = "//" { character } newline .