Releases: DeepSQLAI/deepsql-self-host
v1.3.7 — telemetry: interval rename, real services_up, flat source/dialect rollups
Bumps self-host images to 1.3.1. Three telemetry improvements, all live-verified on a real Amazon Linux 2023 / Docker stack before release.
What's new (dba-agent v1.3.1 images)
Honest rollup naming: queries_24h_* -> queries_interval_*
The heartbeat rollups are per-heartbeat deltas (activity since the last heartbeat), not 24h totals. Renamed to say so. Sum across heartbeats for a range total (PostHog SUM aggregation).
Real services_up probes
services_up previously hardcoded ["backend"]. It now probes each dependency every heartbeat: backend (self), postgres (vault connection valid), valkey (Redis PONG), frontend (in-network HTTP). Verified live: ["backend","postgres","valkey","frontend"] + frontend_reachable: true. Each probe is independently guarded and 2s-bounded.
Flattened source/dialect breakdowns
queries_interval_by_source / _by_dialect were nested JSON objects (required HogQL to chart). Replaced with flat, stable, 0-filled integer props:
queries_interval_source_{ui,chat,mcp,scheduled,api,internal,unknown}queries_interval_dialect_{postgres,mysql,unknown}
Now every breakdown is a drag-and-drop Sum in PostHog Trends — no HogQL. Verified live: source_ui=3, source_mcp=2, dialect_postgres=5.
PostHog: per-install query dashboard
Trends -> event install.heartbeat -> series = Sum of queries_interval_source_ui (one per source) -> break down by install_id. No SQL.
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
v1.3.6 — bootstrap integrity guards (download/extract/exec) + ASCII install.sh
Same images as v1.3.0. Hardens the curl-pipe-bash bootstrap against the failure mode behind a customer 'xrealloc: cannot allocate 18446744071562068080 bytes' crash, and confirms the v1.3.5 telemetry-promotion fix on the real environment.
Investigation summary
Reproduced the customer's exact environment on a throwaway EC2 instance — Amazon Linux 2023 arm64, bash 5.2.15, LANG=C.UTF-8 — and ran fresh-install, install-with-Docker, and full upgrade-with-existing-volumes. None crashed. The non-ASCII v1.3.3 script ran fine, disproving the locale/encoding theory. The crash fires right after 'Installing files into ...' (the extract-then-exec boundary) and is non-deterministic — the signature of a truncated download or broken-pipe partial copy producing a corrupt install.sh that exec then runs as garbage.
Bootstrap integrity guards
gzip -tintegrity check on the downloaded archive (curl exits 0 even on a short read of a 200; this catches the truncation).- Replaced the
tar -cf - . | tar -xf -copy withcp -R, which has no silent-truncation-on-SIGPIPE failure mode on constrained hosts. bash -nparse-check of the installed script beforeexec. Never exec a script we cannot parse — turns the opaque xrealloc crash into a clear 'copy may be corrupt, remove dir and re-run' message.
Verified on the real VM: the negative test confirms gzip -t rejects a corrupt archive; a clean upgrade passes all three guards and exec's normally.
Also in this release (confirmed on the real VM)
- Telemetry promotion now actually runs on upgrade (the v1.3.5 fix): observed
> Promoting DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY from release default— this is the real fix for 'no PostHog key after upgrade'. - install.sh is pure ASCII (portability hygiene).
- Canonical
deepsql-selfhostproject name + absolute volumes + one-shot legacy-volume migration, all exercised end-to-end with data preserved.
Upgrade
curl -fsSL https://install.deepsql.ai/install.sh | bash
v1.3.5 — telemetry promotion actually works on upgrade (+ data-safe migration)
Same images as v1.3.0. Fixes the bug that left customers with no PostHog key after upgrade, plus a data-safety hardening of the volume migration. Validated by a new end-to-end reproduction test.
THE fix — telemetry promotion never ran on real upgrades
bump_image_pins_from_release read .env values with a naive command
substitution:
current="$(grep -E "^${var}=" "$ENV_FILE" | head -1 | cut -d= -f2-)"
Under set -euo pipefail, when grep finds no match it exits 1, pipefail
propagates it, and a failing command substitution in an assignment makes
set -e abort the entire installer — silently, before any output. The
keys being promoted (DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY,
DEEPSQL_RELEASE) are by definition absent from the .env being promoted
into, so the very first lookup killed the installer every time. Fresh
installs were unaffected (their .env is copied wholesale from .env.example,
so the key is present). Net effect: the telemetry promotion shipped in
v1.3.2 never actually executed on any real upgrade — this is why upgraded
installs had no PostHog key.
Fixed via an env_value_for helper that tolerates no-match.
Data-safety hardening — scoped volume migration
The v1.3.3 migration searched for ANY *_dba-agent-postgres volume and
picked the largest. On a host with multiple deepsql-related Compose
projects, that could copy an unrelated stack's data into the canonical
volume. Migration now only considers volumes prefixed with the canonical
project name (deepsql-selfhost) or the install dir's basename — the only
two names our stack has ever used. The obsolete greedy
adopt_existing_project_name (a pre-v1.3.4 stopgap) is removed.
New: reproduction + regression test
scripts/test-upgrade-drift.sh reproduces the whole drift + missing-key
upgrade scenario on a throwaway host and asserts data survival + canonical
naming. Run it before any future install.sh release:
./scripts/test-upgrade-drift.sh
Result on a clean run: 11/11 assertions PASS — data preserved, absolute
volume created, legacy volume kept as a safety net, canonical project name
in use, telemetry key promoted.
Upgrade
curl -fsSL https://install.deepsql.ai/install.sh | bash
v1.3.4 — pin Compose project name (closes container/volume drift permanently)
Same images as v1.3.0. The permanent fix for the upgrade-time container/volume drift that produced data-loss scares in v1.3.0–1.3.3.
Root cause
Docker Compose resolves the project name in this priority order:
- `--project-name` / `-p` flag
- `COMPOSE_PROJECT_NAME` env var
- `name:` top-level field in docker-compose.yml
- Lowercased directory basename (fallback)
`docker-compose.yml` previously declared no `name:`, so anything that ran `docker compose` without `--project-name` fell through to layer 4 — the install directory's basename, `self-host`. install.sh always passed `--project-name deepsql-selfhost`, but that's a per-invocation override that doesn't propagate to:
- manual `docker compose ps/up/down` run while debugging
- cron jobs or systemd units pointing at the compose file
- AI agents (Claude/Codex) running `docker compose` from the install dir
Each of those silently created a parallel `self-host` stack with its own empty volumes — which looked like data loss on upgrade.
Fix — make the project name a shared agreement, not a flag
1. `name: deepsql-selfhost` in docker-compose.yml
The file-level name beats the dir-basename fallback for every invocation from anywhere. A deliberate `--project-name` still wins (intentional override), but accidents can't leak in.
2. install.sh hardcodes the project name
`PROJECT_NAME=deepsql-selfhost` is no longer read from `${DEEPSQL_PROJECT_NAME:-...}`, so a leaked env var can't start the drift chain. To run a differently-named stack on purpose, pass `--project-name` to docker compose directly.
Combined with v1.3.3
v1.3.3 pinned absolute volume names (`name: dba-agent-postgres` etc.) and added one-shot migration from legacy prefixed volumes. v1.3.4 pins the project name. Together they close the drift class at both layers — containers and volumes both stay stable across upgrades regardless of working directory, env, or who's driving docker compose.
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
Existing installs: the upgrade detects your running `deepsql-selfhost` stack, the new compose-file name agrees, and containers continue in place. If you were stuck on a `self-host`-named stack from a prior drift, v1.3.2's project-name adoption + v1.3.3's volume migration bring you back onto the canonical names.
v1.3.3 — absolute volume names + auto-migration (prevents data-loss scare on upgrade)
Same images as v1.3.0. Important upgrade for any v1.2.x or v1.3.0/1/2 install — fixes a customer-facing data-loss scare that came out of a real upgrade today.
What happened
`docker-compose.yml` declared volumes with relative names (`dba-agent-postgres` etc), which Compose automatically prefixes with the project name. If anything leaked `DEEPSQL_PROJECT_NAME=
` into the shell environment (or the upgrade ran from a directory whose basename Docker auto-derived as the project), Compose would silently create a parallel set of EMPTY volumes alongside the original ones. The new containers mounted the empty volumes. Result: 8 days of customer data appeared wiped, when it was actually still on disk under the legacy prefixed volume name.What v1.3.3 does
Absolute volume names
`docker-compose.yml` now declares:
```yaml
volumes:
dba-agent-postgres:
name: dba-agent-postgres
dba-agent-valkey:
name: dba-agent-valkey
dba-agent-logs:
name: dba-agent-logs
```
The `name:` field pins the on-disk volume name regardless of project name. Future project-name drift can't separate containers from their data.
One-shot migration from legacy prefixed volumes
`migrate_prefixed_volumes_if_needed` runs before `compose up` and:
- For each absolute volume (`dba-agent-postgres`, `dba-agent-valkey`, `dba-agent-logs`), checks if it already exists.
- If not, finds the largest matching prefixed volume (`*_dba-agent-postgres` etc.) — "largest" picks the one with real data when multiple parallel projects exist.
- Tar-copies the contents into the new absolute volume.
- Leaves the original prefixed volume untouched as a rollback safety net.
You'll see output like:
```
▸ Migrating volume data: deepsql-selfhost_dba-agent-postgres → dba-agent-postgres
(old volume preserved untouched as a rollback safety net)
✓ dba-agent-postgres now mirrors deepsql-selfhost_dba-agent-postgres
```
Rollback if anything looks wrong
The old prefixed volumes are not deleted — drop the new absolute volumes and revert to the prior install.sh via:
```bash
docker volume rm dba-agent-postgres dba-agent-valkey dba-agent-logs
```
Then bring up the old stack manually with whatever project name the prefixed volumes use.
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
v1.3.2 — adopt existing project name + verbose promotion logs
Same images as v1.3.0. Two install.sh fixes from a real customer upgrade today.
Adopt existing Compose project name on upgrade
If a customer's environment leaks `DEEPSQL_PROJECT_NAME=` into the shell (e.g., debugging session, prior install with a different default, or just an exported var from somewhere), install.sh used to silently create a parallel stack under that name instead of upgrading the existing `deepsql-selfhost` stack. The new stack and the old one then fought for host ports.
`adopt_existing_project_name` pre-flight now scans for running DeepSQL containers and adopts their Compose project name if it differs from the default. You'll see:
```
▸ Existing DeepSQL stack found under Compose project 'deepsql-selfhost'
(default would have been 'self-host'). Adopting the existing name so this
upgrade updates those containers in place.
```
Verbose promotion logging
`bump_image_pins_from_release` silently skipped promotions when keys were already set, making post-upgrade debugging painful when someone wondered why their .env didn't have the telemetry key. It now prints a one-liner per key:
```
▸ DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY: already set in .env, leaving alone
▸ Promoting DEEPSQL_RELEASE from release default
```
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
v1.3.1 — robust default-telemetry rollout
Same images as v1.3.0. Self-host installer changes only — makes the default-on anonymous telemetry actually work for existing customers and adds two upgrade-robustness fixes that surfaced in a customer-VM test run.
Changes
Anonymous telemetry on by default
`.env.example` ships with `DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY` set to DeepSQL's PostHog project ingest key (write-only, safe to publish — same model as Sentry DSNs). Fresh installs get telemetry immediately.
Existing installs get the key on upgrade
`bump_image_pins_from_release` now also promotes `DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY` and `DEEPSQL_RELEASE` from `.env.example` to existing `.env` files when the customer hasn't set their own value. Customer overrides are preserved verbatim.
Partial-success trap
If `install.sh` exits non-zero after bumping image pins but before `docker compose up` swaps containers, an EXIT trap now prints the precise recovery command instead of leaving the customer with mismatched .env and running images.
Stale-stack detection
Pre-flight check that surfaces any deepsql containers running under a Compose project name other than `deepsql-selfhost` (typically from manual debugging or a prior install with a custom `DEEPSQL_PROJECT_NAME`). Host port bindings from those orphan stacks would otherwise cause `up -d` to fail with port-already-allocated. The check prints the exact `docker compose -p '' down --remove-orphans` command — never auto-stops, to preserve data.
Opt-out (unchanged)
```bash
DO_NOT_TRACK=1
or
DEEPSQL_TELEMETRY_DISABLED=1
```
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
v1.3.0 — Phase-2.5 query/brain/slow-query telemetry
Bumps self-host images to 1.3.0 and adds Phase-2.5 anonymous telemetry counters on top of Phase-1's install identity.
What's new
- Query executions counted per call to
QueryExecutorService.executeQuery, tagged bysource(chat/ui/mcp/scheduled/api/internal) anddialect(postgres/mysql). - Brain (RAG) retrievals counted via a
@PrimarySpring AIVectorStoredecorator — single seam, no per-tier breakdown yet. - Slow-query ingestion runs emit one new event per scheduled poll:
slow_query.ingestion_run.completedwithdialect,rows_ingested,run_duration_ms,success. - install.heartbeat now carries 5 rollup properties (
queries_24h_total,queries_24h_by_source,queries_24h_by_dialect,brain_retrievals_24h_total,slow_query_ingestion_runs_24h) computed as deltas from cumulative Micrometer counters.
Privacy
Same Phase-1 guarantees: opt-in via DEEPSQL_TELEMETRY_POSTHOG_PROJECT_KEY, hard-disabled via DO_NOT_TRACK=1 or DEEPSQL_TELEMETRY_DISABLED=1. No SQL text, no schema names, no PII — only enum tags + counts.
Upgrade
```bash
curl -fsSL https://install.deepsql.ai/install.sh | bash
```
The installer detects an existing install, preserves your `.env` (secrets + admin creds), bumps the image pins to 1.3.0, and `docker compose up -d` swaps the running containers.
Image digests
`ghcr.io/deepsqlai/deepsql-self-host-backend:1.3.0`
`ghcr.io/deepsqlai/deepsql-self-host-frontend:1.3.0`
v1.2.4 — robust no-TTY gate
Patch on v1.2.3. company-name prompt now uses the same has_tty() check that read_tty does internally, so curl|bash reliably skips it.
v1.2.3 — fix curl|bash regression
Patch on v1.2.2. The optional company-name prompt now silently skips when there is no TTY (i.e. when invoked via 'curl | bash').