title: v0.7.1 — the OpenWebUI v0.11.0 rebase, working chat attachments, and maintenance
description: Release notes for v0.7.1, as recorded in docs/releases/v0.7.1.md.
url: https://legalquants.github.io/lq-ai/changelog/v0-7-1/
checked-against: bc8b639c (2026-08-31)
status: draft
kind: explanation
sources: docs/releases/v0.7.1.md

> **Status: ready for the `v0.7.1` tag.** All four version strings are at `0.7.1` — the three that
> move together for the image tag (`api/app/__init__.py`, `gateway/app/__init__.py`, and
> `info.version` in the committed OpenAPI export), plus `desktop/package.json` and its lockfile for
> the separate `desktop-v0.7.1` cut that follows it. See *Release readiness*.

This is a **patch release**. Nothing in it requires an operator to touch a working install, which is
what makes it a patch under ADR 0025 rather than a minor. Its bulk is the quarterly `web/`
vendor-fork refresh: the OpenWebUI fork moves from upstream **v0.9.2 to v0.11.0**, the first refresh
executed under the rebase runbook that ADR 0001 had asked for and never had. It also completes the
already-contracted chat-attachment path in the web client: attached files now reach the model and
show their ingestion state. The rest is dependency hygiene, release hardening, test cleanup, and a
governance decision reaching ratification.

The through-line is **deferred plumbing made operational**: the fork was 1402 commits behind, the
runbook did not exist, Dependabot was fighting the fork rather than serving it, and the web composer
displayed attached files without sending their IDs. All four are addressed here.

---

## Headline — the `web/` fork moves to OpenWebUI v0.11.0 (#541)

