Skip to content
LogoLogo

Grammar

Reference for .too source syntax in Toolang 0.4.0, based on tree-sitter-toolang 0.4.0. The upstream syntax and CST reference and generated EBNF contain the complete parser contract. Runtime defaults and validation below are identified separately. See authoring conventions and Run agent scripts for usage.

Changes in 0.4.0

  • Use generate N for repeated independent calls, run for a single call returning an array or consuming an entire array, and reduce for sequential reduction. scatter, storm, gather, and settle are ordinary text.
  • Reducer initializers use initial:, replacing from:.
  • async run, await, spawn, and exec support background calls, handles, independent roots, and control transfer.
  • Lane clauses precede named or inline targets. Named collection targets use using; inline targets omit it. Unit spellings do not depend on the count.
  • Repeat counts and conditions are independently optional. An until condition accepts a name or inline text and may appear anywhere in its repeat body.
  • chore remains a declaration; task is no longer a source declaration. #@ marks program documentation; ##! is item documentation containing !.
  • Same-line content retains every #. Explicit text blocks preserve keywords, comment markers, and assignment-looking lines as literal content.

Program and layout

program ::= (trivia | item)*
item ::= with | struct | psyche | skill | service | prompt | chore
       | context | instruct | agic | flow

Top-level declarations start at column zero. The first substantive entry in a body establishes its baseline; structural siblings share it. A deeper entry requires an enclosing body, and dedents must reach an ancestor baseline. Comments and blank lines do not satisfy a required body. Cap and chore bodies are optional; struct, agic, and flow bodies are required.

Spaces and tabs separate structural tokens. Tabs advance to eight-column stops; do not mix tabs and spaces in structural indentation. LF and CRLF are supported. EOF can finish a final nonempty line, but cannot supply missing content.

Names, types, and signatures

identifier ::= /[a-z][a-z0-9_]*/
type_name ::= /[A-Z][A-Za-z0-9]*/
cap_name ::= /[a-z][a-z0-9_-]*/
integer_literal ::= /[0-9]+/
type ::= ("Text" | "Number" | "Boolean" | "Json" | "Part" | type_name) "[]"*
params ::= "(" (param ("," param)*)? ")"
param ::= (identifier | "_") "?"? (":" type)?

Runnable, agent, local, and handle names use identifier. Chore names use the same spelling as cap names. Keywords are allowed in explicit name positions: let run = Evidence. binds the local run. _ can name a parameter, but cannot be a local destination or await handle. Qualified route references use ([A-Za-z_][A-Za-z0-9_-]*::)*(agic:|flow:)?[A-Za-z_][A-Za-z0-9_-]*; call targets use the narrower identifier form.

[] is a contiguous suffix; spaces before it are allowed. Integers are unsigned decimal digits, including leading zeros. lane/lanes and time/times are interchangeable parser tokens; the formatter chooses their spelling by value.

Runtime signature defaults:

  • Omitting the parameter list implies _ : Part[]; () declares no inputs.
  • An explicit untyped _ defaults to Part[]; an untyped named input defaults to Text. If _ is present, it must be first.
  • An omitted declaration return type defaults to Text. Inline target defaults depend on the operation. A struct defines a user-defined structured type.
struct Finding:
  summary: Text
  sources?: Text[]
 
agic summarize(_: Text, style?: Text) -> Finding:
  Summarize {{_}} in the requested {{style}} style.

Typed boundaries

Named input values must match the runnable signature. Text-source callers (including the CLI) decode Number, Boolean, arrays, and structs from text; the decoded HTTP run endpoint accepts their JSON values directly. Boolean text uses lowercase true or false, and a Boolean is not a Number. Struct fields are checked for unknown keys, missing required fields, and declared types. Output is checked against the declared return type as well; an incompatible model response fails the run.

Part[] carries ordered multimodal content. Text requires text-compatible parts; it does not silently stringify images. Part requires exactly one part. Array operations act on the outer array: generate 3 with a Text[] target returns Text[][], and map preserves that outer item boundary.

Comments and content

MarkerStructural meaning
#Plain comment; also allowed inline on structural lines.
#!Shebang only at byte zero; otherwise a plain comment.
#@Program documentation at program scope and column zero.
##Item documentation. ! after this marker is ordinary text.
## @param name descriptionParameter documentation with a same-line description.

Content can follow its introducing : or = on the same line, or occupy an indented block. Same-line content consumes the whole physical line, including #; it has no inline comments. Multiline content establishes a text baseline, preserves deeper indentation, and ends on dedent. Once explicit text starts, keywords, Markdown fences, comment markers, and assignment-looking lines remain literal. Blank lines alone cannot satisfy required content.

