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

# Quickstart

> Run Sengol locally, gate an agent response, and verify the evidence offline.

This guide runs the whole loop on your laptop: start the appliance, evaluate
one agent response, export the signed evidence, and verify it without Sengol.

> [!WARNING]
>
> The local stack uses fixed development secrets and a `dev` licence. Do not
> use it for anything beyond a laptop.

## Before you start

* Docker 24 or later, with Docker Compose
* Python 3.11 or later

Everything installs from public packages: the `sengol-platform` image on GHCR
and the `sengol` package on PyPI. This release is a pre-release (`2.0.1a2`), so
the versions are pinned exactly.

## 1. Start the appliance

```bash theme={null}
mkdir sengol-demo && cd sengol-demo   # a new directory: the next steps write .env and docker-compose.yml
export SENGOL_IMAGE=ghcr.io/sengol-io/sengol-platform:2.0.1a2
echo "SENGOL_IMAGE=$SENGOL_IMAGE" > .env

# The image carries the demo compose file (Postgres + API + Console).
docker run --rm --entrypoint cat "$SENGOL_IMAGE" /app/demo/docker-compose.yml > docker-compose.yml

# Write an Ed25519 evidence-signing key into .env.
docker run --rm -i --entrypoint python "$SENGOL_IMAGE" - >> .env <<'PY'
from cryptography.hazmat.primitives import serialization as s
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

pem = Ed25519PrivateKey.generate().private_bytes(
    s.Encoding.PEM, s.PrivateFormat.PKCS8, s.NoEncryption()
).decode()
print('SENGOL_EVIDENCE_SIGNING_KEY="' + pem.replace("\n", "\\n") + '"')
PY

docker compose up -d postgres
docker compose run --rm --entrypoint alembic sengol-api upgrade head
docker compose up -d

# Seed five demo agents and two weeks of signed records.
docker compose run --rm --entrypoint python sengol-api /app/scripts/seed_demo.py \
  --api-url http://sengol-api:8080 --admin-secret dev-admin-bootstrap-secret
```

The seeder ends by printing a one-hour admin token. The Console address it
prints uses the container's hostname; open `http://localhost:8080/console`
instead.

```text theme={null}
Done: 5 agents, 420 signed records.
Console: http://localhost:8080/console   token: eyJhbGciOi...
```

Open `http://localhost:8080/console`, choose **Sign in with an API token
instead**, and paste the token. Pasting signs you in; there is no button to
press. The banner at the top says you are on a development licence.