The vendored OpenWebUI fork is rebased from **v0.9.2 to v0.11.0**, the quarterly refresh ADR 0001
mandates. **879 files changed, +187,454/−97,181** — every changed path under `web/` except a single
added line in `docs/adr/0001-openwebui-fork-pin.md`. That containment is the point: our LQ.AI code
has no imports into upstream's tree, so the refresh does not reach the api, the gateway, or the
skills corpus. *(#541)*

It landed alongside the procedure that makes the next one repeatable:

- **The fork rebase runbook** (`docs/openwebui-rebase-runbook.md`, 699 lines) — written against an
  actual merge dry-run rather than inferred, so it records what the inference got wrong. Its central
  correction: the documented `git merge v0.11.0` cannot work (`refusing to merge unrelated
  histories`), and `--allow-unrelated-histories` is worse — it stages upstream's tree at the repo
  root. The working procedure synthesises both upstream endpoints as `web/`-prefixed trees.
  *(#539)*
- **`web/` Dependabot is scoped to security updates only.** The fork tracks upstream; a Dependabot
  PR bumping a package upstream also bumps is a merge conflict waiting to happen. Version updates
  are off, security updates stay on. *(#542)*

**What the rebase carries that no conflict marker announced:** 15 new Alembic migrations, and the
deletion of the 18-file legacy peewee migrations directory upstream removed. See *Schema*.

---

## Chat attachments now reach the model (#402)

The web composer now sends attached `file_ids` with each chat message and polls uploads until they
reach a terminal ingestion state. Status chips move from `pending` to `ready` or `failed`; failed
files are excluded from the outgoing message; and uploads, polling, and draft attachment state are
cancelled or reset when the user switches chats. The client also enforces the backend's 16-file
limit before send, with an inline explanation instead of a late 422 response. This completes the
client half of the existing PRD §3.1 contract; the backend validation and context injection were
already present. Frontend-only, with no schema, migration, configuration, or operator step. *(#402)*

---

## Supply-chain & dependency maintenance

- **Dependency group bumps** across `api/` and `gateway/` — the api-minor-patch group twice (8
  updates, then 4) and the gateway-minor-patch group twice (6 updates, then 4), covering
  `pydantic-settings`, `starlette`, `alembic`, `greenlet`, `pymupdf`, `tiktoken`, `spacy`, `ruff`,
  and `mypy`. *(#550, #543, #513, #500)*
- **`cryptography` 49.0.0 → 50.0.0** in the gateway, clearing a published advisory on the superseded
  version. *(#516)*
- **`starlette`'s gateway upper bound lifted to `<1.5`**, paired with the api-side group bump so the
  two services resolve the same major. *(#514, #513)*
- **`uvicorn[standard]`** requirement updated in both api and gateway. *(#522, #517)*
- **`sqlalchemy[asyncio]`** requirement updated in the api. *(#484)*
- **`pymdown-extensions` → 11.0.2** in the web fork. *(#538)*
- **`docker/login-action`** bumped in the release workflow. *(#478)*
- **`langgraph` excluded from the api-minor-patch Dependabot group**, so a framework with its own
  upgrade cadence stops riding in on a routine group PR. *(#546)*

---

## Correctness & governance

- **ADR 0026 ratified — Docling removed from near-term scope, the pluggable parser interface
  deferred.** Confirmed by the committee at the 2026-08-23 call and flipped from Proposed to
  Accepted. The ADR also records something that cuts against its own case: the Flosters/lq-ai fork
  ("LegVolution", an Argentine production deployment) repaired the Docling call site against the
  real 1.x API and runs it for scanned-PDF OCR. One operator does use Docling. That is recorded
  because the removal case leaned on Docling having never produced output, and the record should say
  so — it does not change the decision, since that operator had to fork the parser call site to get
  what an adapter seam would have handed them by configuration. **DE-387** gains the fork as a
  working reference implementation. *(#528)*
- **The AG-01 retrieval-ownership closure is recorded** across `HONEST-STATE.md`, `PRD.md`, and
  `autonomous-layer.md`, so the audit finding's closure is documented where readers look rather than
  only in the PR that closed it. *(#496)*
- **The documented contributor workflow now matches the checks that actually run.** `CONTRIBUTING.md`,
  the `Makefile`, `CLAUDE.md`, and the coding-agent onboarding guide are reconciled against the real
  gates — +140/−108 across four files. A contributor following the docs now runs what CI runs. *(#505)*
- **Release-range detection now ignores unreachable vendor tags.** Both the runbook and
  `release.yml` choose the previous release only from tags reachable from the commit being released,
  so OpenWebUI's own `v0.9.2` and `v0.11.0` tags can no longer turn the release range into 737 commits
  of unrelated upstream history. *(#552)*
- **Gateway tests share one example-environment fixture.** The remaining issue-scoped copies were
  consolidated into `gateway/tests/conftest.py`, preserving test-specific overrides while removing
  five local definitions and the drift between them. Test cleanup only; runtime behaviour is
  unchanged. *(#527)*

---

## Documentation & deployment

- **A tailnet-hosted Ollama deployment recipe** (`deploy/tailnet-ollama/README.md`, 174 lines) — how
  to point the gateway at an Ollama instance reachable only over a tailnet, keeping model inference
  on infrastructure the operator controls. *(#510)*

---

## Fixes

- **gateway:** the config test fixture pins the remaining example environment variables, closing the
  last ambient-environment leak that let a developer's shell change test behaviour. This finishes
  the job #443 started in `v0.7.0`. *(#497)*

---

## Who built this release

**Two people landed their first commit on `main` in this range.**

| Contributor | What they landed |
|---|---|
| [@Bhoomi-jain](https://github.com/Bhoomi-jain) | four PRs — the AG-01 closure record *(#496)*, the gateway config-fixture pin and shared-fixture cleanup *(#497, #527)*, and the tailnet-Ollama deployment recipe *(#510)* |
| [@katsugtgz](https://github.com/katsugtgz) | the `pymdown-extensions` bump in the web fork *(#538)* |

**And two came back.** [@pscripps](https://github.com/pscripps), whose markdown-upload work landed
in #206 back in June, returned to reconcile the contributor workflow with the checks that actually
run *(#505)*. [@SaifAlYounan](https://github.com/SaifAlYounan), who contributed release hardening and
security fixes before `v0.7.0`, completed the web client's chat-attachment path *(#402)*.

The rest is maintainer work (@houfu) and Dependabot. Four human contributors on this patch, two of
them new, continues the widening `v0.7.0` recorded.

---

## Schema

**No LQ.AI schema change.** The api's Alembic head is unchanged at **0066**
(`0066_backfill_project_knowledge_bases`), the same head `v0.7.0` shipped.

**The `web/` fork gains 15 Alembic migrations** from the upstream rebase, and loses the 18-file
legacy peewee `internal/migrations/` directory that upstream deleted. These are OpenWebUI's own
migrations against the OpenWebUI database, not ours. **They apply automatically** — `web`'s
`config.py` calls `command.upgrade(alembic_cfg, "head")` at startup — so there is **no operator
step**, which is what keeps this release a patch.

That is not the same as saying the upgrade is inert. One of the fifteen
(`461111b60977_add_missing_primary_keys_to_legacy_*`) adds missing primary keys to legacy tables,
which rewrites existing rows on first boot after the upgrade. An operator with a long-lived web
database should expect the first `web` container start on `v0.7.1` to take longer than usual, and
should have a backup, as they should before any migrating upgrade.

---

## Version

Per **ADR 0025 decision 1**, `api`, `gateway`, `web`, and `proxy` share one release version — the
image tag. This release moves **`api` and `gateway` `__version__` → `0.7.1`**.
`web/package.json` now reads **`0.11.0`**, tracking the OpenWebUI fork per ADR 0001 — it is not
retitled to the release version, and the rebase is why the number moved.

**Three strings, not two.** The api version is also stamped into the committed OpenAPI export
(`docs/api/backend-openapi.generated.yaml` → `info.version`, currently `0.7.0`), so the bump needs a
`make openapi` regeneration; `test_generated_openapi_export_is_current`
(`api/tests/test_openapi_export.py:31`) fails otherwise. `v0.7.0` recorded this as a follow-up; it
is not in the release checklist yet.

Per **ADR 0025 decision 3**, this is a **patch**. Reading the 24 merged PRs against the standard —
does a working install need a human to touch it after this upgrade? — nothing qualifies. No PR in
the range carries the `breaking-change` label, and the three that do in project history (#396, #399,
#400) all shipped in `v0.7.0`. #402 completes an existing client contract without changing backend
configuration or requiring a migration, so it does not change that decision. The number is computed
from what accumulated on `main`, not chosen from a milestone.

**The desktop launcher versions independently.** Per **ADR 0025 decision 2** it carries its own
`desktop-vX.Y.Z` tag and records the image set it ships against, so `desktop/package.json` moves
`0.7.0 → 0.7.1` and `desktop-v0.7.1` is cut **after** the `v0.7.1` image set is published and
verified — the launcher pulls those images, so the order is not interchangeable. Nothing in this
range touched `desktop/`; the launcher is re-cut to ship against the new image set, not because its
own code changed.

---

## Honest scope — what did *not* ship

- **The remainder of the #288 audit stays open.** No audit finding is closed in this release. Still
  outstanding: **Medium** — GW-02, GW-03, API-02, API-03, AG-02, D-02, E-05; **Low** — GW-05, AG-03,
  AG-04, D-03, E-03, the E-02 remainder (signing + `packages:write` still in the release job), E-04,
  E-06; **Info** — GW-06.
- **A fresh desktop install does not pin this image set.** The launcher still ships
  `imageTag: 'latest'` (`desktop/src/main/index.ts`), so a new install runs the newest published
  images rather than the `v0.7.1` set the `.dmg` was built against. ADR 0025 decision 2 asks for the
  opposite; changing the default is tracked with that work and does not land here. Pin
  `LQ_AI_IMAGE_TAG` in `.env` for a reproducible hand-run stack.
- **The macOS build is Apple-silicon only.** `desktop-release.yml` runs on `macos-14` and
  `electron-builder.yml` names no `arch` list, so the release publishes a single
  `LQ.AI-0.7.1-arm64.dmg`. Intel Macs are not served by the launcher.
- **Chat attachments are per-page draft state.** #402 resets attachments safely when switching
  chats, but it does not restore them after a page reload. Persisting attachment state and replacing
  the two older route-specific polling loops remain follow-up work.

---

## Release readiness

**Unblocked.** The version bump is prepared and the pre-flight below is satisfied.

**Pre-flight, already satisfied:**
- `api` and `gateway` `__version__` are both `0.7.1`.
- `info.version` in the committed OpenAPI export is `0.7.1`, regenerated with `make openapi`;
  `test_generated_openapi_export_is_current` passes.
- `desktop/package.json` and `desktop/package-lock.json` are both `0.7.1`, resynced with no
  dependency churn.
- No `breaking-change`-labelled PR merged since `v0.7.0`, so neither `[allow-version-drift]` nor
  `[allow-breaking-in-patch]` is needed.

**Gates:** api `ruff`/`mypy` + pytest; gateway `ruff`/`mypy --strict` + pytest; web `check:lq-ai` +
vitest; the stack-boot smoke; and the `version-consistency` job (api == gateway == tag).

**Steps (maintainer):**
1. Merge the version bump to `legalquants/main`.
2. Tag `v0.7.1` (annotated) on the merge commit and push it to `legalquants` — the Release workflow
   builds and signs the images and attaches the SBOM.
3. Verify all published images carry the tag before going further (ADR 0025 decision 4 gates backend
   before frontend, but the intra-stage guarantee is partial).
4. **Then cut the launcher.** Tag `desktop-v0.7.1` and push it; `desktop-release.yml` runs on
   `macos-14` and needs the five Apple signing secrets, all of which are set and working. Record the
   `v0.7.1` image set it ships against (ADR 0025 decision 2). The order is not interchangeable — the
   launcher pulls the images, so they must be published and verified first.
5. **Verify the published `.dmg`, not the CI exit code.** The runbook records that a watch command
   can report success on a failed run, so read the run's `conclusion` field and then check the
   artifact itself — download the `.dmg` from the release and run `spctl -a -vvv -t open --context
   context:primary-signature` and `xcrun stapler validate` over it. Expect `accepted` /
   `source=Notarized Developer ID` / `Developer ID Application: Tucuxi, Inc. (MC8BT9Z8GD)`, and
   "The validate action worked!" from `stapler`. A stapled-but-unsigned `.dmg` still fails
   Gatekeeper; both signature and staple are required.

---

## Follow-ups this release surfaced

- **The OpenAPI regeneration step is worth adding to the release checklist.** Bumping `api`
  `__version__` also requires `make openapi`, and `docs/BUILD-AND-RELEASE.md` does not yet say so.
  It is one line.
- **The runbook's Apple-signing table is out of date.** `docs/BUILD-AND-RELEASE.md` still marks three
  of the five signing secrets "⏳ pending", written before the first successful cut and never
  updated. All five are working — `desktop-release.yml` has published a signed, notarized `.dmg` on
  every run through `desktop-v0.7.0`. A corrected runbook is drafted and not yet merged.

---

*Drafted from the `v0.7.0..main` range on 2026-08-31 — 24 merged PRs, canon SHA `e3625cce3`,
tag base `623a3b3f7`. Every commit in the range was reconciled against GitHub's merged-PR state;
four (#402, #514, #528, #539) lost their `(#N)` suffix in squash and were matched through their merge
commits. Version numbering per ADR 0025. Schema claims verified against the Alembic heads and
`web/backend/open_webui/config.py`; contributor first-commit claims verified against `git log main`.*

## Next

- [Upgrade](/lq-ai/operate/upgrade/) — the runbook for taking this release.
- [Release versioning](/lq-ai/reference/versioning/) — what a patch and a minor each commit to.
- [All release notes](/lq-ai/changelog/) — every tag, and which have notes.
