> ## Documentation Index
> Fetch the complete documentation index at: https://laminarai-docs-lam-1786-dataset-cli-lmnr-cli.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

This quickstart walks through the full Signals loop: *generate traces, write a Signal that reads them, run it, and look at the events*.

<Note>
  Every new Laminar project ships with a **Failure Detector** signal pre-created and triggered automatically on traces with more than 1000 tokens. It categorizes issues as `tool_error`, `api_error`, `logic_error`, `looping`, `wrong_tool`, `timeout`, or `other`. You don't need to build this one yourself. Open it from the Signals list to see events as soon as your traces start arriving.
</Note>

## Prerequisites

* A Laminar project and `LMNR_PROJECT_API_KEY`.
* An agent or LLM app whose traces land in Laminar. The example below uses the [Claude Agent SDK](/tracing/integrations/claude-agent-sdk) to produce traces quickly.

## 1. Generate traces

Any traced application will do. The Claude Agent SDK example below sends a handful of prompts and emits one trace per prompt. Enough to exercise a Signal end-to-end.

```python theme={null}
import asyncio
import os

from claude_agent_sdk import ClaudeSDKClient
from lmnr import Laminar, observe

Laminar.initialize(project_api_key=os.environ["LMNR_PROJECT_API_KEY"])

PROMPTS = [
    "Give me a one-line Python function to reverse a string.",
    "Explain backpressure in distributed systems in one sentence.",
    "What is the CAP theorem? Answer in one sentence.",
    "Write a single bash command to find all .py files modified in the last day.",
    "Why does TCP use three-way handshake? One sentence.",
    "Give me a one-line idiomatic replacement for `for item in arr: print(item)` in Python.",
    "Explain memoization in one sentence.",
    "What is a REST API? One sentence.",
    "What is an LLM hallucination? One sentence.",
    "One-line SQL to find top 5 users by order count.",
]


@observe(name="quickstart_agent")
async def ask(prompt: str) -> None:
    async with ClaudeSDKClient() as client:
        await client.query(prompt)
        async for _ in client.receive_response():
            pass


async def main() -> None:
    for p in PROMPTS:
        await ask(p)


if __name__ == "__main__":
    asyncio.run(main())
```

Run it, then refresh the Laminar traces page to confirm the `quickstart_agent` traces arrive.

## 2. Open Signals

Click **Signals** in the project sidebar. If this is a new project, the **Failure Detector** signal is already there, ready to run on any trace over 1000 tokens.

<Frame caption="Signals list: one card per Signal with recent events and a sparkline">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/PHlKinpyv0TwTGW0/images/signals/signals-list.png?fit=max&auto=format&n=PHlKinpyv0TwTGW0&q=85&s=a78f2b2ece249b3334ef7a660e25819e" alt="Signals list view with cards for each Signal and recent event counts" width="1512" height="982" data-path="images/signals/signals-list.png" />
</Frame>

To write your own, click **Create signal**.

<Frame caption="Empty Create Signal dialog">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/PHlKinpyv0TwTGW0/images/signals/create-signal-empty.png?fit=max&auto=format&n=PHlKinpyv0TwTGW0&q=85&s=0dbd6c52dd5a4ccb18ba660f2169aa4c" alt="Empty signal creation form" width="1512" height="982" data-path="images/signals/create-signal-empty.png" />
</Frame>

## 3. Write the Signal

Fill in the form:

1. **Name**: a stable identifier. Use snake\_case or dot-notation (`agent_response_quality`, `checkout.completed`). The name is what you filter, alert, and query by.
2. **Template** (optional): pick a starting point. Laminar ships templates for task completion, user friction, safety, hallucination, and intent. Templates prefill the prompt and schema; edit both before saving.
3. **Prompt**: describe what the Signal should detect or extract from the trace. *Be concrete.* "The agent answered the user's question correctly and completely" is a better prompt than "good response".
4. **Structured output**: define the JSON schema for the payload. Keep fields small and stable; they become filterable columns on `signal_events`.
5. **Triggers**: toggle on to run this Signal automatically on new traces. Add filters to narrow which traces it runs against.
6. **Sampling** (optional): cap how many matching traces the trigger consumes per time window. Useful when a high-volume filter would otherwise fan out across every trace.

