---
title: Quickstart
description: Run sigiro with one docker command. Point OpenTelemetry at it. Then ask it what changed and why. This takes five minutes. You need no collector and no configuration file.
sidebar:
  order: 1
---

In this tutorial you start a sigiro server, send it telemetry from your own
service, and ask it two questions. At the end you read a diagnosis and run the
SQL behind it. This takes five minutes.

sigiro is one process. You deploy no collector and you write no configuration
file.

## 1. Run it

{/* `param` makes the choice shareable — /docs/tutorials/quickstart?install=docker
    opens on that tab — and `sync` is Blume's default, so every install tab group
    on the site follows the same pick. Nothing is imported: Blume provides these
    in situ. Keep this comment to ONE paragraph: `oxfmt` formats `.mdx` and
    escapes the opening `{/*` to `{/\*` when the comment spans a blank line,
    which fails the MDX parser and the build. On why a tutorial offers a choice
    at all — Diátaxis says it should not — see `meta.ts` in this directory. */}

**binary**

```bash
curl -fsSL https://sigiro.com/install | sh
sigiro serve
```

The script reads your operating system and processor. Then it checks the SHA-256
of the download against the published checksum. It writes the binary to
`~/.local/bin`. Set `SIGIRO_INSTALL_DIR` for a different directory.

Builds exist for Linux and macOS on arm64, and for Linux on x86-64. On another
platform, use the container.

**docker**

```bash
docker run -p 4317:4317 -p 4318:4318 -p 9999:9999 ghcr.io/sigiroai/sigiro
```

Add `-v sigiro-data:/var/lib/sigiro` to keep the data across container restarts.

Each of the three ports has one function:

| Port | Protocol |
| --- | --- |
| `4317` | OTLP over gRPC |
| `4318` | OTLP over HTTP |
| `9999` | the query and diagnose API |

At the first start, sigiro downloads its query extensions. This can take 30–90
seconds, so expect a pause before the server accepts a request. Each later start
is immediate. sigiro writes the data to `SIGIRO_DATA_DIR`. That directory is
`~/.local/share/sigiro` for the binary, and `/var/lib/sigiro` in the image.

Notice that the server asks you for no key. A self-hosted server authenticates
no request, so keep it on a private network. The network is the security
boundary.

## 2. Send it telemetry

Any OpenTelemetry SDK or collector in your stack works without a change. Point
the standard environment variables at sigiro:

```bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
OTEL_SERVICE_NAME=checkout \
  <your-app-start-command>
```

If your code has no instrumentation yet, do not add it by hand. Follow
[Instrument your code with an agent](/docs/how-to/install-with-ai) first, then
come back here.

Now send some real traffic through your service, and confirm that the telemetry
arrived:

```bash
curl http://localhost:9999/v1/services
```

The response is a JSON object with a `services` array. Your service appears in
that array within a few seconds of the first request. If the array is empty,
check that the port is `4318` for OTLP over HTTP and `4317` for OTLP over gRPC.

## 3. Ask what changed

`anomalies` is the entry point of the loop. It returns the shifts that deviate
from the recent baseline of each service, biggest shift first.

```bash
sigiro anomalies
sigiro anomalies --service checkout
```

You configure nothing here. There are no thresholds to choose, and a service
that is always slow but *stable* is not an anomaly. To read how sigiro decides
that, see [About evidence instead of a
dashboard](/docs/explanation/evidence#a-baseline-not-a-threshold).

Notice that the list can be empty on a young server. sigiro needs a few
5-minute buckets of history before it can compare anything, so run your service
for a while and then ask again.

## 4. Ask why

`diagnose` returns one structured evidence block for a service and a time
window. The block starts with a ranked list of what deserves attention. Under
that, it holds error counts, error breakdowns for each operation, LLM statistics
for each model, sampled spans, and deduplicated log patterns. Every row also
carries a ready-to-run SQL query.

```bash
sigiro diagnose checkout
sigiro diagnose checkout --from $(date -v-1H +%s)
```

The command prints indented JSON. Read the `findings` array first: it is sorted
critical first, and each item carries a `summary` you can read and a
`drill_down_sql` you can run.

An agent asks the same question over HTTP. The HTTP request needs an explicit
window, and both timestamps are **microseconds** since the Unix epoch:

```bash
curl -X POST http://localhost:9999/v1/diagnose \
  -H 'content-type: application/json' \
  -d "{\"service\":\"checkout\",
       \"from_ts\":$(( $(date +%s) - 900 ))000000,
       \"to_ts\":$(date +%s)000000}"
```

The `--from`/`--to` flags on the CLI take epoch **seconds**, and the CLI
defaults the window to the last 15 minutes. The HTTP body takes microseconds and
defaults nothing. sigiro rejects a seconds value on the HTTP path with a message
that names the unit, so a wrong unit fails loudly rather than returns an empty
window.

## 5. Run the query behind a row

When the evidence block does not answer your question, run the SQL that a row
gave you. Your telemetry is a set of tables, and the body of a query request is
the raw SQL rather than JSON:

```bash
curl -X POST http://localhost:9999/v1/query \
  --data "SELECT service_name, count(*) AS errors
          FROM sigiro_spans
          WHERE status_code = 2 AND timestamp > now() - INTERVAL '1 hour'
          GROUP BY 1 ORDER BY errors DESC"
```

The response is a JSON array of row objects. `status_code` is the OTLP enum, so
`2` is an error.

Notice that the query bounds `timestamp`. Bound `timestamp` in every query:
sigiro keeps no secondary index, so a bounded query reads a small number of
files and an unbounded query reads every file.

`sigiro_spans` is one of nine tables. The
[hosted guide](/docs/how-to/hosted-onboarding#4-query-your-data-sql-api) lists
all nine with the rules that apply to them, and [About the
tables](/docs/explanation/tables) explains what each family measures.

## What you did

You started a server, sent it OpenTelemetry, asked it what changed, asked it
why, and ran the query that proves one of its answers. That is the whole loop
that an agent runs on its own.

## Next

- [Instrument your code with an agent](/docs/how-to/install-with-ai) — if your
  service still has no OpenTelemetry
- [Send telemetry to hosted sigiro](/docs/how-to/hosted-onboarding) — if you do
  not want to run the server yourself
- [CLI reference](/docs/reference/cli) — the other four subcommands, and every
  flag and environment variable
- `GET /openapi.json` — the full API, machine-readable, and no key is necessary
