Skip to content

Concepts

Hellig has four moving parts. Each is a tiny dataclass or Protocol that you can replace independently.

Compiler

A Compiler turns natural-language source into a Program — an ordered list of Instructions.

class Compiler(Protocol):
    def compile(self, source: str, context: dict | None = None) -> Program: ...

Hellig ships with StubCompiler, a deterministic line-based parser used by default so the framework runs without any external LLM. In production you’ll typically plug in an LLM-backed compiler — see Extending Hellig.

Program & Instructions

A Program is a sequence of Instructions drawn from a tiny ISA:

Op Meaning
say print a message to the user (supports {var} substitution)
ask ask the user a question, bind the reply to a variable
call call a registered agent with a prompt
tool invoke a registered tool function with kwargs
set bind a literal value into scope
done halt execution

Every instruction can read from and write to the runtime's scope — the flat dictionary of variables threaded through a session. Full details in the instruction set reference.

Runtime

The Runtime is the interpreter. It owns:

  • agents: name → Agent lookup for the call op
  • tools: name → callable for the tool op
  • io: how to say and ask (defaults to ClickIO — your terminal)
  • scope: variables produced and consumed by instructions

The runtime can pause mid-program to call back to the user via io.ask. That is what makes Hellig feel conversational rather than batch.

Session

A Session is the multi-turn glue. It pairs a compiler with a runtime and keeps a history of turns. Scope persists across turns, so a later turn can reference variables bound by an earlier one.

from hellig import Session

s = Session()       # default StubCompiler + Runtime + ClickIO
s.turn("? city -> city")          # turn 1: asks the user
s.turn(": You picked {city}")     # turn 2: uses scope from turn 1

Agent

Agents are the workers call instructions dispatch to. The base class is intentionally tiny:

@dataclass
class Agent:
    name: str
    instructions: str = ""
    runtime: Callable[[str, ...], str] = _echo

runtime is any callable that takes a prompt and returns a string — wrap any LLM client you like. The default echoes the prompt back, which is enough for demos and tests.

IO adapter

IO decouples the runtime from where input/output goes:

  • ClickIO — terminal, the default
  • ScriptedIO — deterministic queue of answers for tests, with a transcript

Implement say(text) and ask(prompt) -> str to write your own (web UI, chat platform, voice, etc.).