Skip to content

Block Format

llmist uses a simple block format that works with any text model. This format uses marker prefixes to delimit gadget calls and their parameters—no native tool calling or structured outputs required.

A gadget call consists of a start marker, parameters, and an end marker:

!!!GADGET_START:GadgetName
!!!ARG:parameter_name
parameter_value
!!!ARG:another_param
another_value
!!!GADGET_END
MarkerPurpose
!!!GADGET_START:NameBegins a gadget call with the gadget name
!!!ARG:pointerDeclares a parameter (value on following line(s))
!!!GADGET_ENDEnds the gadget call

Parameters use !!!ARG: followed by a JSON Pointer path (without leading /) to specify where to place the value.

!!!ARG:filename
calculator.ts
!!!ARG:language
typescript

Result: { filename: "calculator.ts", language: "typescript" }

Use / to create nested structures:

!!!ARG:config/timeout
30
!!!ARG:config/retries
3

Result: { config: { timeout: 30, retries: 3 } }

Use numeric indices (0-based):

!!!ARG:items/0
first
!!!ARG:items/1
second
!!!ARG:items/2
third

Result: { items: ["first", "second", "third"] }

Combine array indices with nested paths:

!!!ARG:users/0/name
Alice
!!!ARG:users/0/age
25
!!!ARG:users/1/name
Bob
!!!ARG:users/1/age
30

Result: { users: [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }] }

Single-line values are automatically coerced to appropriate types:

ValueCoerced TypeResult
truebooleantrue
falsebooleanfalse
42number42
3.14number3.14
-17number-17
hellostring"hello"
(multiline)stringpreserved as-is

Multiline content is preserved exactly as written:

!!!ARG:code
function hello() {
console.log("Hello, World!");
return { key: "value" };
}
!!!ARG:filename
example.ts
  • Internal newlines are preserved
  • A single trailing newline is stripped
  • Great for code, documentation, or any multi-line content

Gadgets can specify dependencies on other gadgets using invocation IDs. This enables DAG (Directed Acyclic Graph) execution: independent gadgets run in parallel, dependent gadgets wait.

!!!GADGET_START:GadgetName:invocation_id:dep1,dep2
ComponentRequiredDescription
GadgetNameYesName of the gadget to call
invocation_idOptionalUnique ID for this call (auto-generated if omitted)
dep1,dep2OptionalComma-separated IDs this gadget depends on
!!!GADGET_START:FetchData:fetch_users
!!!ARG:url
/api/users
!!!GADGET_END
!!!GADGET_START:FetchData:fetch_orders
!!!ARG:url
/api/orders
!!!GADGET_END
!!!GADGET_START:MergeData:merge_all:fetch_users,fetch_orders
!!!ARG:format
json
!!!GADGET_END

In this example:

  1. fetch_users and fetch_orders execute in parallel (no dependencies)
  2. merge_all waits for both to complete before executing
  3. If fetch_users fails, merge_all is automatically skipped

You can customize the marker prefixes if needed:

await LLMist.createAgent()
.withGadgetStartPrefix('<<<START:')
.withGadgetEndPrefix('<<<END:')
.withGadgetArgPrefix('@param:')
.ask('...');

This would expect:

<<<START:FloppyDisk
@param:filename
DOOM.ZIP
@param:megabytes
50
<<<END:

The end marker (!!!GADGET_END) is optional. A gadget block terminates when:

  1. An explicit !!!GADGET_END is encountered
  2. A new !!!GADGET_START: begins (implicit termination)
  3. The stream ends (finalization)

This allows streaming parsers to handle incomplete or truncated responses gracefully.

The parser reports errors for:

  • Duplicate pointers: Same path specified twice in one gadget
  • Array index gaps: Non-sequential array indices (e.g., items/0 then items/5)
  • Invalid array indices: Negative or non-numeric indices

Parse errors are captured in the parseError field while parametersRaw preserves the original text for debugging.

For implementers, here’s the formal grammar:

(* Top-level structure *)
gadget_block = start_marker , header_line , newline , parameters , [ end_marker ] ;
(* Markers - these are configurable *)
start_marker = START_PREFIX ; (* default: "!!!GADGET_START:" *)
end_marker = END_PREFIX ; (* default: "!!!GADGET_END" *)
arg_prefix = ARG_PREFIX ; (* default: "!!!ARG:" *)
(* Header line: gadget name with optional ID and dependencies *)
header_line = gadget_name , [ ":" , invocation_id , [ ":" , dependencies ] ] ;
gadget_name = identifier ;
invocation_id = identifier ;
dependencies = identifier , { "," , identifier } ;
(* Parameters section: zero or more argument definitions *)
parameters = { parameter } ;
parameter = arg_prefix , pointer , newline , value ;
(* JSON Pointer path (without leading /) for nested structures *)
pointer = segment , { "/" , segment } ;
segment = identifier | array_index ;
array_index = digit , { digit } ;
(* Value: all text until next arg_prefix or end_marker *)
value = { any_character } ;
(* Basic tokens *)
identifier = letter_or_underscore , { letter_or_underscore | digit } ;
letter_or_underscore = letter | "_" ;
letter = "A" | "B" | ... | "Z" | "a" | "b" | ... | "z" ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
newline = LF ;
any_character = (* any Unicode character *) ;