Implicit agic messages and flow runs form paragraphs: adjacent lines and one intervening blank line stay together; two blank lines or a structural comment split them. Each substantive line checks the context's complete first word for syntax. runworker and run_suffix stay prose; run selects a flow operation. Use explicit content when prose starts with a keyword.

flow explain:
  let note = # This hash is content.
  run:
    # This heading is literal.
    generate and await remain literal here.
    Explain {{note}} and {{_}}.

Templates such as {{_}}, {{topic}}, and {{_1._}} remain literal parser text; placeholder extraction and substitution belong to language semantics.

Templates and includes

Content uses a restricted Mustache template language:

FormMeaning
{{_}}Current primary input
{{topic}}, {{finding.summary}}Named value or dotted field lookup
{{items.0}}Array item by zero-based index
{{#items}}...{{.}}...{{/items}}Positive section; iterate an array and access its current item
{{^items}}...{{/items}}Inverted section for an absent or false value

Substituted text is not HTML-escaped. Sections must balance. Partials, template comments, delimiter changes, triple braces, expressions, and callable values are unsupported. Required named inputs must be supplied. An omitted optional input renders as empty text; use sections when surrounding text should also depend on its presence.

A line beginning with @ includes a file, for example @"notes with spaces.md". A line beginning with $ invokes an available prompt; see Prompt files. Markdown fenced code blocks keep include and prompt lines literal. Content inclusion is resolved by the caller and is separate from with, which acquires a cap definition.

History variables

VariableValue and scope
_1, _2, ...Previous completed iteration frames, newest first, within the nearest repeat's windowing capacity
_1._Primary value at the end of the previous iteration; in a reducer, the current accumulator
_1.__, _1._namePrimary and named values at entry to that iteration
_1.nameA named value at exit from that iteration
_farRecalled compacted history as text, or empty text when excluded
_nearRecalled recent messages as a JSON array, or an empty array when excluded
_pastRecalled summary as a user message, followed by recalled recent messages

A repeat starts with no completed frames. Guard an in-window frame with {{#_1}}...{{/_1}} before using it on the first iteration. Directly reading a missing frame fails; referring beyond the window fails even inside a guard. An until condition that needs unavailable in-window frames waits until those frames exist. Nested loops select their own history scope. Reduce keeps one frame and seeds _1._ from initial: or the first item before its first call. _far, _near, and _past follow the agic's recall selection independently of iteration history.

Declarations

with ::= "with" ("psyche" | "skill" | "service" | "prompt") reference line_end
struct ::= "struct" type_name ":" line_end field_body
field ::= identifier "?"? ":" type line_end
cap ::= ("psyche" | "skill" | "service" | "prompt") cap_name ":" line_end cap_body?
chore ::= "chore" cap_name ":" line_end cap_body?
property ::= identifier "=" raw_value line_end
context ::= "context" identifier? ":" content
instruct ::= "instruct" identifier? ":" content

A struct requires at least one field. Caps and chores have an optional property prefix followed by optional literal content. Comments and blank lines may separate properties. The first non-property text line ends the property prefix permanently. Properties and raw with references end before #; consumers validate their values. A prompt has no typed signature; runtime rejects prompt properties. An omitted context or instruct name defaults semantically to default.

with psyche gh:briceyan/concise
 
skill review:
  description = Review supplied changes.
  Review {{_}} for concrete defects.
 
chore review_changes:
  title = Review changes
  Review the latest changes.
 
instruct: Give concise, source-backed answers.
context project: A documentation project.

Agic and shared directives

agic ::= "agic" identifier? params? ("->" type)? ":" line_end agic_body
flow ::= "flow" identifier? params? ("->" type)? ":" line_end flow_body
message ::= ("user" | "assistant" | "tool") ":" content | implicit_paragraph

Agics accept directives, messages, or directives followed by messages. Flows require statements, optionally preceded by directives. pass is a standalone whole-body alternative for either; it cannot coexist with other entries. Bare agic paragraphs are user messages at runtime.

DirectiveOperatorsValue
models, tools, skills, services, psyches, prompts=, +=, -=Nonempty query text.
hands, handoffs=Comma-separated runnable references, none, or *.
recall=Comma-separated far/near, none, default, or *.
lanes=Integer or default.
instruct, context=Identifier, default, or none.

hands permits model-requested run and spawn targets; handoffs permits exec targets. At a root, omission selects all visible targets. A child inherits its parent's routing settings within the same module; crossing modules resets omitted routing settings to that module's visible targets. Explicit * selects all visible targets and none selects none. These are routing permissions for agics, not model or tool resource queries. Use agic:NAME, flow:NAME, or a qualified module ref to disambiguate targets. recall inherits the parent setting, starting with both far and near at a root; none supplies neither, while default and * restore both. lanes inherits concurrency, starting at 4; lanes = default restores 4. An operation's explicit lane clause selects its own concurrency setting.

Directives form a leading prefix; the first message or statement ends it. Unknown assignments in that prefix are errors. Special list values stand alone. Structural inline comments are allowed on directive lines. Runtime validates query expressions, numeric ranges, duplicates, and referenced names.

instruct = name and context = name select top-level declarations; none disables that layer. Omission inherits the parent's selection or defaults at a root. Runnable-local instruct: and context: blocks are invalid.

agic research(_: Text):
  tools = tavily/*
  recall = far, near
  user: Research {{_}} and cite sources.

Flow

The following forms use BODY for same-line or indented content, NAME for an identifier, and T for a type. Brackets indicate optional syntax.

run NAME
run [-> T]: BODY
async run NAME
async run [-> T]: BODY
spawn NAME
spawn [-> T]: BODY
await NAME
exec NAME
exec [-> T]: BODY
seek AGENT NAME
seek AGENT [-> T]: BODY
ask: BODY

let NAME = VALUE_STATEMENT
let VALUE_STATEMENT
let NAME = BODY

generate N [in P lanes] using NAME
generate N [in P lanes] [-> T]: BODY
map [in P lanes] using NAME
map [in P lanes] [-> T]: BODY
reduce using NAME
reduce [-> T]: BODY

keep first N
keep last N
keep [in P lanes] if NAME
keep [in P lanes] if [-> Boolean]: BODY
drop first N
drop last N
drop [in P lanes] if NAME
drop [in P lanes] if [-> Boolean]: BODY
sort ascending|descending [in P lanes] by NAME
sort ascending|descending [in P lanes] by [-> Number]: BODY

run invokes a named or inline runnable; async run returns a handle for a background child. spawn starts an independent root and may retain its handle through let. await waits for one named handle. exec transfers control to a successor. seek and ask express agent and human requests, respectively. Toolang 0.4.0 parses both forms, but the current executor reports a bridge-required error because the corresponding execution bridges are absent.

At runtime, ordinary value statements update _; named let updates only its local, and nameless let discards the result. Bare async launches and spawns preserve _. A text binding evaluates Content into Part[]. exec and repeat are not value statements and cannot be bound. The parser recognizes a broader operation set after let; runtime rejects bound repeats.

generate N returns N complete child results in an outer array. map transforms each outer item. reduce combines items sequentially. To produce an array in one model call or summarize an entire array, use run with the appropriate input/output signature. Filtering requires Boolean results; sorting requires Number scores. Lane clauses precede targets, with using required only for named generate/map/reduce targets. Reduce has no lane clause.

Reduction initializers

agic merge(_: Text) -> Text:
  Incorporate {{_}} into the report in {{_1._}}.
 
flow combine(_: Text[]) -> Text:
  reduce using merge:
    initial: A report with no findings yet.
 
flow combine_inline(_: Text[]) -> Text:
  reduce -> Text:
    Incorporate {{_}} into the report in {{_1._}}.
    initial:
      A report with no findings yet.

A named reducer's header colon requires an indented initial:. An inline multiline reducer permits an initializer at its text baseline after nonempty reducer text; a deeper initial: stays literal. Same-line reducer text cannot have a following initializer. Without one, runtime seeds from the first item.

Repeat

agic inspect:
  Inspect {{_}} and identify useful improvements.
 
agic ready -> Boolean:
  Is {{_}} ready to publish?
 
agic revise:
  Improve {{_}} using the available evidence.
 
flow improve:
  repeat 5 times windowing 3:
    run inspect
    until ready
    run: Improve {{_}} using the available evidence.
  repeat:
    until: Is {{_}} ready to publish?
    run revise

A repeat requires at least one statement and permits at most one until at its body baseline. Count and window are optional; count precedes window. A condition may appear before, between, or after statements. It takes a bare name or : followed by content, with no return annotation or argument list. Nested repeats own their conditions; until is invalid outside a repeat.

Runtime checks the condition at its authored position. True exits the owning repeat; false continues with the remaining statements. Without a count or condition, repeat continues until control transfer, cancellation, or failure. windowing N sets positive history capacity, which defaults to 3 prior frames.

CST

The root is program. Runnable bodies expose repeated directive, message, or stmt fields. Statements use names such as run_stmt, generate_stmt, reduce_stmt, and let_stmt; a bound operation is let_stmt.stmt. Targets are runnable_name or inline_agic nodes. Authored text is exposed through content containers with text leaves; a reducer's initial field points directly to initializer content. See the upstream CST contract for all public fields and recovery nodes.

Validate and format

Use offline language commands to inspect .too files without making model calls:

too parse --check script.too
too fmt --check script.too
too highlight script.too

parse --check validates syntax and authored-language constraints; runtime resource availability and execution are separate checks. See the CLI reference for command options.