Skip to content

v0.9.0

Latest

Choose a tag to compare

@github-actions github-actions released this 30 Jul 14:54

Upgrade notes

Breaking changes

Re-fetch docker-compose.yml — the database image changed

This release adds Knowledge Base agents, whose search index is built on the pgvector Postgres extension. The database migrations enable that extension on startup, and the stock postgres:17 image doesn't ship it — so the db service now uses pgvector/pgvector:pg17-trixie instead.

If you keep your old `docker-compose.yml`, the migration fails with `extension "vector" is not available` and Pinchy restart-loops without serving anything — migrations run on boot, so a failed one takes the whole app down, not just the Knowledge Base. Nothing is lost when this happens: fetch the new compose file and start again, and the migration picks up where it left off.

Re-fetch the compose file before pulling images:

cd /opt/pinchy
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.9.0/docker-compose.yml -o docker-compose.yml
sed -i 's/^PINCHY_VERSION=.*/PINCHY_VERSION=v0.9.0/' .env
docker compose pull && docker compose up -d && docker image prune -f

Your data is safe across the image swap: it's the same PostgreSQL 17 on the same Debian base, reading the same pgdata volume in place — only the pgvector library is added. Both images are larger this release (the agent runtime now bundles an offline embedding model), so expect a bigger pull; the docker image prune -f from the standard flow keeps disk in check.