<Frame caption="Create Signal dialog filled in with a Task-template Signal">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/PHlKinpyv0TwTGW0/images/signals/create-signal-filled.png?fit=max&auto=format&n=PHlKinpyv0TwTGW0&q=85&s=7f9b476a069e00d7429ec447713ea1b6" alt="Create signal form populated with name, prompt, schema fields, and a realtime trigger" width="1512" height="982" data-path="images/signals/create-signal-filled.png" />
</Frame>

Click **Create**. The Signal is live from this point on: any configured Trigger starts processing new traces immediately.

<Note>
  Creating a Signal automatically creates a **Critical**-severity event alert that posts to the in-app notification center. Open the Signal's **Settings > Alerts** section (or **Project Settings > Alerts**) to route it to Slack or email, change the severity, or add output-schema filters. See [Alerts](/signals/alerts).
</Note>

## 4. Run the Signal: Triggers and Backfill

A Signal can run in two modes, independent of each other. Open a Signal and click **Settings** to manage both from a sidebar with four sections: **General** (definition and triggers), **Alerts**, **Backfill**, and **Activity**.

<Frame caption="Signal Settings > General: name, prompt, output schema, triggers, and sampling">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/signal-settings.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=a360936860c1942888ccc9bd12bba373" alt="Signal settings General section with the four-section sidebar and the signal definition form" width="1512" height="982" data-path="images/signals/signal-settings.png" />
</Frame>

### Triggers (live)

Triggers run the Signal automatically on new traces that match your filter set. **This is what feeds live dashboards and Alerts.**

* Open the Signal's **Settings > General** section and turn on **Triggers** (or configure Triggers while creating the Signal).
* Add one or more filters. All filters are AND-combined.
* Save. Every matching trace now produces a Run; runs that detect the Signal produce events.

### Backfill (historical)

Use **Backfill** to run a Signal across historical traces, for example to evaluate a freshly-created Signal over the last 24 hours of traffic.

<Frame caption="Start a backfill: pick traces or filters, then enqueue">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/create-job.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=bab974a2cf45b5507a23a80b8aa916c3" alt="Backfill page with trace selection, filters, and trace table" width="1512" height="982" data-path="images/signals/create-job.png" />
</Frame>

1. Open the Signal's **Settings > Backfill** section.
2. Pick a **time range** (defaults to the last 24 hours).
3. Optionally narrow with **filters** or **search**.
4. Choose **specific traces** or **all traces matching your filters**.
5. Click **Start backfill**. Laminar enqueues one Run per trace.

Runs appear in the **Activity** section with a status (Pending, Completed, Failed). Each Run that detects the Signal links to the resulting event in the **Events** tab.

<Frame caption="Activity section: one row per Run with its source, status, and the event it produced">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/signal-activity.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=ffd737b0fd1e169a990670960f6d03f7" alt="Signal activity table listing runs with run id, trace id, event id, source, and status" width="1512" height="982" data-path="images/signals/signal-activity.png" />
</Frame>

### Pause and resume a Signal

A Signal you're not ready to delete can be paused. Open the Signal's **Settings > General** section and flip the **Active** switch off.

<Frame caption="The Active switch at the top of Settings > General pauses and resumes the Signal">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/signal-active-switch.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=0ab6bf4599590b2872b1d1d9e8f6dd58" alt="Signal settings General section with the Active switch at the top of the form" width="1512" height="982" data-path="images/signals/signal-active-switch.png" />
</Frame>

While a Signal is paused:

