Redeo Docs
DocsLukiScript / Overview

Specification

Overview

LukiScript is a declarative DSL for describing how an LLM searches, not just what it answers.

Overview

LukiScript is a declarative DSL for describing how an LLM searches, not just what it answers.

What is LukiScript

LukiScript is a declarative DSL for describing how an LLM searches, not just what it answers. It is named after Wittgenstein's childhood nickname.

Search strategies — Tree of Thoughts, debate, recursive refinement, or custom patterns — are expressed in YAML configs. Every stilt config is validated, versioned, and shareable. Deployed stilts expose themselves as OpenAI-compatible API endpoints, so anything that talks to OpenAI can talk to a stilt by swapping the base URL.

Mental Model

A stilt is a search strategy written in LukiScript. It is defined in YAML, saved under an account, and called via API. The caller receives a response in standard OpenAI-compatible format — the internal execution is not exposed.

Stilts are created in Foundry — either through the visual step editor or by pasting YAML directly. The stilt is saved under the author's account. Visibility can be set to private, unlisted, or public.

When a stilt runs, Studio and Foundry render a live timeline — each step appears as a node as it executes. Intermediate outputs are inspectable.

The components of a stilt:

Steps are the building blocks. Each step makes one or more LLM calls. Steps run in order, and a step can read outputs from any previous step. Three types are available: normal (parallel nodes), sequential (nodes run one after another), and group (multiple sibling steps running side by side).

Fields define what goes into each step's prompt. Each field has a name and a source. When the stilt runs, every field resolves to a concrete value and gets rendered like this:

text
Query: What is the meaning of life?
Evidence 1: First source output here
Evidence 2: Second source output here
Node Number: 3
Branch Count: 5

[System Instruction]
You are an evaluator. Score each answer on a scale of 1-10.

Fields pull from user input (text), from another step's output (ingest), from multiple outputs at once (multi_ingest), or inject runtime values like the current node number (nodeInfo) or a knob value (knobInfo).

Knobs are caller-tunable controls. They appear as sliders or number inputs when someone runs the stilt — branch count, iteration depth, coverage breadth, etc. The config defines the range and defaults; the caller adjusts at call time.

Nodes control fanout. A step with 5 nodes makes 5 parallel LLM calls — each one gets its own node number (1, 2, 3, 4, 5) and produces its own output. The node count can be hardcoded, driven by a knob, or derived from a previous step's output.

Loops repeat the entire steps sequence N times. Each loop can read outputs from previous loops. Loop 2 can read what loop 1 produced, loop 3 can read loops 1 and 2, and so on.

Gates prune branches. A step with continueIf checks each node's output against an expected value. Nodes that don't match are pruned — downstream steps won't see them.

Recursion lets a step spawn a child stilt. The step's output becomes the child's input, the child runs its own full execution, and the result bubbles back up. The child can itself recurse, up to maxDepth.

Groups run sibling steps in parallel. A group contains two or more steps that execute simultaneously — for independent analysis tasks that feed into a shared downstream step.

Timeline controls what's visible. Steps marked with timeline: "circle" appear as dots in Studio's timeline. Steps without a timeline marker still execute but are invisible in the UI.

Core Concepts at a Glance

ConceptWhat it controlsSummary
StepsExecution unitsEach step = one or more LLM calls
FieldsData flowHow steps read from inputs and each other
KnobsRuntime controlsCaller-adjustable parameters (slider or numerical)
NodesFanoutHow many parallel LLM calls a step makes
LoopsIterationRepeat all steps N times, carry context forward
GatesPruningFilter branches by output match (continueIf)
RecursionDepthSpawn child stilts from a step's output, up to maxDepth
GroupsParallelismRun sibling steps simultaneously
TimelineObservabilityMark steps as visible dots in Studio

Not every stilt uses all of these. A minimal stilt is one step with one field and no knobs. More complex stilts combine groups, multi-node fanout, gates, loops, and recursion to implement multi-round search strategies.

The Runtime Lifecycle

When a stilt is called via the API:

The config is parsed and validated — every field reference must point to a real step, every knob reference must resolve, and the exit step must exist.

Knobs are resolved from the caller's values, falling back to defaults. Slider positions map to their numeric values. Numerical knobs are clamped to their min/max range.

Steps execute in order. For each step, the node count is resolved, every field is resolved to a concrete string, the prompt is assembled, and the LLM call(s) are made. Outputs are stored keyed by loop index, step id, and node number.

If a step has a continueIf gate, outputs are filtered — non-matching nodes are pruned. If a step has recursion, a child stilt runs and its result replaces the step's output.

After all steps complete, the loop index advances. Steps in the next loop can reference outputs from previous loops. This repeats until maxLoops is reached.

The output of the exit step from the last loop is returned as the stilt's response, in standard OpenAI-compatible format.

Minimal Example

The smallest valid stilt — one step, one field, no knobs:

yaml
id: hello
name: Hello Stilt
author: Redeo Labs
version: 1
allowedTargets:
  strategy: universal
exit: step0
knobs: {}
steps:
  - id: step0
    name: Answer
    type: normal
    fields:
      - name: Context
        type: text
        from: input.context
    systemPrompt: "Answer clearly and directly."

Execution:

  1. One step (step0) with no nodes, so exactly one LLM call.
  2. The single field (Context) reads input.context from the caller's message and renders as Context: <the user's text>.
  3. The system prompt is appended as [System Instruction].
  4. The assembled prompt goes to the LLM, the response is stored as step0's output.
  5. Since exit: step0, that output is the stilt's final answer.

From Config to Running Stilt

The full journey from writing a stilt to getting a response:

Write. Create a stilt in Foundry's visual editor — add steps, define fields, set system prompts, configure knobs — or paste raw YAML directly. Foundry validates the config during editing.

Save. Save the stilt. Set visibility: private (only the author), unlisted (anyone with the link), or public (visible in the library).

Call. Hit the stilt's endpoint using the standard OpenAI chat completions format. The stilt is addressed by the author's username and the stilt's slug name in the URL path:

bash
curl https://api.redeo.ai/v1/redeo-labs/hello/chat/completions \
  -H "Authorization: Bearer $REDEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Explain quantum entanglement"}]
  }'

The URL path /v1/{author}/{stilt}/chat/completions identifies which stilt to run. The last user message becomes input.context inside the stilt. The model field must be allowed by the stilt's allowedTargets policy.

Respond. The exit step's output from the final loop is returned in standard OpenAI-compatible format.