Creating a Track (SDK)
Introduction / Concepts

Lightrail: Core Concepts


Lightrail's functionality is almost entirely built around the concept of Tracks. A Track can be thought of as a provider of workflows and context, as a narrowly defined LLM agent, or as an application that leverages Lightrail's UX to provide end-users with functionality. Basically, if you'd like Lightrail to do something that it doesn't currently do, you can probably achieve this goal by writing a Track. Lightrail comes pre-installed with several Tracks, including a VS Code track (for integrating with VS Code), a Shell track (for writing and executing shell scripts), a Files track (for accessing the local filesystem), and a SQL track (for interacting with SQL databases).

New tracks are written in TypeScript (or JavaScript) and distributed as zip files which can be installed from URLs. A Track definition exports a single object that conforms to the type definitions defined in the SDK (See ). Lightrail also maintains a simple Track Repository (opens in a new tab), and new tracks can be added to it via PR (see Publishing for more info).

Tokens & Actions

A Lightrail Track exposes functionality to the end user in two ways: via a Token or via an Action.

In an LLM context, a Token refers generally to each individual unit of meaning in the user's prompt (e.g. a word or meaningful part of a word). By default, tokens entered into the Lightrail interface are treated as plain text. However, tracks can provide custom types of tokens that users can use to enrich their prompts. Often, custom tokens result in additional context being pulled into a prompt, or in some way refer to things on the user's computer that the user would like to reference. Examples can include URLs, documents in an open application, or file paths.

an Action, meanwhile, is a specific workflow/command that the user can execute. Actions are defined with handlers that receive the prompt entered by the user, as well as any other optional arguments they might require. The handler should first hydrate the prompt, which handles all the custom tokens in the prompt and adds all the required context to the user's text input, then use the hydrated prompt to carry out whatever steps the action requires (and render whatever UX is necessary).

See the first-party tracks (opens in a new tab) for examples that demonstrate defining both Tokens and Actions.

The Main & Renderer Processes

Lightrail tracks run in an Electron environment, and their functionality is split between two processes: Main & Renderer. For more information on this distiction, see this Electron article (opens in a new tab). Essentially, code that runs in the Renderer process can control the user-facing UX (i.e. showing notifications, adding messages to the chat log, exposing controls), and code that runs in the Main process can interact with the machine / filesystem (use Node APIs, interact with Clients (see below), etc). You can also think of the Main process as the "server side" process, while the Renderer process is "client side" and should only rely on functionality available in a browser. Communication between the two processes occurs via Handlers.

Handlers & Message Passing

Tracks communicate between these two processes via Handlers that they define. Handlers can be defined in either the Main or Renderer process, and have access to only the functionality of their respective process. From within a Handler, you can send a message to any other handler, and receive a response (asynchronously). Handlers can be given arbitrary names and arguments. Each Action also includes its own handler, which runs in the Main process when that Action is used.

Process Handles

When a handler is run, it receives as an argument a ProcessHandle (either a LightrailMainProcessHandle or a LightrailRendererProcessHandle, depending on the Process it's running in). This handle is the primary way in which tracks interface with Lightrail's functionality and UX. The methods available in these handlers are defined in the Track Definition APIs section of the documentation.


In addition to communicating internally via Handlers, Lightrail tracks can also communicate with external programs called Clients. Clients are also defined with the Lightrail SDK, and typically take the form of extensions for other platforms/software (though they can also be standalone applications if needed). They communicate with tracks via a websocket connection. Examples of clients include the lightrail-bridge VSCode extension (opens in a new tab), the chrome extension (opens in a new tab), or the JupyterLab extension (opens in a new tab). All three are defined in their respective platforms' extension format, but they use the Client API provided by the Lightrail SDK. Further information about Client development is found in the Client section of the documentation.

Once you're basically familiar with these concepts, you're ready to define a new track. If you run into any issues or have any questions, you can always reach out in our Discord (opens in a new tab) -- we tend to respond very quickly to questions.

Happy coding!