> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.hoop.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> What to do with a running Sidecar

You have a Sidecar running from the file in [Overview](/docs/introduction/getting-started#run-it). This page is what to do with it: confirm what it resolved, watch the rules fire, read what it recorded, and reshape the file as your setup grows.

Every command below assumes that file and a Sidecar started with it.

***

## Confirm what it resolved

Inheritance is merged at startup, so the file tells you what you asked for and the Sidecar tells you what it built. Ask before you deploy — nothing needs to be running:

```bash theme={"dark"}
hoop start sidecar --config config.yaml --validate
```

```
config OK: 1 listener(s)
  localdb          postgres  enforcing 1 rule(s) + masking
```

One line per listener, already resolved: the rule count includes anything inherited from the top level, `+ masking` means a `mask` block reached it, and `observe-only` means it is not denying. Ask a running process the same question:

```bash theme={"dark"}
curl -s localhost:19000/config | jq '.lanes[] | {name, rules}'
```

This is the first thing to check when a rule you wrote never fires.

***

## Connect through it

Point the client at the Sidecar's port instead of the resource's. Nothing else about the client changes:

```bash theme={"dark"}
PGSSLMODE=disable psql -h 127.0.0.1 -p 15432 -U postgres
```

The Sidecar reads the wire protocol, so it needs the connection in the clear. Terminate TLS in front of it — see [Running the Sidecar](/docs/setup/configuration/hoop-inspect/get-started) for the Envoy shapes.

***

## Watch masking work

The rule in the file rewrites emails on the way out. The client never receives the real value:

```
 SELECT name, email FROM customers;

     name     |          email
--------------+--------------------------
 Ada Lovelace | [REDACTED:EMAIL_ADDRESS]
 Grace Hopper | [REDACTED:EMAIL_ADDRESS]
```

`redact` is one of four strategies, and swapping it is a one-line change:

```yaml theme={"dark"}
mask:
  enabled: true
  rules:
    - {name: cards, entity: CREDIT_CARD, strategy: partial, keep_last: 4}
```

| Strategy  | `4111111111111111` becomes                              |
| --------- | ------------------------------------------------------- |
| `redact`  | `[REDACTED:CREDIT_CARD]`                                |
| `mask`    | `****************`                                      |
| `partial` | `************1111`                                      |
| `hash`    | `sha256:<first 16 hex>`, so a masked column still joins |

A rule can also name result columns instead of an entity, which catches a value no detector recognizes:

```yaml theme={"dark"}
    - {name: internal-id, columns: [customer_ref], strategy: hash}
```

More in [Data Masking](/docs/features/data-masking).

***

## Watch a guardrail refuse

The `operation` rule denies `drop`, `delete` and `truncate`, and the statement never reaches the resource:

```
 DELETE FROM customers WHERE id = 1;

FATAL:  destructive statements are not permitted
```

That is a real pgwire error carrying the `message` you wrote in the config, so the developer reads the reason in `psql` instead of watching a connection drop. On an HTTP listener the same denial arrives as `403` with an `X-Hoop-Denied` header.

`operation` is one of eight rule types. Deny by table, by pattern, by detected PII, by HTTP resource or status, by word list, or by AI verdict — all in [Guardrails](/docs/features/guardrails).

***

## Measure before you deny

Turning rules on against real traffic is easier when nothing breaks first. Set enforcement off and every statement is still inspected and recorded, but nothing is refused:

```yaml theme={"dark"}
policy:
  enforce: false
```

```
config OK: 1 listener(s)
  localdb          postgres  observe-only
```

Then read what *would* have been denied:

```bash theme={"dark"}
curl -s 'localhost:19000/api/events?kind=violation' | python3 -m json.tool
```

When that list holds nothing you did not expect, set `enforce: true`.

***

## Read what it recorded

Every session is recorded whether or not it issues a statement. The admin API is the fast way in:

```bash theme={"dark"}
curl -s localhost:19000/api/stats                | python3 -m json.tool
curl -s 'localhost:19000/api/sessions?limit=1'   | python3 -m json.tool
```

```json theme={"dark"}
{"sessions": [
  {"id": "98203ccc…", "principal": "anonymous", "protocol": "postgres",
   "connection": "localdb", "duration_ms": 11,
   "statement_count": 2, "denied_count": 1, "masked_count": 0, "verdict": "denied"}
]}
```

The query endpoints filter on `principal`, `connection`, `protocol`, `since`, `until`, `denied`, `open`, and `q` for a substring, with `limit` and `cursor` for paging. `/api/events` also takes `session_id` and a repeatable `kind`.

The same events go to stdout as JSON lines, which is the durable copy — the admin API reads in-memory buffers sized by `audit.memory_buffer` and `audit.query_sessions`. Full detail in [Audit](/docs/core-concepts/sidecar#audit).

***

## Put it in front of something else

`protocol` picks the codec, and the rest of the listener keeps its shape. SQL Server:

```yaml theme={"dark"}
  - name: reporting
    protocol: mssql
    listen: 127.0.0.1:11433
    upstream: mssql.internal:1433
    connection: reporting
```

An HTTP API, which captures nothing until you ask it to:

```yaml theme={"dark"}
  - name: billing-api
    protocol: http
    listen: 127.0.0.1:18080
    upstream: billing.internal:8080
    connection: billing-api
    http:
      capture_body: true          # off by default: no bodies, no headers
```

***

## Protect more than one resource

`listeners` is a list, so a second resource is a second entry rather than a second process. Each one carries its own rules and can override the top-level defaults:

```yaml theme={"dark"}
listeners:
  - name: localdb
    protocol: postgres
    listen: 127.0.0.1:15432
    upstream: 127.0.0.1:5432
    connection: localdb

  - name: billing-api
    protocol: http
    listen: 127.0.0.1:18080
    upstream: billing.internal:8080
    connection: billing-api
    policy:
      rules:
        - name: no-admin-api
          type: http_resource
          resources: ["/admin/**"]
          message: the admin API is not reachable through this proxy
```

```
config OK: 2 listener(s)
```

One caveat worth knowing before you split rules across levels: `policy.rules` concatenate with the listener's first, while a listener's `mask` block **replaces** the top-level list rather than extending it.

***

## Pass the config another way

`--config` also reads `HOOP_SIDECAR_CONFIG`, which is the shape a Kubernetes deployment wants — mount the ConfigMap, set the variable, pass no arguments:

```bash theme={"dark"}
export HOOP_SIDECAR_CONFIG=/etc/hoop/config.yaml
hoop start sidecar
```

***

## Where to go next

<CardGroup cols={3}>
  <Card title="Running the Sidecar" icon="play" href="/docs/setup/configuration/hoop-inspect/get-started">
    Transports, putting it behind Envoy, and a compose stack that runs the whole thing on your laptop.
  </Card>

  <Card title="Config File Reference" icon="file-code" href="/docs/setup/configuration/hoop-inspect/config-file">
    Every section, every field, and what startup refuses.
  </Card>

  <Card title="Agentic Access" icon="robot" href="/docs/features/agentic-access">
    Put an AI Analyzer in front of the rules and let the risk level pick what happens.
  </Card>
</CardGroup>