* New traces are not evaluated, even if they match the Signal's triggers.
* Backfills are rejected until the Signal is re-enabled.
* Existing events and clusters are kept, and stay queryable in SQL and the UI.
* Alerts on the Signal stay configured but have nothing to fire on.

Paused Signals show a **Disabled** badge on the Signals list and are grouped separately from active ones. Flip the switch back on and the Signal resumes evaluating new traces immediately.

<Frame caption="The Signals list groups paused Signals under a Disabled section">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/signals-list-disabled.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=f85485e4ba55dec5abcacca14dce953a" alt="Signals list with an Active section and a Disabled section, the disabled Signal card dimmed with a Disabled badge" width="1512" height="982" data-path="images/signals/signals-list-disabled.png" />
</Frame>

You can also pause a single [alert](/signals/alerts#enable-or-disable-an-alert) instead of the whole Signal, to keep collecting events while silencing notifications.

## 5. Inspect events

Open the Signal detail page and switch to the **Events** tab. Each row is one detected event, linked back to the trace that produced it.

<Frame caption="Events tab: structured payloads, timestamps, and jump-to-trace links">
  <img src="https://mintcdn.com/laminarai-docs-lam-1786-dataset-cli-lmnr-cli/Vjr3k9UkDsim3SCJ/images/signals/signal-detail.png?fit=max&auto=format&n=Vjr3k9UkDsim3SCJ&q=85&s=b3f84c2b03407a1444df1283371fc310" alt="Signal events view with chart, event list, and per-event payload" width="1512" height="982" data-path="images/signals/signal-detail.png" />
</Frame>

From here you can:

* Filter events by any field you defined in the structured output schema.
* Click any row to open the corresponding trace.
* Scroll to the clusters view below the events table to see similar events grouped together. See [Clusters](/signals/clusters).
* Query the raw events in the [SQL Editor](/platform/sql-editor) via the `signal_events` table.

## Querying `signal_events` in SQL

`signal_events` stores each event's payload as a JSON string. The UI's payload filter uses `simpleJSONExtractString` / `simpleJSONExtractRaw`, so you can mirror the same behavior in SQL.

### Quick payload filter (UI-equivalent)

```sql theme={null}
SELECT
    timestamp,
    trace_id,
    name,
    payload
FROM signal_events
WHERE name = 'checkout.completed'
  AND (
    simpleJSONExtractString(payload, 'error_type') = 'timeout'
    OR simpleJSONExtractRaw(payload, 'error_type') = 'timeout'
  )
  AND timestamp > now() - INTERVAL 7 DAY
ORDER BY timestamp DESC
LIMIT 200
```

### Numeric comparisons with JSONExtractFloat

```sql theme={null}
SELECT
    timestamp,
    trace_id,
    JSONExtractFloat(payload, 'score') AS score,
    JSONExtractFloat(payload, 'latency_ms') AS latency_ms
FROM signal_events
WHERE name = 'agent_response_quality'
  AND JSONExtractFloat(payload, 'score') >= 0.9
  AND timestamp > now() - INTERVAL 30 DAY
ORDER BY score DESC
```

### Typed or nested fields with JSONExtract

```sql theme={null}
SELECT
    timestamp,
    trace_id,
    JSONExtract(payload, 'summary', 'String') AS summary,
    JSONExtract(payload, 'metrics', 'confidence', 'Float64') AS confidence,
    JSONExtract(payload, 'labels', 'Array(String)') AS labels
FROM signal_events
WHERE name = 'support.intent_classification'
  AND timestamp > now() - INTERVAL 14 DAY
ORDER BY timestamp DESC
LIMIT 100
```

## Next steps

<CardGroup cols={2}>
  <Card title="Clusters" href="/signals/clusters" icon="boxes">
    Group similar events into recurring patterns.
  </Card>

  <Card title="Alerts" href="/signals/alerts" icon="bell">
    Send Slack or email notifications on new signal events.
  </Card>
</CardGroup>