**If you edited `docker-compose.yml` to [mount data directories](/guides/mount-data-directories/)**, re-apply those `volumes:` lines after re-fetching — the download overwrites them. Keeping custom mounts in a `docker-compose.override.yml` instead makes future upgrades hands-off. **If you run your own PostgreSQL** instead of the bundled `db` service, install the [pgvector](https://github.com/pgvector/pgvector) extension on that server before upgrading — the migration runs `CREATE EXTENSION IF NOT EXISTS vector` and needs both the extension files and a role allowed to create it.

Upgrade notes

First boot may take longer on installations with a lot of history

The migrations build new indexes over your audit log and usage records. On an instance with months of history this can take a few minutes, during which Pinchy reports "unhealthy". If docker compose up -d gives up waiting and the openclaw service doesn't start ("dependency failed to start"), wait for docker compose logs pinchy to show the server starting, then run docker compose up -d once more.

Container resource limits are now set by default

The compose file now caps each service (pinchy 1 GB, openclaw 2 GB, db 1 GB memory, plus CPU limits) so one runaway container can't take down the host. Deployments that routinely needed more will see the container restarted by the kernel instead. Every limit is overridable in .env — see Customizing your deployment. After upgrading, docker inspect --format '{{.State.OOMKilled}}' pinchy-openclaw-1 (and the other containers) tells you whether a limit is too tight for your workload.

Knowledge Base agents (new, opt-in)

Agents can now answer from your own documents with cited sources, backed by a search index in Pinchy's Postgres. Nothing is indexed until you set it up: mount document directories, pull the embedding model on your local Ollama (ollama pull bge-m3), create an agent from the new Knowledge Base template, and trigger indexing. See Create a Knowledge Base agent. If you don't use it, nothing changes for you.

Agent memory recall now works offline

The agent runtime image bundles a local embedding model, so agents' memory search works on every install — including fully offline ones — with no API key. Installs where memory recall silently returned nothing will notice agents actually remembering things. The memory index rebuilds automatically in the background after the upgrade; brief extra CPU on the openclaw container in the first minutes is expected.

Shared agents no longer bring private memory into group chats

A shared agent's MEMORY.md — what it learned in one-to-one conversations — is no longer injected into Telegram group sessions, so notes from private chats can't surface in front of a group. Shared agents may appear to "know less" in groups; that's the privacy fix working.

Old channel attachments are cleaned up after 48 hours

Inbound channel media (Telegram photos, documents) is now copied into the agent workspace on arrival, and the runtime's internal media cache is swept after 48 hours instead of growing forever. Attachments received before this upgrade were never copied, so ones older than 48 hours are removed by the first sweep and may no longer open from old conversations. Export anything you still need from pre-upgrade chats before upgrading.

Workspace terminals stay disabled

The OpenClaw runtime this release ships (2026.7.1) adds an interactive terminal into agent workspaces. Pinchy pins it off: a shell would bypass agent permission allow-lists and the audit trail. It will return as an RBAC-scoped, audited feature.

Database migrations

Eleven additive migrations (00440054) run automatically on startup — no manual steps. No data is dropped or destructively rewritten; existing rows already satisfy every new constraint.

  • 0044 — schema hardening: four timestamp columns to NOT NULL, foreign-key and hot-path composite indexes, CHECK constraints on the enum-like text columns (roles, agent visibility, invite/connection types and statuses), and the invites.claimed_by_user_id foreign key switched to ON DELETE SET NULL.
  • 0045 — per-agent starter prompts (agents.starter_prompts, defaults to empty).
  • 0046, 0048 — GDPR crypto-erasure groundwork: a pseudonymized actor ID on user (backfilled, then defaulted and made UNIQUE/NOT NULL) plus the audit_verify_state table backing periodic incremental chain verification.
  • 0047 — audit-log TRUNCATE guard (statement-level trigger) closing the row-trigger gap.
  • 00490051 — tables and constraints for email inbox workflows (foundation; no runtime surface in this release).
  • 0052 — notifications / activity-feed tables (foundation; no runtime surface in this release).
  • 0053 — per-turn context-window usage tracking (usage_records.context_tokens).
  • 0054 — Knowledge Base tables (kb_documents, kb_chunks) with the pgvector index; enables the vector extension (see the breaking change above).

What's Changed

  • fix(telegram): stop the poller promptly on disconnect via config.apply (#476 gap 1) by @clemenshelm in #674
  • feat(telegram): per-agent disconnect + channel_links cleanup (#476 gaps 2+3) by @clemenshelm in #628
  • feat(pinchy-odoo): resolve nested m2o fields inside one2many command tuples (#615) by @clemenshelm in #627
  • feat(chat): quiet AI assistant disclosure label in chat header (#115) by @clemenshelm in #625
  • feat(ops): production hardening — graceful shutdown, DB pool, Docker limits (#263) by @clemenshelm in #624
  • feat(db): schema hardening — NOT NULL, FK indexes, composite indexes, cascade fix, CHECKs (#259) by @clemenshelm in #622
  • feat(chat): in-composer slash commands /compact /new /reset /help (#611) by @clemenshelm in #618
  • feat(settings): grouped sidebar navigation replacing the overflowing tab bar (#479) by @clemenshelm in #626
  • fix(chat): honest banner + dedicated audit class for generic provider rejection (#584) by @clemenshelm in #675
  • feat(chat): per-agent starter prompts (#570) by @clemenshelm in #620
  • feat(telegram): auto-disable recently-added bots on sustained getUpdates-409 conflict (#477 layer 2) by @clemenshelm in #686
  • feat(telegram): connect-time polling-conflict probe + operator guidance (#477 layer 1) by @clemenshelm in #685
  • perf(usage): adaptive per-session backoff for the usage poller (#261 D) by @clemenshelm in #680
  • feat(chat): cache the per-agent chat list so the switcher isn't empty (#610) by @clemenshelm in #619
  • perf(api): batch telegram-bot + allow-store settings N+1 + cache headers on list endpoints (#261) by @clemenshelm in #623
  • docs(audit): add "how the audit trail works & verify it yourself" deep-dive by @clemenshelm in #692
  • docs(audit): prettier-format audit-trail-verification.mdx (unblock CI on main) by @clemenshelm in #694
  • ci(format): gate docs & workflow formatting on docs PRs, not as code-PR collateral by @clemenshelm in #695
  • feat(pinchy-odoo): governance gating + many2many + read-side line refs for nested command tuples (#615) by @clemenshelm in #693
  • feat(audit): GDPR hardening — active chain verification, actorId pseudonymisation, TRUNCATE guard by @clemenshelm in #691
  • docs(audit): document automatic background chain verification by @clemenshelm in #701
  • chore(deps): workspace dependency sweep (safe patch/minor + paired bumps) by @clemenshelm in #702
  • feat(telegram): mirror inbound media into agent workspace uploads by @clemenshelm in #696
  • feat(email): generic IMAP/SMTP email support by @clemenshelm in #663
  • feat(chat): multi-device live-sync via body-free poke/pull (v1) by @clemenshelm in #700
  • feat: Share to Pinchy (Web Share Target) — share photos, PDFs, links & contacts into an agent chat by @clemenshelm in #708
  • test(telegram): fix flaky OpenClaw-history-fallback poll (poll for the exact message) by @clemenshelm in #709
  • feat: org timezone setting (Background Jobs foundation, #704) by @clemenshelm in #707
  • feat(inbox-agent): schema + ledger (processed-tracking core, #139) by @clemenshelm in #710
  • feat(inbox-agent): notifications/activity-feed foundation (#704) by @clemenshelm in #712
  • feat(inbox-agent): dispatcher fan-out core (#139) by @clemenshelm in #713
  • feat(eval): Eval-v1 — model-reliability eval harness (#669) by @clemenshelm in #681
  • fix(eval): transport-errored runs are invalid trials, never honest passes by @clemenshelm in #716
  • chore(deps): bump OpenClaw 2026.6.11 → 2026.7.1 + self-restart conflicted Telegram channels (#477) by @clemenshelm in #718
  • fix(attachments): read chat PDFs/images via pinchy_read, drop built-in pdf/image tools by @clemenshelm in #724
  • fix(pinchy-files): NFC/NFD filename fallback so already-stored macOS uploads read by @clemenshelm in #732
  • fix(attachments): normalize upload filenames to NFC (macOS/umlaut names unreadable) by @clemenshelm in #729
  • feat(inbox-agent): production RunAgent adapter — isolated OpenClaw runs by @clemenshelm in #717
  • feat(openclaw-config): disable OpenClaw workspace terminals for governance by @clemenshelm in #719
  • fix(email): preserve umlaut/international attachment filenames (NFC) by @clemenshelm in #733
  • feat(inbox-agent): reclaim stuck ledger rows for reconciliation (#139) by @clemenshelm in #734
  • refactor(chat): remove thought_signature upstream-format-error UX classifier (#338) by @clemenshelm in #726
  • feat(inbox-agent): workflow loader + connection cursor store (#139) by @clemenshelm in #739
  • fix(eval): honest hard-rejection runs wrongly graded false-success (#731) by @clemenshelm in #740
  • fix(memory): make agent memory recall actually work (file fallback + offline embedding index) by @clemenshelm in #736
  • feat(inbox-agent): deterministic mail lister seam (#139) by @clemenshelm in #741
  • ci(eval): run the Eval-v1 harness self-test on every PR by @clemenshelm in #725
  • fix(inbox-agent): pin finalizeEmail to the claim row id (#735) by @clemenshelm in #744
  • fix(eval): join trajectory regrades by (model, latencyMs), and regrade hard-rejection by @clemenshelm in #745
  • fix(security): force method=post on credential forms by @clemenshelm in #743
  • fix(chat): reserve action-bar height so messages don't resize by @clemenshelm in #746
  • fix(composer): restore screenshot paste into the chat box by @clemenshelm in #748
  • test(chat): compare footer heights with sub-pixel tolerance, not bit-exactly by @clemenshelm in #753
  • test: type-check web test files in CI, fix 1058 dormant type errors by @clemenshelm in #742
  • fix(uploads): keep the real filename on compressed image attachments by @clemenshelm in #749
  • fix(test): repair the two type errors that leave main's typecheck red by @clemenshelm in #757
  • fix(auth): stop reporting rate-limited and failed sign-ins as a wrong password by @clemenshelm in #759
  • fix(ci): stop docs-only PRs blocking on checks that can never report by @clemenshelm in #764
  • fix(pinchy-web): dispatch web_fetch through undici's own fetch by @clemenshelm in #760
  • fix(pinchy-files): stop misdiagnosing a missing write root as a symlink escape by @clemenshelm in #761
  • fix(workspace): create the memory/ directory the config already grants by @clemenshelm in #762
  • fix(pinchy-files): create parent directories before pinchy_write by @clemenshelm in #763
  • fix(models): correct deepseek-v4-pro context window to 524288 by @clemenshelm in #765
  • fix(usage): make per-turn accounting tell the truth about cost and context by @clemenshelm in #767
  • fix(odoo): stop leaking synthetic fields to Odoo, stop misdiagnosing corrupted refs by @clemenshelm in #768
  • fix(ci): retry the embedding-model download on transient HuggingFace errors by @clemenshelm in #781
  • fix(models): block minimax-m3 for tool slots, it mangles nested args by @clemenshelm in #766
  • fix(smithers): refresh un-customized souls on upgrade by @clemenshelm in #754
  • feat(kb): Knowledge Base Phase 1 — retrieval, citations, and access-controlled sources by @clemenshelm in #711
  • refactor(seed): make seedDefaultAgent's ownerId required by @clemenshelm in #772
  • test(openclaw-config): find the openclaw.json write by path, not call order by @clemenshelm in #780
  • ci: enable merge queue (trigger on merge_group) to end the rebase treadmill by @clemenshelm in #785
  • test(e2e): stop the stop-button spec gating on another spec's reply by @clemenshelm in #776
  • fix(models): cap deepseek-v4-pro's effective context at 128K by @clemenshelm in #783
  • test(models): catch nested-argument mangling in the ollama-cloud tool probe by @clemenshelm in #777
  • fix(scripts): guard AGENTS.md's documented commands against drift by @clemenshelm in #774
  • fix(diagnostics): stop the export form spilling out of its dialog by @clemenshelm in #778
  • feat(eval): fail CI on a catastrophic scorecard cell without a verdict by @clemenshelm in #779
  • feat(pinchy-odoo): add odoo_reconcile for bank/payment reconciliation by @clemenshelm in #782
  • fix(openclaw-config): strip MEMORY.md from group-session bootstrap (#369) by @clemenshelm in #784
  • fix(eval): narrow the latency-collision guard, and publish the complete hard-rejection sweep by @clemenshelm in #751
  • fix(eval): stop grading a negated creation claim as false-success by @clemenshelm in #756
  • data(eval): re-run silent's 17 invalid trials, restoring 14 cells to n=12 by @clemenshelm in #758
  • test(e2e): stabilize CI-load flakes in settings/permissions E2E (API sign-in in data-setup hooks + deep-link users tab) by @clemenshelm in #786
  • fix(chat): stop trusting a non-throwing chat.abort as a real abort (#550) by @clemenshelm in #752
  • feat(inbox-agent): reconciliation sweep orchestrator (#139) by @clemenshelm in #750
  • fix(pinchy-odoo): actionable tool-arg errors so the model can self-correct by @clemenshelm in #790
  • test(web): give ref-based odoo tools real E2E dispatch coverage (#791) by @clemenshelm in #792
  • feat(kb-eval): three-layer Knowledge Base evaluation harness by @clemenshelm in #793
  • eval: mark the dataset with a contamination canary (#794) by @clemenshelm in #805
  • eval: oracle solution per scenario, proven green in CI (#795) by @clemenshelm in #808
  • eval: paired model comparisons with scenario-clustered SEs and ties (#797) by @clemenshelm in #809
  • test(web): cover every remaining ref-based odoo tool with E2E dispatch (#791) by @clemenshelm in #804
  • eval: versioned dataset releases, dispute channel, disclosures (#802) by @clemenshelm in #807
  • perf(ci): cut CI wall-clock from 45 to 14 min — parallel image builds, cache fix, sharding by @clemenshelm in #811
  • fix(web): clear the copy-confirmation timer on unmount by @clemenshelm in #810
  • eval: surface the pass^k reliability curve in the published export (#796) by @clemenshelm in #806
  • feat(kb): report unsearchable and failed files in reindex counts by @clemenshelm in #815
  • fix(ci): make the format gate cover the whole repo, not just packages/web by @clemenshelm in #813
  • feat(inbox-agent): make the sweep autonomous — scheduler, mailbox ports, boot wiring (#139) by @clemenshelm in #812
  • docs(eval): state the funding and vendor relationships outright (#802) by @clemenshelm in #814
  • docs(skills): refresh the model catalog before any eval sweep by @clemenshelm in #816
  • fix(models): retire the 14 models Ollama dropped, repoint the dead tier slots by @clemenshelm in #817
  • feat(kb): run the reindex as a background job with progress (#714 part 1) by @clemenshelm in #818
  • feat(eval): fingerprint the platform build per sweep (#799) by @clemenshelm in #836
  • fix(release): safe v0.9.0 upgrade path for the pgvector image swap by @clemenshelm in #837
  • fix(eval): stamp PINCHY_BUILD_SHA into the eval stack so the fingerprint is comparable (#799) by @clemenshelm in #841
  • fix(openclaw-config): stop fanning out integration blobs across permission rows by @clemenshelm in #843
  • docs(release-skill): build the staging test plan from the full changelog, split agent vs human by @clemenshelm in #844
  • fix(audit): pseudonymize tool-event actor by canonicalizing OpenClaw's lowercased session-key user id by @clemenshelm in #845
  • fix(kb): batch and time-bound Ollama embedding requests by @clemenshelm in #840
  • feat(integrations): diagnose SMTP port blocks on the IMAP test route by @clemenshelm in #847
  • feat(settings): quiet sidebar, sticky nav, mobile drill-down by @clemenshelm in #706
  • feat(eval): capture per-run token cost, joined by session key (#798) by @clemenshelm in #839
  • fix(deps): green the security audit after an overnight OSV advisory batch by @clemenshelm in #853

Full Changelog: v0.8.0...v0.9.0