> ## Documentation Index
> Fetch the complete documentation index at: https://tracevell.com/docs/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 Tracevell project ships with a **Failure Detector** signal pre-created. It runs
> automatically on traces with more than 1000 tokens, and 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.

## Prerequisites

* A Tracevell project and `LMNR_PROJECT_API_KEY`.
* An agent or LLM app whose traces land in Tracevell. The example below uses the [Claude Agent SDK](https://tracevell.com/docs/integrations/claude-agent-sdk.md) to produce traces quickly.
* On a self-hosted deployment, one [LLM profile](https://tracevell.com/docs/platform/llm-profiles.md) in the workspace. Each Signal picks a profile and one of its models to run on. On Tracevell Cloud there is nothing to configure.

## 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 Tracevell, 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 Tracevell 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.

![Signals list view with cards for each Signal and recent event counts](https://mintcdn.com/laminarai/_RffGZ5BN8_uG7vl/images/signals/signals-list.png?fit=max\&auto=format\&n=_RffGZ5BN8_uG7vl\&q=85\&s=a9e6a0e5cc9b1831f00258adcf1b9a44)

Signals list: one card per Signal with its event and cluster counts

To write your own, click **+ Signal**. The Create Signal drawer opens with the definition at the top and the trigger, filters, and sampling below it.

![Empty Create Signal drawer showing the trigger options and the default total tokens filter](https://mintcdn.com/laminarai/_RffGZ5BN8_uG7vl/images/signals/create-signal-empty.png?fit=max\&auto=format\&n=_RffGZ5BN8_uG7vl\&q=85\&s=66e72a33da9344549b6f5d25ec6eab58)

Create Signal drawer: name, template, instruction, and output schema on top, trigger and filters below

## 3. Write the Signal

![Create Signal drawer populated with a name, the Task template, an instruction, and two output schema fields](https://mintcdn.com/laminarai/_RffGZ5BN8_uG7vl/images/signals/create-signal-filled.png?fit=max\&auto=format\&n=_RffGZ5BN8_uG7vl\&q=85\&s=15ff3fb5ef922d48158d614d3b39c0de)

Create Signal drawer filled in from the Task template: the instruction and output schema come prefilled

**1. Name**

**2. Template (optional)**

Templates prefill the instruction and schema

**3. Instruction**

Describe what the Signal should detect or extract from the trace in plain English. This is an instruction to the Signals agent, not a full LLM prompt: skip the role (*You are a judge...*) and the output format, and say what to look for. One or two sentences is often enough. See [Write the instruction](https://tracevell.com/docs/signals/introduction.md#write-the-instruction).

**4. Structured output**

Signals Agent will generate a payload for every event. Define the shape of this payload with a
JSON schema.

**5. Trigger**

*When* the Signal evaluates a trace. A Signal has exactly one trigger.

* **When a trace finishes** — fires once the trace's root span ends. The default, and right for most agents.
* **When a specific span finishes** — fires when any span you name ends. Use this when the work is spread across services and spans keep arriving after the root span closes (distributed tracing).

**6. Filters**

*Which* traces actually run once the trigger fires. Filters are **AND-combined** — a trace runs only if every filter passes. The default is `total tokens > 1000`.

| Filter | Type | Matches against |
| - | - | - |
| **Total tokens** | number | The trace's cumulative token count across all spans. |
| **Status** | enum | `error` if any span in the trace errored, `success` otherwise. |
| **Span names** | array | Any span name anywhere in the trace. |
| **Span tags** | array | Any [tag](https://tracevell.com/docs/tracing/structure/tags.md) attached to any span in the trace. |

**7. Sampling (optional)**

Evaluate only a percentage of matching traces (5–95%). Sampling is applied **per user**, so coverage stays spread across your user base instead of concentrating on whoever is noisiest. Useful when a broad filter would otherwise fan out across every trace.

Click **Create**. The Signal is live from this point on: the trigger starts processing new traces that match the filters.

> [!NOTE]
>
> By default, Signals will notify the creator of critical events through the platform notifications panel and email. Open the Signal's **Settings > Alerts** section to change channels, connect Slack, or add additional filters. See [Alerts](https://tracevell.com/docs/signals/alerts.md).

## 4. Manage the Signal

A Signal can evaluate new traces as they arrive, or a historical slice. Open a Signal and click **Settings** to manage both from a sidebar with four sections: **General** (definition, trigger, and filters), **Versions** (the history of the Signal's definition), **Alerts**, and **Backfill**. Every evaluation the Signal performs is listed on the **Runs** tab, next to **Events** and **Settings**.

![Signal settings General section with the trigger options and the filters bar](https://mintcdn.com/laminarai/_RffGZ5BN8_uG7vl/images/signals/signal-settings.png?fit=max\&auto=format\&n=_RffGZ5BN8_uG7vl\&q=85\&s=a2f9301346bf48333428697e258e2743)

Signal Settings > General: instruction, output schema, trigger, filters, and sampling

### 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.

![Backfill page with trace selection, filters, and trace table](https://mintcdn.com/laminarai/FewoaJfRhgoIkj3v/images/signals/create-job.png?fit=max\&auto=format\&n=FewoaJfRhgoIkj3v\&q=85\&s=07d1f0fe5b4107b249f0f4f2fed21b58)

Start a backfill: pick traces or filters, then enqueue

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**. Tracevell enqueues one Run per trace.

Backfills count toward your workspace's Signals usage. If the workspace has reached its Signals hard limit, the backfill is rejected: see [Usage limits](https://tracevell.com/docs/platform/usage-limits.md).

Runs appear on the **Runs** tab with a status (Pending, Processing, Completed, Failed), a source that distinguishes backfilled Runs from the ones a live trigger produced, and the token cost of the evaluation. Each Run that detected the Signal links to the event it created.

![Signal runs table listing runs with status, source, event, clusters, cost, and event id](https://mintcdn.com/laminarai/FewoaJfRhgoIkj3v/images/signals/signal-activity.png?fit=max\&auto=format\&n=FewoaJfRhgoIkj3v\&q=85\&s=c0d563938d8a23737d54f0bfa5c6aa63)

The Runs tab: one row per evaluated trace with its source, status, cost, and the event it produced

### 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.

![Signal settings General section with the Active switch flipped off and the signal marked Inactive](https://mintcdn.com/laminarai/FewoaJfRhgoIkj3v/images/signals/signal-active-switch.png?fit=max\&auto=format\&n=FewoaJfRhgoIkj3v\&q=85\&s=07f79e246e806f7db6b0afd59672ffb8)

The Active switch at the top of Settings > General; flipped off, the Signal reads Inactive

While a Signal is paused:

* New traces are not evaluated, even if they match the Signal's trigger and filters.
* 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.

![Signals list with an Active section and a Disabled section, the disabled Signal card dimmed with a Disabled badge](https://mintcdn.com/laminarai/_RffGZ5BN8_uG7vl/images/signals/signals-list-disabled.png?fit=max\&auto=format\&n=_RffGZ5BN8_uG7vl\&q=85\&s=3afce76ab553698f9aeee7decc8e10b6)

The Signals list groups paused Signals under a Disabled section

You can also pause a single [alert](https://tracevell.com/docs/signals/alerts.md#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.

![Signal events view with chart, event list, and per-event payload](https://mintcdn.com/laminarai/FewoaJfRhgoIkj3v/images/signals/signal-detail.png?fit=max\&auto=format\&n=FewoaJfRhgoIkj3v\&q=85\&s=4442be48d5a3622b87858e1724bd9ebb)

Events tab: structured payloads, timestamps, and jump-to-trace links

From here you can:

* Filter events by any field you defined in the structured output schema.
* Click any row to open the corresponding trace.
* Use the clusters view above the events table to see similar events grouped together. See [Clusters](https://tracevell.com/docs/signals/clusters.md).
* Query the raw events in the [SQL Editor](https://tracevell.com/docs/platform/sql-editor.md) 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.

Events are also attached to the traces they came from, as `signal_events` and `clusters` columns on the `traces` table. Read them from there when the row you want back is a trace: see [Signal events on traces](https://tracevell.com/docs/platform/sql-editor.md#signal-events-on-traces).

### 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

> [card] [Clusters](https://tracevell.com/docs/signals/clusters.md)
>
> Group similar events into recurring patterns.

> [card] [Alerts](https://tracevell.com/docs/signals/alerts.md)
>
> Send Slack or email notifications on new signal events.

> [card] [CLI](https://tracevell.com/docs/signals/cli.md)
>
> Do all of this from the terminal instead: create, update, and delete Signals.

> [card] [SQL Editor](https://tracevell.com/docs/platform/sql-editor.md)
>
> Query the `signal_events` table directly across every Signal.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.