![Console sign-in page with the API token field](https://mintcdn.com/sengol/WAzD6pTFOjHwDiMz/images/console-login.png?fit=max\&auto=format\&n=WAzD6pTFOjHwDiMz\&q=85\&s=41671c73d7178cf2362a514478c3f817)

The sign-in page, after choosing Sign in with an API token instead.

The **Overview** shows the seeded portfolio against the ControlBook:

![Console overview page with portfolio score 96 and one agent needing review](https://mintcdn.com/sengol/WAzD6pTFOjHwDiMz/images/console-overview.png?fit=max\&auto=format\&n=WAzD6pTFOjHwDiMz\&q=85\&s=4cc24882748daa5bce2b56c3b7a59f55)

Overview: portfolio score and the agents outside their ControlBook.

> [!NOTE]
>
> The seeder reports `not registered ... needs an approved intake` for each
> demo agent. That is expected. New agents are registered through an intake
> that an approver approves. The evidence is ingested anyway.

## 2. Install the CLI

The CLI and Python SDK ship in the `sengol` package. Install it into a
virtual environment:

```bash theme={null}
python3 -m venv .venv && source .venv/bin/activate
pip install "sengol==2.0.1a2"
```

Point the CLI at the API. The local stack accepts the bootstrap secret
`dev-admin-bootstrap-secret` in exchange for an admin token:

```bash theme={null}
export SENGOL_API_URL=http://localhost:8080
export SENGOL_TENANT_ID=dev-tenant
export SENGOL_API_TOKEN=$(curl -s -X POST "$SENGOL_API_URL/v1/auth/token" \
  -H "Content-Type: application/json" \
  -d '{"grant_type":"console_admin","secret":"dev-admin-bootstrap-secret"}' \
  | python -c 'import sys, json; print(json.load(sys.stdin)["access_token"])')
curl -s "$SENGOL_API_URL/health"
```

> [!TIP]
>
> `SENGOL_TENANT_ID` must match the appliance's tenant (`dev-tenant` in the
> local stack). A mismatch makes the API refuse records with `422`.

## 3. Gate one agent response

Create `sengol.yaml`. It names the agent, the evaluators to run, and one
sample response:

```yaml sengol.yaml theme={null}
agent:
  agent_id: quickstart-agent
  agent_version: 1.0.0

suite:
  name: quickstart
  evaluators:
    - ResponseLengthEvaluator
    - PIIEvaluator

sample_input:
  agent_id: quickstart-agent
  agent_version: 1.0.0
  prompt: "What is the management fee on Fund X?"
  response: "The management fee on Fund X is 0.42%. Past performance is not indicative of future results."
  policies:
    - OSFI_E23
```

Run the gate and keep its run id:

```bash theme={null}
sengol gate --config sengol.yaml --fail-on-gate-failure | tee gate.log
RUN_ID=$(grep '^run_id=' gate.log | cut -d' ' -f1 | cut -d= -f2)
```

The last line of output is the verdict:

```text theme={null}
run_id=01a10cae-a5f9-... gate_passed=True pass_rate=100.00% (1/1)
```

The appliance stores the run as a signed `EvaluationRunRecord`. Read it back:

```bash theme={null}
curl -s "$SENGOL_API_URL/v1/eval-runs/$RUN_ID" \
  -H "Authorization: Bearer $SENGOL_API_TOKEN" | python -m json.tool
```

```json theme={null}
{
  "run_id": "01a10cae-a5f9-...",
  "agent_id": "quickstart-agent",
  "pass_rate": 1.0,
  "gate_passed": true,
  "required_pass_rate": 0.95,
  "scores_by_evaluator": {"PIIEvaluator": 1.0, "ResponseLengthEvaluator": 1.0},
  "hmac_signature": "ac30a404...",
  ...
}
```

Now make the agent leak personal data. Replace the response with one that
contains an email address and run the gate again:

```bash theme={null}
sed -i.bak 's/response: .*/response: "Email jane.doe@example.com for the fee schedule."/' sengol.yaml
```

```bash theme={null}
sengol gate --config sengol.yaml --fail-on-gate-failure
```

`PIIEvaluator` fails with `PII_DETECTED`, the gate reports
`gate_passed=False`, and the command exits `1`. Without
`--fail-on-gate-failure`, a failed gate still exits `0`.

> [!NOTE]
>
> The gate signs one aggregate record per run. It does not store a separate
> record per sample. Per-response records come from the runtime path: the
> SDK, guardrails, or trace ingest. See the [AI developer
> journey](https://docs.sengol.io/journeys/ai-developer.md).

## 4. Export the evidence

The seeder wrote two weeks of per-response records for five agents.

The appliance countersigns records in the background, nine at a time every
30 seconds by default. Right after seeding, most records are still queued.
Drain the queue now instead of waiting about 20 minutes:

```bash theme={null}
until [ "$(curl -s -X POST "$SENGOL_API_URL/v1/outbox/drain" \
    -H "Authorization: Bearer $SENGOL_API_TOKEN" \
    | python -c 'import sys, json; print(json.load(sys.stdin)["claimed"])')" = 0 ]; do :; done
```

Export one agent's records as an evidence pack:

```bash theme={null}
sengol export --agent gic-advisor --out pack.json --wait-for-countersign
```

```text theme={null}
Bundle written to pack.json (84 records, 84 countersigs, 0 anchors).
```

The same records appear in the Console under **Monitor → Traces**:

![Traces page listing signed evaluation records for gic-advisor](https://mintcdn.com/sengol/WAzD6pTFOjHwDiMz/images/console-traces.png?fit=max\&auto=format\&n=WAzD6pTFOjHwDiMz\&q=85\&s=4a505c14a81df6d6b82d68aa74a00641)

Traces: every signed record, with its result and policies.

`pack.json` holds the signed records, their Ed25519 countersignatures, and
the appliance's public keys. `--wait-for-countersign` waits up to 30 seconds
for countersigning to finish. If the output ends with `countersignature(s)
still pending`, drain the queue again and re-export.

## 5. Verify it without Sengol

`sengol-verify` is a separate, Apache-2.0 package with no dependency on
Sengol. Install it and check the pack:

```bash theme={null}
pip install sengol-verify
```

```bash theme={null}
sengol-verify pack.json
```

It exits `3`: the chain is intact, but you have not said which appliance key
you trust. The key embedded in the pack only proves the pack is internally
consistent. Fetch the appliance's key from the appliance itself, then verify
against it:

```bash theme={null}
curl -s "$SENGOL_API_URL/v1/audit/verification-keys" \
  | python -c 'import sys, json; json.dump({k: v["public_key"] for k, v in json.load(sys.stdin)["keys"].items()}, open("trusted-keys.json", "w"))'
sengol-verify pack.json --trusted-keys-file trusted-keys.json
```

Exit `0` means every check that can run offline passed and the
countersignatures match a key you trust. See the [auditor
journey](https://docs.sengol.io/journeys/auditor.md) for what each check proves.

## Clean up

```bash theme={null}
docker compose down -v   # stops the stack and deletes its volume
```

## Next steps

> [card] [Evaluate in code](https://docs.sengol.io/journeys/ai-developer.md)
>
> Use the SDK and guardrails.

> [card] [Gate in CI](https://docs.sengol.io/guides/ci-gate.md)
>
> Add the GitHub Action.

> [card] [Write a ControlBook](https://docs.sengol.io/concepts/controlbook.md)
>
> Map regulations to evaluators.

> [card] [Install for real](https://docs.sengol.io/journeys/platform-operator.md)
>
> Licence, identity, roles.


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