From 8b51196f1c2ee0848f2296b6db933e4b020eeee4 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:02:54 +0100 Subject: [PATCH 1/2] docs: add Recall as homepage step 09 and to the README --- README.md | 8 ++++++++ website/public/index.html | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a9d3af395..776d5014b7 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,14 @@ The playground runs on local DuckDB, with no warehouse credentials. - **Tidy up safely.** The [janitor](https://sqlbuild.com/docs/cli/janitor/) archives stale tables before anything is deleted. +### Find out what happened + +- **Every run is recorded.** [Recall](https://sqlbuild.com/docs/concepts/observability/recall/) + keeps each command's statements, SQL, audit results and exact output. Agents and people query it + with SQL through [`sqb recall`](https://sqlbuild.com/docs/cli/recall/), then check live state in + the warehouse with the same command. History stays in a SQLite file in the project, or in + ClickHouse for a team. + Ingestion with Python loaders, and Python tasks, assets and checks, run in the same graph as your SQL models. See the [docs](https://sqlbuild.com/docs/) for everything else. diff --git a/website/public/index.html b/website/public/index.html index 0c34d03669..68cb11f56d 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -362,12 +362,45 @@

Archive old tables before deleting them

Relations to archive prod.weekly_revenue -> prod._sqb_archive__20260925t155417z__weekly_revenue … +

After production changes

+
+
+ 09 · Investigate +

Find out what happened, then check what's true now

+

+ Every run is recorded: what ran, the SQL it executed, audit results and everything it printed. Agents and people ask in SQL, then check live state with the same command. +

+
+
sqb recall query "SELECT invocation_started_at AS run, outcome, violation_count
+  FROM audit_results WHERE audit_name = 'revenue_is_non_negative'
+  ORDER BY run DESC LIMIT 3"
+run               | outcome | violation_count
+2026-10-20T00:01  | warn    | 1
+2026-10-20T00:00  | pass    | 0
+2026-10-19T23:59  | pass    | 0
+
+sqb recall output last --tail 4
+  daily_revenue
+    audit revenue_is_non_negative returned 1 row
+✓ Completed with warnings  PASS=89  WARN=1  FAIL=0  …
+
+sqb recall query --backend warehouse "SELECT r.revenue_date, r.total_revenue_cents,
+  p.payment_id, p.amount_cents FROM prod.daily_revenue r JOIN prod.stg_payments p
+  ON CAST(p.paid_at AS DATE) = r.revenue_date WHERE p.amount_cents < 0"
+revenue_date | total_revenue_cents | payment_id | amount_cents
+2026-04-03   | -1250               | 9          | -2200
+

Real output from SQLBuild's example project, trimmed to the relevant lines. During a migration the old table is never modified, archives can be renamed back until they expire, and every move is recorded. + In step 09 the audit started warning on the latest run, the build still finished, and the bad + row is still in prod: a refund recorded as a negative payment. Three queries, no log digging. + History stays in a SQLite file in your project, or in ClickHouse for a team. No service, no + account, no paid tier. How migrations work · - How the janitor works + How the janitor works · + How Recall works

From 433e443b70ca9d2ef4c7ae139c0247cb2604162b Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:06:59 +0100 Subject: [PATCH 2/2] docs: show a Recall investigation and point readers to Recall across the docs --- .../docs/concepts/adapters/clickhouse.md | 9 +++ .../docs/concepts/adapters/sqlite.md | 7 +++ .../references/docs/concepts/observability.md | 18 +++++- .../observability/execution-history.md | 4 ++ .../docs/concepts/observability/recall.md | 59 +++++++++++++++++++ .../references/docs/feature-comparison.md | 6 +- .../skills/sqlbuild/references/docs/index.md | 10 +++- .../sqlbuild/references/docs/roadmap.md | 4 +- website/public/index.html | 4 +- .../docs/concepts/adapters/clickhouse.mdx | 8 +++ .../docs/docs/concepts/adapters/sqlite.mdx | 6 ++ .../docs/docs/concepts/observability.mdx | 18 +++++- .../observability/execution-history.mdx | 4 ++ .../docs/concepts/observability/recall.mdx | 58 ++++++++++++++++++ .../content/docs/docs/feature-comparison.mdx | 6 +- website/src/content/docs/docs/index.mdx | 10 +++- website/src/content/docs/docs/roadmap.mdx | 4 +- 17 files changed, 217 insertions(+), 18 deletions(-) diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/clickhouse.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/clickhouse.md index b8bdd8f42d..c3cf447db9 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/clickhouse.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/clickhouse.md @@ -19,6 +19,7 @@ Online: https://sqlbuild.com/docs/concepts/adapters/clickhouse/ - Settings SQLBuild pins - SQL differences to watch - Limits +- Recall store The ClickHouse adapter is in beta and supports a single server. Clusters (`ON CLUSTER`, replicated and distributed tables) are not supported yet. Please [report issues](https://github.com/chio-labs/sqlbuild/issues). @@ -187,3 +188,11 @@ ClickHouse returns a type's default value (`0`, the epoch, an empty string) from - Snapshots always use an unsorted `MergeTree` table. - Seeds load through the HTTP insert interface as CSV, so large seeds never hit the `max_query_size` limit. - Retention and time travel are not available. + +## Recall store + +A ClickHouse connection can also hold [Recall](../observability/recall.md)'s command +history for a whole team, whichever adapter the project builds with. Set +`[recall] connection` to it; Recall creates its tables on first use, keeps every output byte by +default, and needs only `SELECT` and `INSERT` once the tables exist. See +[Sharing history in ClickHouse](../observability/recall.md#sharing-history-in-clickhouse). diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/sqlite.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/sqlite.md index 701f486d34..fc912192a9 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/sqlite.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/adapters/sqlite.md @@ -15,6 +15,7 @@ Online: https://sqlbuild.com/docs/concepts/adapters/sqlite/ - Capabilities - Scenarios - Limits +- Recall store SQLite uses the `sqlite3` module that ships with Python. No extra installation is needed. SQLBuild requires SQLite 3.44 or newer; Python builds installed by `uv` bundle a recent version. @@ -130,3 +131,9 @@ as `datetime(ordered_at, 'start of day')`, have no DuckDB translation and fail l | SQLite older than 3.44 | `A701` | | Another process holds the write lock beyond `busy_timeout` | `A702` | | Concurrent microbatch writes: one file has one writer | refused at plan time | + +## Recall store + +[Recall](../observability/recall.md) keeps its local history in a SQLite file, +`logs/recall.sqlite3`, for every project, whichever adapter it builds with. Point +`[recall] connection` at a `sqlite` connection to put the file somewhere else. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability.md index 1129254621..04e47f9354 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability.md @@ -13,14 +13,28 @@ whether work started, completed, failed, skipped, or retried. |--------|---------|-----------| | `LifecycleEvent` | Immutable invocation, run, resource-attempt, operation, statement, retry, and audit facts | Canonical lifecycle evidence once durably stored | | `DiagnosticLog` | Structured framework diagnostics | Explanatory only | -| `stdout.log` / `stderr.log` | Exact host-local process output | Troubleshooting transcript | -| [Recall](observability/recall.md) | Local queryable history of invocations, statements, SQL, and output | Troubleshooting history; best effort | +| [Recall](observability/recall.md) | Queryable history of invocations, statements, SQL, audit results, and output, locally or in ClickHouse | Troubleshooting history; best effort | +| `stdout.log` / `stderr.log` | Exact host-local process output (compute log files) | Troubleshooting transcript; also stored by Recall | | `CommandOutputRecord` | Bounded, ANSI-free remote stdout/stderr chunks | Potentially sensitive and lossy troubleshooting data | | Final JSON output | End-of-command aggregate | Result projection, not event history | Human-readable CLI output remains the normal operator interface. Structured records are a separate contract for integrations and durable consumers. +## Which to use + +| You want to | Use | +|-------------|-----| +| Find out what a past run did: what ran, its SQL, audit results, errors and output | [Recall](observability/recall.md) and [`sqb recall`](../cli/recall.md) | +| Send events or output to your own systems, such as a message queue or a monitoring tool | [Typed sinks](observability/sinks.md) | +| Store lifecycle events and query run state from your own Python application | [Execution history](observability/execution-history.md) | +| Read the result of the command you just ran | Its final `--json` output | + +Recall is on by default and covers investigation for people and agents. Sinks and execution history +are for building on SQLBuild's events elsewhere. The `stdout.log`, `stderr.log` and +`diagnostics.jsonl` compute log files under `logs//` are still written alongside Recall and +hold the same bytes; prefer `sqb recall output`, which works the same with a shared store. + ## Lifecycle envelope New events use lifecycle schema version 2: diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/execution-history.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/execution-history.md index 1399e3390c..bc1da46322 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/execution-history.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/execution-history.md @@ -17,6 +17,10 @@ published, rebuildable run projection. Diagnostic and compute logs are never acc contract. The public types, filters, pages, records, errors, and helper functions are exported from `sqlbuild.execution_history`. +This is a Python API for applications that store and serve SQLBuild events themselves. To look into +what past runs did, use [Recall](recall.md), which records every command +automatically and is queried with [`sqb recall`](../../cli/recall.md). + ## Public contracts `LifecycleEventLogStorage` provides `append_event`, `append_events`, `get_events`, `get_schema_version`, diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/recall.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/recall.md index 2b92ac0dcb..3c9aaa4bf6 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/recall.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/observability/recall.md @@ -8,6 +8,7 @@ Online: https://sqlbuild.com/docs/concepts/observability/recall/ ## Contents +- An investigation, start to finish - What is recorded - Settings - Output limit @@ -22,6 +23,64 @@ Recall records each `sqb` invocation in a local SQLite store, or in a shared [ClickHouse store](#sharing-history-in-clickhouse), so you can ask what happened after the fact: which command ran, how it ended, which statements it executed and how long they took, and exactly what it printed. Recall is on by default and needs no setup. +## An investigation, start to finish + +The waffle shop example's `daily_revenue` model has an audit, `revenue_is_non_negative`, at warn +severity. One night the payments feed starts recording a refund as a negative payment. The unit tests +still pass, because they run on mocked data. The build finishes with a warning that nobody reads. + +The next morning, ask when the audit started failing: + +```bash +sqb recall query --format table \ + "SELECT invocation_started_at AS run, outcome, violation_count FROM audit_results + WHERE audit_name = 'revenue_is_non_negative' ORDER BY run DESC LIMIT 3" +``` + +``` +run | outcome | violation_count +--------------------------- | ------- | --------------- +2026-10-20T00:01:44.784683Z | warn | 1 +2026-10-20T00:00:34.652468Z | pass | 0 +2026-10-19T23:59:23.827831Z | pass | 0 + +3 rows +``` + +See what that run printed, exactly as the scheduler saw it: + +```bash +sqb recall output last --tail 4 +``` + +``` + daily_revenue + audit revenue_is_non_negative returned 1 row + +✓ Completed with warnings PASS=89 WARN=1 FAIL=0 INSUFFICIENT=0 SKIP=0 TOTAL=90 (3.08s) +``` + +Then check what is true in the warehouse now, with the same command: + +```bash +sqb recall query --backend warehouse --format table \ + "SELECT r.revenue_date, r.total_revenue_cents, p.payment_id, p.amount_cents + FROM prod.daily_revenue r JOIN prod.stg_payments p + ON CAST(p.paid_at AS DATE) = r.revenue_date + WHERE p.amount_cents < 0" +``` + +``` +revenue_date | total_revenue_cents | payment_id | amount_cents +------------ | ------------------- | ---------- | ------------ +2026-04-03 | -1250 | 9 | -2200 + +1 row +``` + +The bad row is still in prod, and payment 9 explains it. A coding agent can follow the same steps: +every answer is a SQL query over the [views](#querying-history), with the same output in `--json`. + ## What is recorded For every recorded invocation, Recall keeps: diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/feature-comparison.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/feature-comparison.md index 15ca62a78a..f49854e538 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/feature-comparison.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/feature-comparison.md @@ -118,11 +118,11 @@ SQLBuild, dbt, and SQLMesh are all SQL pipeline frameworks. They share common gr | Feature | SQLBuild | dbt | SQLMesh | |---------|----------|-----|---------| | Reference syntax | `__ref()` - parses as valid SQL | `{{ ref() }}` - Jinja template | `model_name` with dependency tracking | -| Adapters | DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server | 30+ (community adapters) | DuckDB, Snowflake, BigQuery, Databricks, Spark, Redshift, Postgres, Trino, MySQL | +| Adapters | DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server, ClickHouse, SQLite | 30+ (community adapters) | DuckDB, Snowflake, BigQuery, Databricks, Spark, Redshift, Postgres, Trino, MySQL | | State requirements | Stateless by default | manifest.json + target/ | Requires state store (local database or PostgreSQL for production) | | Playground | `sqb playground` | Clone example repo | Example project | | AI agent skills | General guidance with `sqb skills`; Rules guidance with `sqb rules skills` | No | No | -| Execution observability | Immutable schema-versioned lifecycle facts, invocation-local ordering, orchestration context, and typed project sinks | Events/artifacts plus external observability | Plans, state, and external observability | +| Execution observability | Recall: every command's statements, SQL, audit results and output, queryable with SQL locally or in ClickHouse; immutable schema-versioned lifecycle facts and typed project sinks | Events/artifacts plus external observability | Plans, state, and external observability | ## Where each tool fits @@ -134,4 +134,4 @@ SQLBuild, dbt, and SQLMesh are all SQL pipeline frameworks. They share common gr ## Not yet in SQLBuild -- **Broader adapter support** - ClickHouse, Redshift, Trino, Spark, Athena +- **Broader adapter support** - Redshift, Trino, Spark, Athena diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/index.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/index.md index 6f40ad6671..75eddbc8f4 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/index.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/index.md @@ -42,6 +42,12 @@ updated, a [migration](concepts/models/migrations.md) moves its table instead of history, and the old name keeps working as a view. Columns can be renamed the same way. The [janitor](cli/janitor.md) archives tables the project no longer builds before it deletes them. +## Investigate + +[Recall](concepts/observability/recall.md) records every command: what ran, the SQL it executed, +audit results and everything it printed. Agents and people query that history with SQL through +[`sqb recall`](cli/recall.md), then check live state in the warehouse with the same command. + ## How it fits together | Step | Command | What it does | @@ -51,8 +57,10 @@ history, and the old name keeps working as a view. Columns can be renamed the sa | Plan | [`sqb plan`](cli/plan.md) | Shows what will run, why, and how much it will rebuild | | Build | [`sqb build`](cli/build.md) | Runs tests, builds models in dependency order, and blocks bad data with audits | | Compare | [`sqb diff`](cli/diff.md) | Compares schemas and rows between two targets | +| Investigate | [`sqb recall`](cli/recall.md) | Queries the history of past runs, then live warehouse state | -SQLBuild works with DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL and SQL Server. +SQLBuild works with DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server, +ClickHouse and SQLite. DuckDB runs locally, so you can try everything without warehouse credentials. See [Adapters](concepts/adapters.md) for connection setup. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/roadmap.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/roadmap.md index 25ad459e93..70259da331 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/roadmap.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/roadmap.md @@ -21,8 +21,8 @@ A self-hosted web app for your SQLBuild project: ## Later -- Moving BigQuery, Databricks and SQL Server from beta to supported. -- More warehouses, such as ClickHouse, Redshift and Trino. +- Moving BigQuery, ClickHouse, Databricks, SQLite and SQL Server from beta to supported. +- More warehouses, such as Redshift and Trino. ## Not planned diff --git a/website/public/index.html b/website/public/index.html index 68cb11f56d..058a1d2e7a 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -371,8 +371,8 @@

Find out what happened, then check what's true now

Every run is recorded: what ran, the SQL it executed, audit results and everything it printed. Agents and people ask in SQL, then check live state with the same command.

-
sqb recall query "SELECT invocation_started_at AS run, outcome, violation_count
-  FROM audit_results WHERE audit_name = 'revenue_is_non_negative'
+
sqb recall query "SELECT substr(invocation_started_at, 1, 16) AS run, outcome,
+  violation_count FROM audit_results WHERE audit_name = 'revenue_is_non_negative'
   ORDER BY run DESC LIMIT 3"
 run               | outcome | violation_count
 2026-10-20T00:01  | warn    | 1
diff --git a/website/src/content/docs/docs/concepts/adapters/clickhouse.mdx b/website/src/content/docs/docs/concepts/adapters/clickhouse.mdx
index 5aa6becff3..78ead20622 100644
--- a/website/src/content/docs/docs/concepts/adapters/clickhouse.mdx
+++ b/website/src/content/docs/docs/concepts/adapters/clickhouse.mdx
@@ -174,3 +174,11 @@ ClickHouse returns a type's default value (`0`, the epoch, an empty string) from
 - Snapshots always use an unsorted `MergeTree` table.
 - Seeds load through the HTTP insert interface as CSV, so large seeds never hit the `max_query_size` limit.
 - Retention and time travel are not available.
+
+## Recall store
+
+A ClickHouse connection can also hold [Recall](/docs/concepts/observability/recall)'s command
+history for a whole team, whichever adapter the project builds with. Set
+`[recall] connection` to it; Recall creates its tables on first use, keeps every output byte by
+default, and needs only `SELECT` and `INSERT` once the tables exist. See
+[Sharing history in ClickHouse](/docs/concepts/observability/recall#sharing-history-in-clickhouse).
diff --git a/website/src/content/docs/docs/concepts/adapters/sqlite.mdx b/website/src/content/docs/docs/concepts/adapters/sqlite.mdx
index a1930765ee..d9f871d197 100644
--- a/website/src/content/docs/docs/concepts/adapters/sqlite.mdx
+++ b/website/src/content/docs/docs/concepts/adapters/sqlite.mdx
@@ -117,3 +117,9 @@ as `datetime(ordered_at, 'start of day')`, have no DuckDB translation and fail l
 | SQLite older than 3.44 | `A701` |
 | Another process holds the write lock beyond `busy_timeout` | `A702` |
 | Concurrent microbatch writes: one file has one writer | refused at plan time |
+
+## Recall store
+
+[Recall](/docs/concepts/observability/recall) keeps its local history in a SQLite file,
+`logs/recall.sqlite3`, for every project, whichever adapter it builds with. Point
+`[recall] connection` at a `sqlite` connection to put the file somewhere else.
diff --git a/website/src/content/docs/docs/concepts/observability.mdx b/website/src/content/docs/docs/concepts/observability.mdx
index 7819885ff9..c93bfa395a 100644
--- a/website/src/content/docs/docs/concepts/observability.mdx
+++ b/website/src/content/docs/docs/concepts/observability.mdx
@@ -10,14 +10,28 @@ whether work started, completed, failed, skipped, or retried.
 |--------|---------|-----------|
 | `LifecycleEvent` | Immutable invocation, run, resource-attempt, operation, statement, retry, and audit facts | Canonical lifecycle evidence once durably stored |
 | `DiagnosticLog` | Structured framework diagnostics | Explanatory only |
-| `stdout.log` / `stderr.log` | Exact host-local process output | Troubleshooting transcript |
-| [Recall](/docs/concepts/observability/recall) | Local queryable history of invocations, statements, SQL, and output | Troubleshooting history; best effort |
+| [Recall](/docs/concepts/observability/recall) | Queryable history of invocations, statements, SQL, audit results, and output, locally or in ClickHouse | Troubleshooting history; best effort |
+| `stdout.log` / `stderr.log` | Exact host-local process output (compute log files) | Troubleshooting transcript; also stored by Recall |
 | `CommandOutputRecord` | Bounded, ANSI-free remote stdout/stderr chunks | Potentially sensitive and lossy troubleshooting data |
 | Final JSON output | End-of-command aggregate | Result projection, not event history |
 
 Human-readable CLI output remains the normal operator interface. Structured records are a separate
 contract for integrations and durable consumers.
 
+## Which to use
+
+| You want to | Use |
+|-------------|-----|
+| Find out what a past run did: what ran, its SQL, audit results, errors and output | [Recall](/docs/concepts/observability/recall) and [`sqb recall`](/docs/cli/recall) |
+| Send events or output to your own systems, such as a message queue or a monitoring tool | [Typed sinks](/docs/concepts/observability/sinks) |
+| Store lifecycle events and query run state from your own Python application | [Execution history](/docs/concepts/observability/execution-history) |
+| Read the result of the command you just ran | Its final `--json` output |
+
+Recall is on by default and covers investigation for people and agents. Sinks and execution history
+are for building on SQLBuild's events elsewhere. The `stdout.log`, `stderr.log` and
+`diagnostics.jsonl` compute log files under `logs//` are still written alongside Recall and
+hold the same bytes; prefer `sqb recall output`, which works the same with a shared store.
+
 ## Lifecycle envelope
 
 New events use lifecycle schema version 2:
diff --git a/website/src/content/docs/docs/concepts/observability/execution-history.mdx b/website/src/content/docs/docs/concepts/observability/execution-history.mdx
index 6291fdd6c8..95dcb01931 100644
--- a/website/src/content/docs/docs/concepts/observability/execution-history.mdx
+++ b/website/src/content/docs/docs/concepts/observability/execution-history.mdx
@@ -8,6 +8,10 @@ published, rebuildable run projection. Diagnostic and compute logs are never acc
 contract. The public types, filters, pages, records, errors, and helper functions are exported from
 `sqlbuild.execution_history`.
 
+This is a Python API for applications that store and serve SQLBuild events themselves. To look into
+what past runs did, use [Recall](/docs/concepts/observability/recall), which records every command
+automatically and is queried with [`sqb recall`](/docs/cli/recall).
+
 ## Public contracts
 
 `LifecycleEventLogStorage` provides `append_event`, `append_events`, `get_events`, `get_schema_version`,
diff --git a/website/src/content/docs/docs/concepts/observability/recall.mdx b/website/src/content/docs/docs/concepts/observability/recall.mdx
index 69a1328e64..d0ac97d210 100644
--- a/website/src/content/docs/docs/concepts/observability/recall.mdx
+++ b/website/src/content/docs/docs/concepts/observability/recall.mdx
@@ -7,6 +7,64 @@ Recall records each `sqb` invocation in a local SQLite store, or in a shared
 [ClickHouse store](#sharing-history-in-clickhouse), so you can ask what happened after the fact: which command ran, how it ended, which statements it executed and how long they took, and
 exactly what it printed. Recall is on by default and needs no setup.
 
+## An investigation, start to finish
+
+The waffle shop example's `daily_revenue` model has an audit, `revenue_is_non_negative`, at warn
+severity. One night the payments feed starts recording a refund as a negative payment. The unit tests
+still pass, because they run on mocked data. The build finishes with a warning that nobody reads.
+
+The next morning, ask when the audit started failing:
+
+```bash
+sqb recall query --format table \
+  "SELECT invocation_started_at AS run, outcome, violation_count FROM audit_results
+   WHERE audit_name = 'revenue_is_non_negative' ORDER BY run DESC LIMIT 3"
+```
+
+```
+run                         | outcome | violation_count
+--------------------------- | ------- | ---------------
+2026-10-20T00:01:44.784683Z | warn    | 1
+2026-10-20T00:00:34.652468Z | pass    | 0
+2026-10-19T23:59:23.827831Z | pass    | 0
+
+3 rows
+```
+
+See what that run printed, exactly as the scheduler saw it:
+
+```bash
+sqb recall output last --tail 4
+```
+
+```
+  daily_revenue
+    audit revenue_is_non_negative returned 1 row
+
+✓ Completed with warnings  PASS=89  WARN=1  FAIL=0  INSUFFICIENT=0  SKIP=0  TOTAL=90  (3.08s)
+```
+
+Then check what is true in the warehouse now, with the same command:
+
+```bash
+sqb recall query --backend warehouse --format table \
+  "SELECT r.revenue_date, r.total_revenue_cents, p.payment_id, p.amount_cents
+   FROM prod.daily_revenue r JOIN prod.stg_payments p
+     ON CAST(p.paid_at AS DATE) = r.revenue_date
+   WHERE p.amount_cents < 0"
+```
+
+```
+revenue_date | total_revenue_cents | payment_id | amount_cents
+------------ | ------------------- | ---------- | ------------
+2026-04-03   | -1250               | 9          | -2200
+
+1 row
+```
+
+The bad row is still in prod, and payment 9 explains it. A coding agent can follow the same steps:
+every answer is a SQL query over the [views](#querying-history), with the same output in `--json`.
+
 ## What is recorded
 
 For every recorded invocation, Recall keeps:
diff --git a/website/src/content/docs/docs/feature-comparison.mdx b/website/src/content/docs/docs/feature-comparison.mdx
index 01ad2944c0..1ae7e04db1 100644
--- a/website/src/content/docs/docs/feature-comparison.mdx
+++ b/website/src/content/docs/docs/feature-comparison.mdx
@@ -109,11 +109,11 @@ SQLBuild, dbt, and SQLMesh are all SQL pipeline frameworks. They share common gr
 | Feature | SQLBuild | dbt | SQLMesh |
 |---------|----------|-----|---------|
 | Reference syntax | `__ref()` - parses as valid SQL | `{{ ref() }}` - Jinja template | `model_name` with dependency tracking |
-| Adapters | DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server | 30+ (community adapters) | DuckDB, Snowflake, BigQuery, Databricks, Spark, Redshift, Postgres, Trino, MySQL |
+| Adapters | DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server, ClickHouse, SQLite | 30+ (community adapters) | DuckDB, Snowflake, BigQuery, Databricks, Spark, Redshift, Postgres, Trino, MySQL |
 | State requirements | Stateless by default | manifest.json + target/ | Requires state store (local database or PostgreSQL for production) |
 | Playground | `sqb playground` | Clone example repo | Example project |
 | AI agent skills | General guidance with `sqb skills`; Rules guidance with `sqb rules skills` | No | No |
-| Execution observability | Immutable schema-versioned lifecycle facts, invocation-local ordering, orchestration context, and typed project sinks | Events/artifacts plus external observability | Plans, state, and external observability |
+| Execution observability | Recall: every command's statements, SQL, audit results and output, queryable with SQL locally or in ClickHouse; immutable schema-versioned lifecycle facts and typed project sinks | Events/artifacts plus external observability | Plans, state, and external observability |
 
 ## Where each tool fits
 
@@ -125,4 +125,4 @@ SQLBuild, dbt, and SQLMesh are all SQL pipeline frameworks. They share common gr
 
 ## Not yet in SQLBuild
 
-- **Broader adapter support** - ClickHouse, Redshift, Trino, Spark, Athena
+- **Broader adapter support** - Redshift, Trino, Spark, Athena
diff --git a/website/src/content/docs/docs/index.mdx b/website/src/content/docs/docs/index.mdx
index 557da16103..8e68dbb6c4 100644
--- a/website/src/content/docs/docs/index.mdx
+++ b/website/src/content/docs/docs/index.mdx
@@ -42,6 +42,12 @@ updated, a [migration](/docs/concepts/models/migrations) moves its table instead
 history, and the old name keeps working as a view. Columns can be renamed the same way. The
 [janitor](/docs/cli/janitor) archives tables the project no longer builds before it deletes them.
 
+## Investigate
+
+[Recall](/docs/concepts/observability/recall) records every command: what ran, the SQL it executed,
+audit results and everything it printed. Agents and people query that history with SQL through
+[`sqb recall`](/docs/cli/recall), then check live state in the warehouse with the same command.
+
 ## How it fits together
 
 | Step | Command | What it does |
@@ -51,8 +57,10 @@ history, and the old name keeps working as a view. Columns can be renamed the sa
 | Plan | [`sqb plan`](/docs/cli/plan) | Shows what will run, why, and how much it will rebuild |
 | Build | [`sqb build`](/docs/cli/build) | Runs tests, builds models in dependency order, and blocks bad data with audits |
 | Compare | [`sqb diff`](/docs/cli/diff) | Compares schemas and rows between two targets |
+| Investigate | [`sqb recall`](/docs/cli/recall) | Queries the history of past runs, then live warehouse state |
 
-SQLBuild works with DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL and SQL Server.
+SQLBuild works with DuckDB, MotherDuck, Snowflake, BigQuery, Databricks, PostgreSQL, SQL Server,
+ClickHouse and SQLite.
 DuckDB runs locally, so you can try everything without warehouse credentials. See
 [Adapters](/docs/concepts/adapters) for connection setup.
 
diff --git a/website/src/content/docs/docs/roadmap.mdx b/website/src/content/docs/docs/roadmap.mdx
index 691c69a353..915215520d 100644
--- a/website/src/content/docs/docs/roadmap.mdx
+++ b/website/src/content/docs/docs/roadmap.mdx
@@ -18,8 +18,8 @@ A self-hosted web app for your SQLBuild project:
 
 ## Later
 
-- Moving BigQuery, Databricks and SQL Server from beta to supported.
-- More warehouses, such as ClickHouse, Redshift and Trino.
+- Moving BigQuery, ClickHouse, Databricks, SQLite and SQL Server from beta to supported.
+- More warehouses, such as Redshift and Trino.
 
 ## Not planned