Skip to main content
lmnr-cli signal creates, inspects, updates, and deletes Signals from your terminal. Keep a Signal’s prompt and schema in your repo, ship changes from CI, or hand the surface to a coding agent that can shell out.
signal ships in the standalone lmnr-cli npm package. You do not need the @lmnr-ai/lmnr SDK installed to use it.

Install and authenticate

The CLI authenticates as you, the signed-in user, and resolves which project to target from the directory you run in. Run setup once per project:
That logs you in and writes .lmnr/project.json, so every signal command in that directory (or any subdirectory) targets that project. Override per command with --project-id <uuid>. See Authenticate and Directory-scoped projects. The rest of this page assumes a global install. With npx, prefix each command with npx lmnr-cli@latest.

Create a Signal

A Signal is a prompt, a schema, a trigger, and filters. At minimum signal create needs a name, --prompt, and --schema:
llm profile: env means the Signal runs on the deployment’s own model credentials, which is how every Signal on Laminar Cloud runs. On a self-hosted deployment you pick a profile instead: see Run a Signal on an LLM profile. The trigger defaults to root-span-finished, the filter to total_token_count > 1000, and the mode to realtime, so the Signal is already live on new traces. See Triggers and Filters for how they work. --schema takes a JSON Schema object:
  • Field names must be identifiers: ^[a-zA-Z_][a-zA-Z0-9_]*$.
  • Field types are string, number, or boolean. For a fixed set of values, use "type": "string" with an enum array.
  • Every field is required. type and required are filled in for you if you omit them.
To override the trigger, filters, or mode from the CLI:
--filter takes JSON {"column":"...","operator":"...","value":"..."} and is repeatable. Columns: total_token_count, status, span_names. Pass it on create to replace the default.
--span-name is the trigger flag. span_names is a filter column: it matches a name anywhere in the trace.
Two more flags shape a new Signal:
  • --sample-rate <1-95> evaluates only that percentage of matching traces. Omit it for no sampling.
  • --disabled creates the Signal paused. Turn it on later with signal update --no-disabled.
Creating a Signal also creates two alerts: a Critical-severity event alert and, when clustering is enabled, a New cluster alert. Both notify you in-app and by email. Route them to Slack, change their severity, or add output-schema filters from the Signal’s Settings > Alerts section. See Alerts.

List and inspect Signals

Columns are truncated to fit your terminal width. Pass a name to filter the list by case-insensitive substring, and signal get to see one Signal in full:
Every command that takes a <signal> accepts either an id or a name, so you rarely need to look up a uuid. An ambiguous name is an error listing the candidates rather than a silent pick, since update and delete change things:
signal get renders the trigger and filters in the same syntax the flags accept, so its output is copy-pasteable into signal update.

Machine-readable output

Every subcommand takes --json, which prints structured JSON to stdout while human-facing messages go to stderr. That keeps pipes clean for scripts and coding agents:
version is the current version of the judge definition (the prompt and schema). The full history is signal versions, below. llmProfileId, llmProfileName, and model are null when the Signal runs on the deployment’s own credentials.

Version history

Editing a Signal appends a new version of its definition: the name, prompt, schema, trigger, filters, mode, sampling, status, and LLM route as they were at that moment. An edit that changes nothing appends nothing. signal versions prints that history, oldest first, so you can see what the judge was asked at the time an old event was extracted:
Like get, it takes an id or a name. The human output shows the prompt and the payload fields of each version; with --json each entry is {"version","createdAt","definition"} and definition carries the whole snapshot. The version field on signal get is only the current pointer; this command is the log.

Update a Signal

signal update is a partial patch: any flag you omit keeps its stored value. Changing the prompt cannot clear your sampling, reactivate a paused Signal, or alter when it fires.
Switching a Signal to batch processing leaves its trigger and filters untouched:
Everything you can set on create, you can change:
A paused Signal stops evaluating new traces and rejects backfills, but keeps its existing events and clusters. See Pause and resume a Signal. An update with no flags is an error rather than a silent no-op:

Run a Signal on an LLM profile

Pointing a Signal at an LLM profile is available on self-hosted deployments. On Laminar Cloud, Signals run on Laminar’s own model credentials and the flags below are rejected.
On a self-hosted deployment, each Signal runs on one LLM profile and one of that profile’s models. --llm-profile-id and --model set the pair, and they are required together on signal create:
signal update takes the same pair to move a Signal onto a different profile or model:
Both flags pass straight through, so the server’s own rules apply and its messages are what you see:
  • Passing only one of the two is rejected. So is passing either one on Laminar Cloud.
  • The model has to be one the profile declares. Discover both with lmnr-cli llm-profile list.
  • There is no flag for moving a Signal back to the deployment’s environment credentials. Signals created before you added profiles keep running on them until you pin a profile.
  • Deleting a profile, or removing a model a Signal is pinned to, is refused while that Signal exists.
signal get shows the pair, with the profile name for readability:
See LLM profiles for how to create one and what each provider needs.

Delete a Signal

Deletion is permanent and cascades: the Signal’s triggers, its alerts, and every signal event it ever produced are removed. To stop a Signal without losing its history, pause it with signal update --disabled instead.

Reference

Shared by every signal subcommand:

signal create

signal update

signal list, get, versions, delete

Every command has examples in its own help text:

What’s next

Signals

How a Signal reads a whole trace and turns it into structured events.

Quickstart

Write your first Signal in the UI and run it over historical traces.

Alerts

Fire Slack or email notifications on the events your Signal produces.

CLI

The rest of lmnr-cli: setup, SQL queries, datasets, and debug sessions.