Skip to main content
Lion is designed to sit on top of ordinary JavaScript. Any value you place in the evaluation environment — a plain object, a class constructor, a function, or a live instance — becomes a first-class citizen inside a Lion program. The object and func standard library modules expose the full surface of host JavaScript through simple, composable JSON expressions.

Accessing object properties

Use object/get to read a single named property from a host object, and object/get-path to traverse a nested structure with a dot-separated path. Numeric segments in a path index into arrays.
When a host object is available in the environment under a string key, pass the key instead of the literal object:
With { user: { name: "Ada", stats: { score: 92 } } } in the environment, this returns 92. The path "stats.score" resolves two levels deep. A path segment like "users.1.name" would index the second element of an array named users.

Calling object methods

object/call-method invokes a method by name on a host object, forwarding any additional arguments:
For methods nested deeper in an object tree, use object/call-method-path with a dot path:
Both forms bind this correctly — the method is called on the object at the path before the final key, so prototype methods work as expected. object/get-method and object/get-method-path retrieve the bound method without calling it immediately, which is handy when you want to store a method reference for later use:

Constructing classes

object/new calls a constructor with new, forwarding all arguments:
SomeClass must be present in the environment as a function. The result is a fully constructed instance that can then be used with object/call-method or stored with define.

Binding Lion lambdas as JavaScript callbacks

func/callback wraps a Lion lambda so it can be handed to any JavaScript API that expects a plain function — promise handlers, event listeners, array iterators, and so on. The wrapper captures the current Lion environment so the lambda continues to have access to all bindings:
When the callback is invoked by the host, it runs the lambda synchronously and returns the result, or returns a Promise if the lambda body yields an effectful value.

Partial application

func/partial pre-fills the leading arguments of any callable — host functions and Lion lambdas alike:
The returned function accepts the remaining arguments when called. This is particularly useful inside match structural predicates, where you need a single-argument predicate but only have a two-argument equality function:
func/partial works on any value stored in the environment under a string key, including stdlib entries such as "string/equals?" or "number/greaterThan".

Real-world example: the agent package

The packages/agent package is the most complete demonstration of host interop. It injects into the Lion environment:
  • OpenTUI UI classes and layout enums
  • AI SDK streaming helpers
  • A model instance
  • Node fs
  • Zod schema constructors
  • A live renderer instance
The agent program in agent.json then orchestrates the entire terminal UI using only Lion expressions — constructing components with object/new, traversing nested APIs with object/get-path, calling methods with object/call-method, and attaching event handlers with func/callback.

Walkthrough: injecting a class, constructing it, and calling its methods

The following steps show the full lifecycle from TypeScript to Lion.
1

Inject the class into the environment

Add the constructor as an environment entry alongside stdlib. Any string key works; choose a name your Lion code will reference.
2

Construct an instance with object/new

Inside a Lion begin block, use object/new to create an instance and define to bind it:
This evaluates to 5.
3

Run the program from TypeScript

Pass the program and environment to run, then execute with Effect:
4

Pass a Lion callback to a host method

If Counter had an onChange method that accepted a listener, you could attach a Lion lambda using func/callback:
The lambda runs inside the Lion environment each time the host calls the listener.