> ## Documentation Index
> Fetch the complete documentation index at: https://hoopdev-docs-control-plane-owns-listeners.mintlify.site/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](/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={null}
hoop start sidecar --config config.yaml --validate
```

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

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

```bash theme={null}
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={null}
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](/setup/configuration/hoop-sidecar/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={null}
mask:
  rules:
    - {name: cards, entities: [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 |

`entities` is a list, so one rule can name several. A rule can also name result columns instead, which catches a value no detector recognizes:

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

More in [Data Masking](/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](/features/guardrails).

***

## Measure before you deny

A rule set that reaches a lane enforces — there is no observe-only switch to leave off. To measure first, run the new rules on a lane pointed at a staging copy of the resource, send real query shapes through it, and read what got denied:

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

Each `violation` names the rule that fired and the message the client read, so an over-broad rule is visible by name before it reaches production. For a rule you want live on production without deciding on its own, give it `action: defer` and let [OPA](/setup/configuration/hoop-sidecar/policy-rules#deferring-to-opa) allow it while you watch the findings.

***

## 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={null}
curl -s localhost:19000/api/stats                | python3 -m json.tool
curl -s 'localhost:19000/api/sessions?limit=1'   | python3 -m json.tool
```

```json theme={null}
{"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](/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={null}
  - name: reporting
    protocol: mssql
    listen: 127.0.0.1:11433
    upstream: mssql.internal:1433
```

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

```yaml theme={null}
  - name: billing-api
    protocol: http
    listen: 127.0.0.1:18080
    upstream: billing.internal:8080
    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={null}
listeners:
  - name: localdb
    protocol: postgres
    listen: 127.0.0.1:15432
    upstream: 127.0.0.1:5432

  - name: billing-api
    protocol: http
    listen: 127.0.0.1:18080
    upstream: billing.internal:8080
    guardrails:
      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: `guardrails.rules` concatenate with the listener's first, while a listener's `mask` and `opa` blocks **replace** the top-level ones rather than extending them.

***

## 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={null}
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="/setup/configuration/hoop-sidecar/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="/setup/configuration/hoop-sidecar/config-file">
    Every section, every field, and what startup refuses.
  </Card>

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