Skip to content

Upgrading Pinchy

Pinchy handles most upgrade steps automatically — database migrations run on startup, and the OpenClaw configuration is regenerated from your current settings. A typical upgrade takes under a minute.

  1. Back up your database

    Before any upgrade, create a database backup. This lets you roll back if anything goes wrong.

    Terminal window
    mkdir -p backups
    docker compose exec -T db pg_dump -U pinchy pinchy > backups/pinchy-$(date +%Y%m%d-%H%M%S).sql

    Keeping backups under backups/ instead of loose in /opt/pinchy/ means they don't sit next to your docker-compose.yml / .env, and the directory is easy to target with your off-host backup rotation.

  2. Bump the version pin

    Edit /opt/pinchy/.env and update PINCHY_VERSION to the new release tag (e.g. PINCHY_VERSION=v0.8.0), then pull the matching images:

    Terminal window
    cd /opt/pinchy
    docker compose pull
  3. Restart and prune the old image layer

    Terminal window
    docker compose up -d && docker image prune -f

    up -d applies any pending database migrations, regenerates the OpenClaw configuration, and restarts all services. docker image prune -f then removes the previous image layer for each Pinchy service that pull left dangling — without this, every upgrade keeps the prior pinchy and pinchy-openclaw layers on disk and a long-running deployment eventually fills its root volume.

  4. Verify

    Confirm the new version is running by hitting /api/version — this endpoint is public and ignores Domain Lock, so it works from inside the server even when external access is locked to a specific domain:

    Terminal window
    curl -s http://localhost:7777/api/version
    # {"pinchyVersion":"0.5.8","openclawVersion":"2026.6.5","build":"<git sha>","nodeEnv":"production"}

    Then open Pinchy in your browser at the URL you normally use (e.g. https://your-domain.example) and check the logs for any warnings:

    Terminal window
    docker compose logs pinchy --tail 50

You don't need to worry about these — Pinchy handles them on every startup:

  • Database migrations — Drizzle ORM tracks which migrations have been applied and only runs new ones. This is idempotent and safe to run repeatedly.
  • OpenClaw configuration — Rebuilt from your database state (agents, providers, permissions) every time Pinchy starts. Config format changes between versions are handled transparently.
  • Plugins — Copied from the source code into the OpenClaw extensions volume during the Docker build.
  • New environment variables — Check the release notes for any new variables. Pinchy won't crash if they're missing (features may just be disabled), but review them in your .env file.
  • Docker Compose changes — Most releases reuse the existing docker-compose.yml and only require bumping PINCHY_VERSION in .env. When a release does need a new compose file (new services or volumes), the release notes spell out the extra curl step. New volumes and services are then created automatically on first start.

If you need to roll back after an upgrade:

  1. Stop Pinchy

    Terminal window
    docker compose down
  2. Restore the database

    Pick the backup you want from backups/ (the most recent one is usually what you want):

    Terminal window
    docker compose up db -d
    ls -lt backups/ # newest first
    docker compose exec -T db psql -U pinchy pinchy < backups/pinchy-YYYYMMDD-HHMMSS.sql
  3. Pull the previous version

    Replace vX.Y.Z with the version you want to roll back to (check the Releases page):

    Terminal window
    curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/vX.Y.Z/docker-compose.yml -o docker-compose.yml
    docker compose pull
  4. Restart

    Terminal window
    docker compose up -d

email_search now uses a structured DSL instead of a raw Gmail query string

Section titled “email_search now uses a structured DSL instead of a raw Gmail query string”

The email_search tool previously accepted a raw Gmail query string via a query parameter. It now requires a structured filter object. If your agents called email_search with a query field, update them to use the new fields.

Before (no longer supported):

email_search({ query: "from:alice@example.com is:unread" })

After (structured DSL):

email_search({ from: "alice@example.com", unread: true })

Available filter fields: from, to, subject, text, unread, sinceDays, folder, limit. text is a free-text match across sender, subject, and body — use it for a content match (an invoice number, an order ID, a phrase from the message) that subject alone can't express. See the email_search tool description in your agent's tool list for the full field reference. The structured DSL is provider-agnostic — the same filters work for both Gmail and the new Microsoft 365 backend.

The tighter agent tool boundary described below also changes runtime behaviour for existing agents, but it only removes built-ins that were never meant to be reachable — see the note under Upgrade notes.

The standard flow applies:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.7.0/PINCHY_VERSION=v0.8.0/' .env
docker compose pull && docker compose up -d && docker image prune -f

v0.8.0 adds Microsoft 365 (Outlook) email support alongside Gmail. Connect a Microsoft work/school account under Settings → Integrations, and agents get the same email_list, email_read, email_search, email_get_attachment, email_draft, and email_send tools — backed by the Microsoft Graph API and governed by the same per-agent email permissions. Existing Gmail connections are unaffected.

Each email operation (Read, Create drafts, Send) is granted independently in the Permissions tab — checking one does not grant the others. If you're upgrading an agent that relied on Send also implying Read or Draft, re-check the operations it needs.

Legacy permission vocabulary. Agents created before this release may still have their email permissions stored as legacy per-tool rows (search, list) instead of the current read operation. Pinchy treats search and list as aliases of read — they unlock the exact same read-only toolset and never unlock draft or send. The Permissions UI displays these agents' rows as Read messages, and saving the agent's permissions normalizes them to the current read vocabulary. No action needed.

The audit log now binds every row into an HMAC hash-chain: each row's signature includes its predecessor's, so deleting a row from the middle, truncating the tail, or reordering history breaks the chain — not just editing a field. verifyIntegrity checks each link and reports any breaks. Historical rows are never re-signed — existing entries stay verifiable under their original signature, and the chain starts binding from the upgrade onward. Nothing to configure.

Governed agents now run against a fail-closed allowlist — exactly the audited Pinchy plugin tools plus a few read-only built-ins (memory_search, memory_get, pdf, image, session_status) — instead of a deny-list that left powerful built-ins silently reachable and unaudited. Anything not on the list — cron, gateway, message, nodes, subagents/sessions_*, the tts/image_generate/music_generate/video_generate generators, and any built-in a future OpenClaw version adds — is now denied by default. Existing agents pick this up automatically when their OpenClaw config regenerates on startup; there's no migration and nothing to configure. These built-ins were never an audited Pinchy capability, so no governed agent should notice — and they're denied by design, not re-grantable through agent permissions.

A round of fixes from this cycle that need no action on your part:

  • attachment downloads now enforce per-user ownership (closes an IDOR gap)
  • deactivating a user immediately revokes their active sessions
  • the file-write path resolves symlinks before writing
  • audit and usage CSV exports neutralize spreadsheet formula injection
  • webFetch caps response bodies to bound memory use

Models: self-healing config and smarter vision routing

Section titled “Models: self-healing config and smarter vision routing”
  • Pinchy now self-heals its OpenClaw config when a dispatch hits a retired model, instead of leaving the agent stuck on an unavailable model.
  • Ollama Cloud vision models resolve against the live catalog, and kimi-k2.7-code joins the curated catalog.
  • Image reads route through the audited pinchy_read tool (with its own resolved vision model) rather than OpenClaw's built-in image tool, and image-turn fallbacks pick the best-vision model while honouring the tools blocklist.
  • The composer keeps your unsent draft across reloads, scoped per conversation.
  • Selecting an agent reopens your last-viewed conversation.
  • Agents now carry brand-themed avatars.

Telegram conversations from before the upgrade

Section titled “Telegram conversations from before the upgrade”

Telegram conversations that predate Pinchy's own transcript store now render through an OpenClaw history fallback, so upgrading no longer leaves older chats blank. The Telegram channel also shows as a titled icon in the chat list.

  • OpenClaw 2026.6.11 (was 2026.6.8) — picked up via Dockerfile.openclaw, surfaced in GET /api/version. Same protocol train; backward-compatible patch bump.

One additive migration runs automatically on startup — no manual steps:

  • 0043 — adds the nullable prev_hmac column to audit_log, backing the tamper-evident audit hash-chain.

None.

The standard flow applies:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.6.0/PINCHY_VERSION=v0.7.0/' .env
docker compose pull && docker compose up -d && docker image prune -f

One last sign-in, then your session survives updates

Section titled “One last sign-in, then your session survives updates”

Until now, every update could silently sign you out. On HTTPS/domain-locked instances the session cookie's name depended on a value that was computed nondeterministically at startup, so it sometimes changed between container versions and orphaned your existing login. v0.7.0 pins that decision to the domain-lock state via a stable, persisted flag, so the cookie name no longer changes across restarts.

One transitional effect: this upgrade may sign you out one final time as the cookie name settles onto the stable value. The flag is reconciled before the server starts, so the very first boot already uses the stable cookie name — no second sign-out, and Secure cookies are never briefly downgraded. After that, logins persist across updates as expected. Nothing to configure — just sign back in once if prompted.

One-click deploys: DigitalOcean Marketplace and CapRover

Section titled “One-click deploys: DigitalOcean Marketplace and CapRover”

Spinning up a fresh Pinchy is now a one-click affair on two more platforms: a DigitalOcean Marketplace 1-Click image and a CapRover one-click app template. Existing installs need nothing here — this only adds new install paths. Both templates are version-pinned to the release.

Agents now carry a skills allowlist (migration 0042 adds the column, defaulting to none). This release lays the foundation plus a web-search skill pilot and a market-monitor template. Existing agents are unaffected until you assign skills in their settings.

Pinchy now mirrors conversations into its own store (channel_messages) via the pinchy-transcript plugin, instead of relying solely on OpenClaw's session-scoped history. The transcript is immune to /new, daily resets, and compaction, and backs the read-only channel views. Nothing to configure; the mirror starts filling from the upgrade onward.

When an agent run fails, the chat now shows a persistent banner above the composer with honest, cause-specific wording, instead of a transient message that vanishes on reload. The active error is stored (chat_session_errors), exposed via GET/dismiss endpoints, and swept once resolved. Reload-safe; nothing to configure.

The audit entry-detail sheet is wider and its JSON payload is now one-click copyable — easier to pull a full audit record for review or an incident report.

  • OpenClaw 2026.6.8 (was 2026.6.5) — picked up via Dockerfile.openclaw, surfaced in GET /api/version. Same protocol train; backward-compatible patch bump. The runtime image is now a slimmer multi-stage build (faster pulls), with no behavioural change.

Three additive migrations run automatically on startup — no manual steps, nothing you'd miss:

  • 0040channel_messages table (the Pinchy-owned transcript mirror).
  • 0041chat_session_errors table (the durable paused-error banner).
  • 0042 — adds the skills column to agents (defaults to empty) for the agent-skills allowlist.

Telegram and web no longer share one conversation

Section titled “Telegram and web no longer share one conversation”

Pinchy now uses per-chat sessions. Web and Telegram are separate OpenClaw sessions instead of being folded into one. Previously, an agent linked to a Telegram peer merged that peer's DMs into the user's web chat — which is why a Telegram /new could wipe web history. Starting with v0.6.0, each Telegram peer gets its own session and shows up as a read-only chat in the agent's Chats list.

  • No action required. The stale link is removed automatically the next time the OpenClaw config is regenerated (any settings save, or the first boot after the upgrade). Permissions are unaffected — the Chats list and Telegram allow-listing read channel links directly, not the removed setting.
  • Where your history goes. Your existing web conversation keeps everything under its current session, including Telegram messages that were previously merged in. Telegram starts a fresh, separate thread from the upgrade onward — so a Telegram chat that suddenly looks empty isn't lost; its past messages live in the web conversation.

The standard flow applies:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.8/PINCHY_VERSION=v0.6.0/' .env
docker compose pull && docker compose up -d && docker image prune -f

Each agent now keeps a list of separate conversations per user. A chat switcher in the chat header lets you start a new chat, jump between existing ones, and see the current one at a glance. Chat titles are derived from the first message you send, so the list stays scannable. New chats show a "Not saved yet" marker until the first message lands.

Telegram conversations are visible as read-only chats

Section titled “Telegram conversations are visible as read-only chats”

When an agent is connected to Telegram, each linked peer's conversation appears in the Chats list as a read-only transcript. You can read what was said over Telegram from the web UI; replying still happens in Telegram. This makes Telegram activity auditable from the same place as web chats.

Backgrounding a chat tab mid-reply, reloading during a stream, or reconnecting while a run is still in flight no longer corrupts the message list. The chat view keeps a stable in-flight assistant slot across reconnects and discards stale pre-history buffers, so resume, timeout, and full-reload transitions land cleanly. Nothing to configure.

Reading OpenClaw session files for usage analytics now retries transient EACCES errors instead of failing the request, so per-user/per-turn usage numbers stay reliable under concurrent writes.

  • openclaw-node 0.13.0 (was 0.12.1) and odoo-node 0.3.0 (was 0.2.0) — client-library bumps bundled into the images; no operator action.
  • hono override raised to ≥ 4.12.25 — a transitive web-framework dependency, bumped to clear a published advisory. Build/runtime dependency only.

None this release.

None.

The standard flow applies:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.7/PINCHY_VERSION=v0.5.8/' .env
docker compose pull && docker compose up -d && docker image prune -f

Automatic migration off the default database password

Section titled “Automatic migration off the default database password”

The default pinchy_dev database password is public in our repository, so running on it was never real protection. Starting with v0.5.8, installations that never set DB_PASSWORD are migrated automatically on their first boot after the upgrade: Pinchy generates a strong password, persists it in the pinchy-secrets Docker volume (the same place the encryption key already lives), and applies it to PostgreSQL — no action required, no downtime beyond the normal upgrade restart.

  • If you set DB_PASSWORD in .env: nothing changes. Your value always wins — and if you ever set it without updating PostgreSQL itself, Pinchy now applies it for you on the next boot instead of failing to connect.
  • If you never set DB_PASSWORD: the migration runs once, invisibly. Settings → Security shows the database password as Auto-generated (Docker volume), and GET /api/health reports "db_password": "generated".
  • Backups keep working: the documented docker compose exec db pg_dump … flow authenticates over the container's local socket and does not need the password.
  • Heads-up for direct TCP access: if you connect to the database from the host with the old default password (custom scripts, DB GUIs), switch them to the managed credential or pin your own DB_PASSWORD in .env — Pinchy will apply it on the next restart.

Settings → Security gains a Secrets card showing where each secret comes from — environment variable, persisted file in the Docker volume, or not created yet. The same information is available from the shell via GET /api/health (a new secrets object with provenance values only — never the secrets themselves). This makes the auto-generated file fallback visible from outside the container, so you can tell "secret loaded from the volume" apart from "no secret at all" before rotating anything.

License now fails closed on expiry, with seat grace and renewal prompts

Section titled “License now fails closed on expiry, with seat grace and renewal prompts”

Enterprise licensing was reworked so an expired key can never silently widen access. The change is behavioural — nothing to configure — but worth knowing:

  • Fail-closed expiry. When a license lapses, restricted agents stay restricted and group-based access keeps being enforced. Pinchy never falls back to "everything visible to everyone." All data is untouched; entering a new key re-activates management instantly.
  • 30-day grace for paid keys. A paid key keeps working for 30 days past its paid-until date (trial keys expire immediately at their expiry). After grace, existing restrictions hold and management operations (creating/editing groups, changing agent visibility, analytics export) lock until a new key is entered. Restriction-tightening always works without a license — an admin can still remove users from groups or deactivate them at any time.
  • Seat grace. Invites keep working up to 20% over your seat count; beyond that, new invitations pause (existing users are never deactivated). The seat counter and an inline notice make the headroom visible.
  • Renewal prompts. The license banner now shows trial days remaining (dismissible per session) and a renewal reminder starting 14 days before a paid key expires; gated feature cards link to renewal.

Chat survives tab switches and reconnects without crashing

Section titled “Chat survives tab switches and reconnects without crashing”

Backgrounding a chat tab mid-reply and returning to it — or any reconnect while a run is still streaming — no longer trips the "Something went wrong" error screen. The chat view now keeps a stable in-flight assistant slot across the WebSocket reconnect, so disconnect, timeout, and resume transitions never leave the message list in the index-mismatch state that produced the crash. Nothing to configure; reload any chat tab left open across the upgrade once.

  • PDFs are never wrongly blocked. Pinchy used to gate PDF attachments on a model "documents" capability that didn't reflect reality — PDFs are routed through OpenClaw's pdf tool, not the model's native input. The false block is gone; PDFs attach and work regardless of the model's native document support.
  • Model changes are validated. Updating an agent's model now rejects a model whose provider isn't configured (no API key) with a clear 400, instead of silently leaving the agent unable to chat. Leaving the model unchanged (e.g. a name-only edit) still works even if its provider was since disconnected.
  • Ollama Cloud catalog reconciled with the live model list — newly tool-reliable models added, known-broken ones kept out. No action required; the list refreshes from the built-in catalog.

DOCX uploads are now guarded against decompression ("zip bomb") attacks on two layers — a pre-decompress size check and a post-decompress cap — and malformed/ZIP64 archives are rejected fail-closed. Ordinary documents are unaffected.

  • OpenClaw 2026.6.5 (was 2026.5.28) — picked up via Dockerfile.openclaw, surfaced in GET /api/version. Same protocol train; backward-compatible patch bump.
  • esbuild ≥ 0.28.1 — a transitive build-time dependency, bumped to clear GHSA-gv7w-rqvm-qjhr (CVSS 8.1). Build-tooling only; nothing ships it to production or to operators.

0038 drops the unused documents/audio/video columns from the models capability table (they had no consumer — see the PDF-routing note above). Additive cleanup, runs automatically on startup, no manual steps and no data you'd miss.

Reload any chat tab left open across the upgrade. This release moves image and file attachments from inline base64 frames to a staged multipart-upload pipeline (see Resumable, staged file uploads below). A chat tab that was open before the upgrade is still running the previous client; the first time it tries to send an image it receives a PROTOCOL_OUTDATED error toast instead of delivering the message. Reloading the tab loads the new client and clears the error. Text-only messages from a stale tab are unaffected, and no server-side, config, or data action is required — this is purely a client-refresh transition.

v0.5.7 is a large release. The headline changes are a new staged file-upload pipeline, capability-aware attachment handling with inline recovery, resumable streaming across reconnects, and a more reliable first chat on freshly-created agents. Everything below is picked up by the standard docker compose pull && docker compose up -d flow; three additive database migrations (00340036) run automatically on startup and require no manual steps.

Attachments no longer travel inline as base64 inside the chat WebSocket frame. Instead the browser uploads each file to a new endpoint — POST /api/agents/<agentId>/uploads — which stages it server-side and returns an upload id; the chat message then references files by id. This makes large attachments reliable, shows per-file progress and retry in the composer, and keeps the chat socket lean.

  • Limits. Up to 10 attachments per message and 15 MB per file (the endpoint returns 413 above that). Staged files live for 24 hours before they become eligible for cleanup.
  • Wider file support. The picker now accepts CSV, plain text, Markdown, JSON, and YAML in addition to images and PDFs.
  • Automatic cleanup. A garbage-collection sweep runs at startup and hourly, deleting staged files whose 24-hour TTL has elapsed and that were never attached to a sent message. Each sweep is correlated by a sweepId and emits one file.upload.expired audit row per reclaimed file.
  • New audit events. file.upload.staged (a file was accepted, or rejected with outcome: "failure"), file.upload.attached (a staged file was promoted into a sent message), and file.upload.expired (a staged orphan was swept). These are additive — existing audit queries are unaffected.

As noted under Breaking changes, the server now rejects the old inline-image_url frame with PROTOCOL_OUTDATED, so each browser tab must be reloaded once after the upgrade before it can send images again.

Capability-aware attachments and inline recovery

Section titled “Capability-aware attachments and inline recovery”

Pinchy now knows which capabilities (vision, documents, audio, video, long-context, tools) each model supports and uses that to stop a doomed attachment before it is sent, rather than failing deep inside the agent.

  • Pre-send block + RecoveryPanel. Attaching an image or PDF to an agent whose current model can't handle it hard-blocks the send and shows an inline RecoveryPanel with a plain-English explanation and a one-click link to switch the agent's model. Nothing is sent until the mismatch is resolved.
  • Capability hints in the model picker. The model picker shows per-capability icons and tooltips, and an amber warning on any model that fails a capability required by the current agent or template.
  • 422 on agent creation. POST /api/agents now returns 422 template_capability_unavailable (with the missing capabilities and a docs link) and writes a failure agent.created audit row when no installed model satisfies a template's required capabilities — instead of silently creating an agent that can't do its job.
  • Onboarding warning. The setup wizard warns when no available model satisfies the default agent's required capabilities.
  • models table — zero configuration. A new models table records each model's capabilities. It is seeded from Pinchy's built-in catalog on every boot; for local Ollama, capabilities are detected from the Ollama API when you save the URL. No manual entry is required.

Earlier docs described this capability handling under the v0.5.4 notes; it actually ships in v0.5.7, and the v0.5.4 section has been corrected accordingly.

When your browser drops mid-stream and reconnects (closed tab, network blip, Wi-Fi handoff), Pinchy now joins the new connection to the in-flight run and keeps streaming chunks into the same assistant bubble — no more "The agent didn't respond" flash bubble for runs that were actually still running server-side. Under the hood:

  • A new in-memory ActiveRuns registry on Pinchy tracks every in-flight chat run by sessionKey, with each entry holding the OpenClaw-correlated runId, the per-turn messageId, and the set of currently-connected listener WebSockets. Multi-tab sessions on the same chat now naturally see the same stream — both tabs end up in the listener set.
  • The in-flight reply text is buffered server-side and replayed on reconnect. Streaming chunks are deltas the server never re-sends, so a tab reloaded mid-stream used to lose the words that had already streamed. The registry now accumulates the emitted text and seeds the resumed bubble with it — the reply arrives complete, not just from the reconnect point onward.
  • A server-side run watchdog scans ActiveRuns every 30 seconds and tears down runs whose absolute age exceeds the per-deployment cap (default 15 minutes). This is the server-side belt to the existing client-side stuck-timer suspenders — it catches runs that hang while the tab is backgrounded or after the laptop sleeps. Stuck runs are aborted via OpenClaw, audited as chat.run_timed_out, and a terminal error frame is broadcast to any still-connected listener.
  • The same watchdog also catches the opposite failure: a run the backend accepts at dispatch but that never produces a first chunk within the first-chunk timeout (default 180 seconds) — a wedged or rate-limited provider/lane — is torn down, audited as chat.run_no_first_chunk, and surfaced to the user as a retryable error so they can resend instead of staring at a blank thread. This is the reload-surviving server-side backstop to the client's 60-second stuck timer.
  • The audit trail gains four new event types: chat.run_timed_out, chat.run_no_first_chunk, chat.run_completed_after_disconnect, and chat.run_aborted (the last is declared in the audit union for a future user-triggered abort UI; emission lands when that UI ships). Existing audit queries are unaffected — the new events are additive.

The ActiveRuns registry is in-memory only — a Pinchy restart drops every entry, which is acceptable because the OpenClaw side is restarted (or unreachable) in that case. No database migration is required for it.

Operationally:

  • New audit-trail queries you might want bookmarked:
    • chat.run_timed_out — how many runs hit the 15-min hard cap last week?
    • chat.run_no_first_chunk — how often does the backend accept a run but never start streaming? A spike here points at a wedged or rate-limited provider/lane (this is the signal that was missing during exactly that class of incident).
    • chat.run_completed_after_disconnect — how often do users abandon a long-running chat? Correlates with background-tab behavior.
  • The 15-minute absolute cap and the 180-second first-chunk timeout are both per-deployment and live in packages/web/src/server/run-watchdog.ts (DEFAULT_MAX_RUN_DURATION_MS and DEFAULT_FIRST_CHUNK_TIMEOUT_MS). There is intentionally no per-agent override; surface one as a deployment env var if you ever see a legitimate need (YAGNI today).

More reliable first chat on freshly-created agents

Section titled “More reliable first chat on freshly-created agents”

The first message to a just-created agent could previously fail with unknown agent id when the chat dispatch raced ahead of OpenClaw applying the new agent config. Pinchy now gates the first dispatch on OpenClaw's agents.list runtime-readiness signal, retries config.apply when the gateway rate-limits it instead of silently dropping the change, and applies new agents via hot-reload rather than an atomic file write the gateway's watcher could miss. No action required — it's a reliability fix.

OpenClaw owns the Telegram poller, so a channel worker that crash-loops below the gateway WebSocket used to be invisible — the connection stayed "connected" while the bot silently dropped messages. A new watchdog probes the channel status every 30 seconds and makes those failures operator-visible:

  • A red Degraded badge appears on the agent's Telegram settings while the poller is failing, with the underlying error on hover.
  • The audit trail gains three event types: channel.degraded (first failure), channel.polling_failed (still down after several consecutive probes), and channel.recovered — together they bound the outage window. Error detail is PII-scrubbed.

The classic trigger is one bot token polled by two deployments (staging and production, say): Telegram allows a single getUpdates consumer per bot, so the instances terminate each other in a loop. If you see a persistent degraded badge with a "terminated by other getUpdates request" error, give each environment its own bot. Nothing to configure — the watchdog is on after the upgrade.

Admins can now generate a downloadable bug-report bundle from Settings → Support: pick an agent, and Pinchy packages the version triplet (Pinchy, OpenClaw, openclaw-node), the scoped session trace as OTel-style spans with per-turn timing and token usage, and the related audit entries. Secrets are redacted with the audit-trail sanitizer and session keys are hashed before anything is written; the bundle does include conversation text, since that is usually what a bug report needs. Each export is audited as diagnostics.exported.

v0.5.7 also fixes the v0.5.6 setup-wizard regression where Smithers replied with No API key found for provider '<name>' on the very first chat message after a fresh install. The bug was provider-agnostic: OpenClaw's secrets-provider initialised at gateway boot with a "file missing" state because secrets.json was only written after the user completed the wizard. The provider never reinitialised when Pinchy hot-reloaded openclaw.json (the secrets-section diff was empty), so the gateway ran the rest of the session with no provider keys until a manual container restart.

The fix is Pinchy-side: an inotifywait handler in start-openclaw.sh writes a /openclaw-secrets/.bootstrap-applied marker on the first appearance of secrets.json and SIGTERMs the gateway exactly once so the next boot picks up the file. The health-check loop respawns the gateway within ~10–40 s, and a build-time drift guard in validateBuiltConfig rejects emitted configs whose SecretRef pointers don't resolve in secrets.json — closing the related class of "config references a key that isn't there" bugs that would have produced the same symptom from the Pinchy side.

If you saw the "No API key found" error on v0.5.6 and restarted the OpenClaw container manually to recover, no follow-up action is needed — the secrets-provider re-reads cleanly from disk on every boot.

No manual steps beyond the standard upgrade flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.6/PINCHY_VERSION=v0.5.7/' .env
docker compose pull && docker compose up -d && docker image prune -f

BETTER_AUTH_URL removed — no action needed

Section titled “BETTER_AUTH_URL removed — no action needed”

Pinchy no longer reads BETTER_AUTH_URL. An investigation (#352) confirmed the variable had no functional consumer:

  • Pinchy doesn't use Better Auth's email-verification or password-reset email flows. Password resets run through Pinchy's own invite-token system, and the reset link is built from the browser's current origin — not from a configured base URL.
  • Origin / CSRF checks read the Domain Lock value (and the request host), not BETTER_AUTH_URL.
  • We don't use OAuth, the one remaining Better Auth feature that needs an absolute callback URL.

The variable is gone from docker-compose.yml, .env.example, and the startup warning that previously told Domain-Locked deployments to set it (added in v0.5.4 — see below). If you set BETTER_AUTH_URL in your .env or a docker-compose.override.yml, you can drop it. Leaving it in place is harmless — it is simply ignored — but the line is now dead config. Domain Lock remains the single source of truth for your public origin; HTTPS, secure cookies, and origin enforcement are unchanged.

Ollama Cloud model catalog refreshed against the live API

Section titled “Ollama Cloud model catalog refreshed against the live API”

The Ollama Cloud library pages over-promise: some models advertise capabilities the live API doesn't actually honor. We re-probed every cloud model against the real /v1/chat/completions endpoint — sending image payloads with non-guessable content for vision and a function schema for tools — and corrected the catalog to match what the API does, not what the library page claims.

  • MiniMax M3 added. minimax-m3 joins the picker as a vision + reasoning + tools model (512K context). Vision and tool calling were both confirmed against the live API. It is now the reasoning-tier vision default.
  • qwen3.5:397b is now text-only. Its library page lists image input, but the live endpoint accepts image payloads and then hallucinates their contents rather than rejecting them — it does not actually see images. It stays available as a text/reasoning model and is no longer offered as a vision choice. Image work that previously could route here now uses the canonical vision line (qwen3-vl > gemini-3-flash-preview > gemma4).
  • qwen3-next:80b removed. On Ollama Cloud's OpenAI-completions endpoint it never emits a structured tool call — it returns empty content or a malformed tool-call blob, even when tools are required. Every Pinchy agent uses tools, so a tool-broken model has no place in the picker. The Ollama Cloud balanced default moves to glm-4.7.

No action is required for agents created the normal way: their model comes from the capability resolver (which never selected qwen3-next:80b), and the global default is recomputed on the upgrade's config regeneration. The only agents affected are ones where someone manually pinned ollama-cloud/qwen3-next:80b — those couldn't call tools before this release either, so switch them to ollama-cloud/glm-4.7 (or another model) in the agent's settings.

Pinchy now ships a web-app manifest and platform splash screens, so it can be installed as a standalone app. In Chrome on the desktop an install icon appears in the address bar; on iOS Safari, Share → Add to Home Screen produces a launcher that opens Pinchy full-screen with a branded splash. See the new Install as an app guide. Nothing to configure — it is available after the upgrade.

  • Usage dashboard now records prompt-cache tokens. Previously the poller read the wrong field names from OpenClaw and stored every cache counter as 0 — with providers that cache aggressively (Anthropic), the dashboard could show single-digit input for heavy days. After the upgrade, new usage records carry cache reads/writes, the daily chart gains a dashed Cached Input series, and cost estimates include cache pricing. Historic rows stay as recorded; expect day totals to jump. Totals remain approximate until per-turn accounting lands (#483).
  • Configurable usage poll interval. The usage-counter poller interval is now configurable via PINCHY_USAGE_POLL_INTERVAL_MS (default 60000, minimum 1000). Most deployments need not set it.
  • Database migrations. 0034 adds last_error/last_error_at to integration_connections (surfaces integration auth-failure detail), 0035 creates the uploaded_files staging table, and 0036 creates the models capability table. All three are additive and run automatically on startup.
  • openclaw-node 0.12.1 (was 0.10.0) — Pinchy bundles this internally; nothing for operators to install. It adds agents.list(), which powers the dispatch-readiness gate above, and carries the Gateway-correlated runId on every ChatChunk.
  • OpenClaw 2026.5.28 (was 2026.5.20) — picked up via Dockerfile.openclaw and surfaced in GET /api/version.
  • hono ≥ 4.12.21 — pinned to clear four disclosed CVEs in this transitive dependency.

None.

v0.5.6 is a cosmetic patch on top of v0.5.5. The v0.5.5 release-cut was performed via gh release create instead of pnpm release, which skipped the version bump in package.json and packages/web/package.json. As a result, v0.5.5 images report "pinchyVersion": "0.5.4" from /api/version even though the image tag, OCI image.version label, and OpenClaw runtime are all on the intended v0.5.5 wire. v0.5.6 restores agreement between the tag and the reported version. There are no functional changes versus v0.5.5.

If you already deployed v0.5.5, upgrade straight to v0.5.6:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.5/PINCHY_VERSION=v0.5.6/' .env
docker compose pull && docker compose up -d && docker image prune -f

If you are upgrading directly from v0.5.4, skip v0.5.5 and follow the v0.5.4 → v0.5.5 upgrade notes below (substituting v0.5.6 for v0.5.5 in the sed command). All v0.5.5 behaviour ships in v0.5.6 unchanged.

None for stock templates. If you maintain a custom AGENTS.md that tells the agent to save files into uploads/, see Agent writable area moved to workbench/ below for the recommended (non-mandatory) migration.

v0.5.5 picks up OpenClaw 2026.5.20 with the v4 client protocol (was 2026.5.7 / v3), gives every agent a dedicated workbench/ subdirectory in its workspace for files it produces, separate from the user's uploads/, and hardens the Odoo plugin against silent cross-company writes for multi-company databases. It also fixes a confusing failure mode for the built-in image tool on Ollama Cloud stacks, adds an explicit image-model default, patches a reliability edge where chat history could disappear overnight due to OpenClaw's default daily session-reset behavior, and tightens the password-reset path so leaked recovery links cannot leave a logged-in session behind.

Upgrade with the standard flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.4/PINCHY_VERSION=v0.5.5/' .env
docker compose pull && docker compose up -d && docker image prune -f

No database migration, no docker-compose.yml change, and no env-var changes are required.

Each agent workspace now has three zones (see Agent Workspaces for the full model):

  • Workspace root — system files like SOUL.md, AGENTS.md, IDENTITY.md. Read-only for the agent.
  • uploads/ — files the user attached in chat. Created on workspace spawn; previously created lazily by the first upload.
  • workbench/ (new) — the agent's own writable area. Created on workspace spawn. pinchy_write accepts paths under here without prior user upload.

On v0.5.4 and earlier, a fresh agent could not call pinchy_write until the user had attached at least one file via the chat upload button — pinchy_write to <workspace>/uploads/foo.txt failed with ENOENT because the uploads/ directory didn't exist yet, and writing anywhere else (e.g. the workspace root) was rejected. v0.5.5 provisions both uploads/ and workbench/ on workspace creation, and adds workbench/ to the pinchy_write allow-list as the canonical agent write target.

Existing custom AGENTS.md files keep working. uploads/ remains writable for backward compatibility, so any custom instruction telling the agent to save into uploads/ continues to function. If you maintain such an AGENTS.md, consider updating it to use workbench/ instead — the separation makes "user-uploaded" vs. "agent-produced" easier to reason about. There is no automatic migration; this is a documentation-level switch.

Stock templates do not currently instruct agents to write to either location, so most deployments need no action.

When pinchy_write (or pinchy_read) refuses a path, the error message now includes the configured allow-list so the LLM can retry against the right location:

Access denied: path not in write_paths (allowed: /root/.openclaw/workspaces/<id>/uploads, /root/.openclaw/workspaces/<id>/workbench)

This eliminates a class of stalls where the model would repeatedly try the same wrong path. The error string format is unchanged at the prefix (Access denied: path not in write_paths) so any external monitoring that matched on it continues to work.

Image tool no longer routes to devstral-small-2:24b

Section titled “Image tool no longer routes to devstral-small-2:24b”

On Ollama Cloud stacks without an explicit image model, Pinchy's built-in image tool could pick devstral-small-2:24b and fail with HTTP 400 "Image input is not enabled for this model" mid-chat — confusing because the user never selected devstral. Two fixes ship together:

  • Data correction. devstral-small-2:24b is now flagged vision: false. Its ollama.com library page lists "Text, Image" as input types, but an empirical smoke test against the live /v1/chat/completions endpoint (see scripts/verify-ollama-cloud-vision.mjs) confirms the runtime API rejects images with HTTP 400. Devstral is Mistral's coding series, not a vision model.
  • Explicit image-model default. Pinchy now emits agents.defaults.imageModel.primary into the OpenClaw config, parallel to the existing pdfModel selection. Provider preference order: anthropic > google > openai > ollama-cloud. For ollama-cloud the canonical-vision line wins (qwen3-vl:235b-instruct > qwen3-vl:235b > gemini-3-flash-preview > gemma4:31b), avoiding models like mistral-large-3:675b or qwen3.5:397b that accept image input but mislabel colors.

No action required. The new field is regenerated on startup from your existing provider settings. Operators who want to override the auto-pick can hand-edit agents.defaults.imageModel.primary in openclaw.json.

A companion verification script lives at scripts/verify-ollama-cloud-vision.mjs and can be re-run whenever the Ollama Cloud catalog changes: it tests each curated model against the live API and reports any drift between the vision flag in ollama-cloud-models.ts and runtime acceptance.

CRM & Sales Assistant template gains quotation-ready Odoo models

Section titled “CRM & Sales Assistant template gains quotation-ready Odoo models”

The CRM & Sales Assistant template now declares three additional Odoo models so a Sales agent can build quotations end-to-end (lead → opportunity → quote with the right VAT regime) and answer "is this invoice paid?":

  • account.fiscal.position (read + write) — set the customer's tax regime (e.g. "EU B2B reverse-charge") on res.partner.property_account_position_id so future quotations auto-apply the correct taxes.
  • sale.order.line (read + create + write) — inspect and revise quotation line items directly. Normal happy-path writes still go through sale.order.order_line.
  • account.move (read-only) — look up invoice payment status. Drafting, posting, or amending invoices remains exclusive to the Bookkeeper template, which is governed by a regulated draft-first / four-eyes flow.

A new Fiscal Positions row also appears in the Permissions UI for every Odoo connection (regardless of which template the agent uses), because the schema sync now probes account.fiscal.position as part of the standard accounting category.

Action required for existing CRM agents. Template changes only affect newly-created agents. To grant an existing CRM & Sales Assistant agent access to the new models:

  1. Open the agent's settings → Permissions.
  2. Tick account.fiscal.position (Read + Write), sale.order.line (Read + Create + Write), and account.move (Read).
  3. Save.

If you skip this step, the existing agent keeps its previous (narrower) permission set — there is no automatic migration. Newly-created agents from this template pick up the new models automatically.

Chat history persists across daily restarts

Section titled “Chat history persists across daily restarts”

OpenClaw ships with a default session.reset: { mode: "daily", atHour: 4 } that rotates the session pointer at 04:00 gateway-local time. Each morning the pointer moved to a new, empty transcript — old history stayed on disk but became unreachable from the Pinchy UI. Pinchy now unconditionally overrides this setting to an idle-based reset with a one-year idle window (mode: "idle", idleMinutes: 525600), which never fires under normal use. Conversations persist until the user explicitly resets with /new or a new chat is started manually.

No action required. The override is written on every Pinchy startup via regenerateOpenClawConfig(). If your instance was affected, existing message files are still on disk under ~/.openclaw/agents/<agentId>/sessions/. Reach out to your administrator if you need to restore a specific session.

v0.5.5 bumps the bundled OpenClaw runtime from 2026.5.7 to 2026.5.20 and openclaw-node from 0.9.0 to 0.10.0. OpenClaw 2026.5.12 raised MIN_CLIENT_PROTOCOL_VERSION from 3 to 4 — earlier Pinchy releases paired with a self-hosted OpenClaw on a newer tag would fall into an infinite "Waiting for OpenClaw Gateway…" loop with protocol mismatch … expected=4 in the gateway log (#411). The v0.5.5 client advertises protocol v4 and clears the handshake.

OpenClaw 2026.5.12 also stopped self-bootstrapping a random gateway.auth.token on first start and now refuses to bind on a non-loopback interface without one. Pinchy now seeds gateway.auth.{mode,token} before OpenClaw starts so fresh installs (no setup wizard run yet) come up cleanly.

No action required for the standard Docker Compose stackdocker compose pull && up -d swaps both images together. If you run a custom OpenClaw on the side and pair it with openclaw-node directly, bump to 0.10.0 to advertise protocol v4.

Cross-company write protection in Odoo agents

Section titled “Cross-company write protection in Odoo agents”

For multi-company Odoo databases, the pinchy-odoo plugin now refuses to write a record whose embedded _pinchy_ref company tag disagrees with the company implied by the relation chain (top-level field only). This stops a class of silent cross-company mistakes — for example, an agent applying a fiscal position from Company A to a partner that lives under Company B, where the write would previously be accepted by Odoo but produce wrong downstream taxes.

Companion changes ship together:

  • Auto-include company_id. odoo_read now transparently augments the requested field list with company_id for company-scoped models (res.partner, account.fiscal.position, etc.) so the agent always has the company context it needs for the next decision, without bloating the agent's prompt with extra field lists.
  • _pinchy_ref carries the company name. Encoded references now include an optional companyId / companyLabel, and labels are suffixed with the company name ("ACME Bookkeeping [Company A]") when ambiguity exists. The base ordering invariant for _pinchy_ref is unchanged.
  • Better many2one collision errors. When an odoo_create or odoo_write lookup matches more than one record across companies, the error message now explains the multi-company collision instead of returning a generic "multiple matches" string, so the agent can retry with a company_id constraint.
  • Penny and Bookkeeper templates updated. Both stock templates now instruct the agent to disambiguate multi-company records up front instead of guessing.

Action for existing read-write Odoo agents (Penny / Bookkeeper): newly-created agents get the updated instructions automatically. Existing agents keep their current AGENTS.md unless you re-create them; the runtime guard (cross-company write rejection) applies to all Odoo agents regardless of AGENTS.md content.

Password reset now revokes sessions and writes an audit entry

Section titled “Password reset now revokes sessions and writes an audit entry”

POST /api/invite/claim on the reset branch is now wrapped in a database transaction with three guarantees (PR #431):

  1. Existing sessions for the target user are revoked. A leaked or stale session token cannot survive a password reset, so recovery semantics are now sound.
  2. The four writes (account password, optional user name, invite-token claim, session revocation) are atomic. If any step fails, everything rolls back and the reset link stays usable for a retry.
  3. An auth.password_reset_completed audit entry is written. Password changes are security-sensitive regardless of who triggers them, and CISOs expect to see them in the audit trail.

See the new row in Audit trail → Authentication for the detail-shape.

No action required. Behavior change only on the reset path; ordinary login sessions are untouched.

Before v0.5.5, only three error classes wrote audit entries (agent.model_unavailable, agent.upstream_format_error, chat.silent_stream) and each was throttled. The long tail — incomplete-terminal-response failovers, unclassified provider errors, transient blips — had no audit signal at all, which made "how often does this happen?" unanswerable without screenshotting.

A new chat.agent_error event now fires unconditionally for every error chunk plus the synthesised silent-stream timeout. It captures agent, model, an errorClass discriminator (one of failover_incomplete_stream / schema_rejection / model_unavailable / transient / provider_config / silent_stream_timeout / unknown), and an email-scrubbed providerError truncated to 1024 bytes. The specialised events stay in their role as throttled per-class signals; the umbrella runs alongside them, not instead.

A single SQL query grouped by detail->>'errorClass' now aggregates every failure shape for a fleet-wide failure-rate dashboard. See Audit trail → Chat runtime for the full row.

  • uuid < 11.1.1 (GHSA-w5hq-g745-h8pq, moderate). Reachable only via googleapis → google-auth-library → gaxios → uuid from the pinchy-email plugin's Gmail integration. The advisory is missing-buffer-bounds checks in v3/v5/v6 UUID generation when callers supply their own buffer; Pinchy and its downstream deps only call the no-argument v4 form, so the gadget is unreachable in our code paths. The dep cannot be upgraded without bumping googleapis past a major it has not yet released. Tracked; pnpm audit --audit-level=high --prod (the level our release gate runs at) stays clean.

Integration lifecycle events have moved out of the generic config.changed bucket and into their own resource namespace, matching the convention already used for agent.*, group.*, and user.*.

| Before | After | | ------------------------------------------------------------- | ---------------------------- | | config.changed (detail.action: integration_created) | integration.created | | config.changed (detail.action: integration_updated) | integration.updated | | config.changed (detail.action: integration_deleted) | integration.deleted | | config.changed (detail.action: integration_schema_synced) | integration.synced | | integration.recovered | integration.auth_recovered |

integration.auth_failed and integration.credentials_updated are unchanged. Credential changes no longer emit a paired config.changed row alongside integration.credentials_updated — one mutation now produces one audit row. See Audit trail → Integration management for the full list and detail-field reference.

Existing audit rows from v0.5.3 and earlier keep their original event names — the log is HMAC-signed and immutable. Any alerting or compliance pipelines that filter on eventType need to be updated to match both old and new names during the transition window. A single filter that covers both is eventType IN ('integration.created', 'integration.updated', 'integration.deleted', 'config.changed') AND resource LIKE 'integration:%'.

v0.5.4 extends the Odoo template library with read-write operator agents, hardens how those agents reference Odoo records, and irons out several chat-reliability edges. It also picks up Next.js security patches and OpenClaw 2026.5.7.

Upgrade with the standard flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.3/PINCHY_VERSION=v0.5.4/' .env
docker compose pull && docker compose up -d && docker image prune -f

No database migration, no docker-compose.yml change, and no env-var changes are required.

Bookkeeper / Odoo schema discovery (auto-migrated)

Section titled “Bookkeeper / Odoo schema discovery (auto-migrated)”

The odoo_schema tool has been replaced by two narrower tools: odoo_list_models and odoo_describe_model. The new odoo_describe_model returns a compact field map (default ~40 most-common fields per model) and accepts fields: ["…"], limit, and verbose: true arguments. This cuts typical schema-discovery context cost from ~18 kB per model to ~1 kB, which unblocks vision-capable models like ollama-cloud/gemini-3-flash-preview for invoice-processing flows.

No action required. A startup migration rewrites every agent's allowed_tools to use the new names, and the read-write Odoo operator templates (Bookkeeper, Warehouse Operator, HR Operator, etc.) ship with updated guidance for the agent.

For existing agents created before v0.5.4, the old odoo_schema tool name is kept as a deprecated alias. The AGENTS.md files those agents store in their workspace still contain literal odoo_schema references — the alias keeps them working without any manual file editing, and routes the call through the new compact code path. You can safely ignore the alias; it will be removed in v0.6.x.

The agent picker now includes a Bookkeeper template and five read-write Odoo operator counterparts to the existing read-only Analysts:

| Analyst (read-only) | Operator (read + create + write) | | --------------------- | -------------------------------- | | Project Tracker | Project Manager | | HR Analyst | HR Operator | | Inventory Scout | Warehouse Operator | | Manufacturing Planner | Production Operator | | — | Approval Manager (cross-module) |

Each operator template follows a safety pattern: mandatory user confirmation before any side-effecting write, duplicate-check on every create, no delete on any model (cancellations are write transitions, never hard deletes), and read-only access to records that belong to a different role. The new Bookkeeper template covers the "book this receipt" workflow with a draft-first, dedupe-first, one-shot-create flow.

The Approval Manager works on Odoo Community as well as Enterprise — the approval.request and approval.category models are flagged optional, so the Create button stays enabled on Community installs and the agent discovers availability at runtime via odoo_schema.

Vision capability is now standard for read-write Odoo templates

Section titled “Vision capability is now standard for read-write Odoo templates”

Every read-write Odoo operator template now declares the vision capability in its model hint. Previously this had to be set manually after agent creation, which often landed users on unstable Vision+Tools models. A new drift invariant in the test suite enforces this for any future write-capable Odoo template.

When an Odoo tool returns a record, related-record references are now emitted as opaque, encrypted tokens (pinchy_ref:v1:…) rather than raw (id, label) tuples. The pinchy-odoo plugin transparently resolves these tokens on subsequent calls, so an agent can no longer fabricate or substitute a numeric ID it never saw. Existing agents pick up the new behavior automatically; no configuration change is required.

Self-refs on odoo_create and odoo_read (_pinchy_ref)

Section titled “Self-refs on odoo_create and odoo_read (_pinchy_ref)”

Every record the plugin returns now carries a _pinchy_ref field — an opaque, encrypted token that identifies the record itself (alongside the raw integer id). odoo_create returns {id, _pinchy_ref} instead of just {id}, and every record returned by odoo_read carries one.

This closes a release-blocker gap surfaced on staging in late v0.5.3 testing: the odoo_attach_file tool only accepts opaque references for targetRef, but odoo_create's old {id}-only response left agents no path to a valid token for a record they had just created. They would fabricate strings like "account.move,37", which the plugin correctly rejected with "Invalid integration reference" — making odoo_createodoo_attach_file chains (the entire Bookkeeper "book this bill and attach the PDF" flow) effectively unreachable.

The field is named _pinchy_ref rather than ref to avoid shadowing Odoo's own ref field, which exists on account.move, account.payment, and others as a string holding payment-reference identifiers ("INV/2026/0001" etc.). The underscore prefix signals "Pinchy-added, not Odoo data" so the LLM's view of actual Odoo records stays lossless.

Tools that already accept raw integer IDs (odoo_write, odoo_delete) are unchanged. Existing agents pick up the new behavior automatically; the operator-template AGENTS.md files have been updated to teach agents about the _pinchy_ref field, so old agents continue to work via the shared instruction shipped in their template prompt.

Odoo file attachment (new odoo_attach_file tool)

Section titled “Odoo file attachment (new odoo_attach_file tool)”

Read-write Odoo operator templates can now attach uploaded files to Odoo records as ir.attachment. The Bookkeeper template uses this to link receipt images to the corresponding vendor bill; the Warehouse Operator can attach delivery notes to pickings; the HR Operator can attach medical certificates to leave requests; and so on for the Project Manager, Production Operator, and Approval Manager.

The new odoo_attach_file tool is automatically included in the read-write permission tier alongside odoo_create and odoo_write. When you create any read-write Odoo agent, the tool is pre-enabled — no manual permission change is required.

After upgrading: existing Odoo connections need a schema re-sync to pick up ir.attachment. Open Settings → Integrations → Odoo → ⋯ → Sync now. Until you sync, the Create buttons for operator templates that reference ir.attachment will remain disabled.

The tool rejects filenames containing path separators or leading dots, and caps attachments at 25 MB (matching Odoo's default web.max_file_upload_size). These guardrails prevent a prompt-injection-influenced agent from referencing files outside the agent's uploads directory.

Open chats keep running in the background while you navigate within Pinchy — agents no longer reset when you switch to another part of the app. A pulse dot in the sidebar marks each agent with an active run; if the last turn errored, the dot turns red so you see at a glance which chats need attention. (#199)

  • Browser sleep recovery. Chats now reattach cleanly when a tab returns from background sleep instead of getting stuck on a stale stream.
  • Dead-key composer freeze. Typing characters that involve dead keys (e.g. ^ + eê) no longer desyncs the composer input.
  • Payload rejection visibility. When OpenClaw rejects a payload mid-stream, the chat now surfaces a clear error status instead of leaving the spinner running.
  • Silent stream-end retry. A run that finishes without producing any assistant text — typically a cold-path tool call that timed out inside OpenClaw's embedded layer — now shows the standard error bubble with a Retry button instead of an indistinguishable "successful empty reply". Each occurrence writes a throttled chat.silent_stream audit entry so admins get an operational signal.
  • Gemini 3 thought_signature errors are now named and explained. When the upstream provider drops Gemini 3's required thought_signature field on a tool-call replay turn (upstream openclaw/openclaw#72879), Pinchy now shows a dedicated transient upstream issue bubble that names the cause and tells the user that Retry usually clears it on the next try. The bubble deliberately offers no "Switch model" link — the model is fine. Each occurrence writes a throttled agent.upstream_format_error audit entry so admins can track frequency from the audit page rather than grepping gateway logs. The upstream fix for the native Google path lands in OpenClaw 2026.5.18; v0.5.4 is still pinned at 2026.5.7 and ships with the transient-issue bubble as the user-facing mitigation. The OpenClaw bump is scheduled for the next Pinchy release. (#338)

Permissions tab no longer reports false-positive dirty state

Section titled “Permissions tab no longer reports false-positive dirty state”

If an Odoo or Email connection was configured on an agent, the Settings → Agent → Permissions tab kept showing "Unsaved changes" and a Save & Restart button after a successful save. The dirty-state check now re-syncs against the persisted state once the post-save refetch lands, so a clean save shows as clean.

New /api/version endpoint + OCI image labels

Section titled “New /api/version endpoint + OCI image labels”

You can now confirm which Pinchy and OpenClaw versions are actually running without opening the UI. GET /api/version returns { pinchyVersion, openclawVersion, build, nodeEnv } and is exempt from Domain Lock so it works from monitoring tools and the host shell. Docker images now also carry standard OCI labels (org.opencontainers.image.version, org.opencontainers.image.revision, …), so docker inspect ghcr.io/heypinchy/pinchy:v0.5.4 reports the version and git SHA the image was built from.

The upgrading guide's "Verify" step is updated to use /api/version instead of opening http://localhost:7777 directly — the old instruction returned 403 on Domain-Lock-enabled deployments.

Startup warning when Domain Lock is set but BETTER_AUTH_URL is unset

Section titled “Startup warning when Domain Lock is set but BETTER_AUTH_URL is unset”

Better Auth's own baseURL autodetection does not read Pinchy's Domain Lock value (verified on a staging v0.5.4 install where Better Auth still logged Base URL could not be determined). On a Domain-Locked deployment, that gap silently sends password-reset and email-verification links pointing at the wrong host.

Pinchy now logs a clear ⚠ Domain Lock is configured (<your-domain>) but BETTER_AUTH_URL is unset… warning on every startup of such a deployment, with the exact env-var assignment to copy-paste into your .env. The existing BETTER_AUTH_URL is set line is retained for the positive case. If you are running with Domain Lock today, check your pinchy container logs after this upgrade and add BETTER_AUTH_URL=https://<your-domain> to /opt/pinchy/.env if the warning appears. (#352)

  • OpenClaw 2026.5.7 (was 2026.5.3) — picked up via Dockerfile.openclaw and the bundled openclaw-node 0.9.0.
  • Next.js 16.2.6 (was 16.2.4) — addresses GHSA-wfc6-r584-vfw7 and GHSA-26hh-7cqf-hhc6.
  • ws 8.20.1 (was 8.20.0) — addresses GHSA-58qx-3vcg-4xpx (uninitialized memory disclosure).

None.

v0.5.3 is a maintenance release focused on chat reliability: the recommended Ollama Cloud reasoning model was swapped after the previous default soft-deprecated upstream, model errors now surface as actionable in-chat bubbles instead of raw HTTP 500s, and the chat layout was restructured so per-agent runtimes survive in-app navigation. File attachments also got a proper preview surface.

Upgrade with the standard flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.2/PINCHY_VERSION=v0.5.3/' .env
docker compose pull && docker compose up -d

No database migration, no docker-compose.yml change, and no env-var changes are required.

Default Ollama Cloud reasoning model swapped

Section titled “Default Ollama Cloud reasoning model swapped”

ollama-cloud/kimi-k2-thinking is removed from the curated model list. The model began returning silent HTTP 500s from Ollama Cloud and is no longer a safe default. Agents that resolve via tier=reasoning now fall through to deepseek-v4-pro, which is already configured and tested.

Existing agents that pinned kimi-k2-thinking explicitly keep loading from the database — but the next request will fail upstream. Open Settings → Agent → Model for each affected agent and pick a working model. The new in-chat error surface (below) makes those agents easy to spot.

When an agent's model call returns a 5xx from the upstream provider, the chat now shows a structured error bubble (<Agent> couldn't respond. + provider/model + a deep-link to the agent's model picker) instead of the raw HTTP 500: "Internal Server Error (ref: …)" string. The original error stays available under a collapsible Technical details section so support requests can still cite the upstream ref ID. Every flip into this error state writes an agent.model_unavailable audit entry.

Per-agent chat runtimes survive in-app navigation

Section titled “Per-agent chat runtimes survive in-app navigation”

Switching between agents in the sidebar no longer tears down and recreates the chat runtime: a new ChatSessionProvider mounts one runtime per agent at the (app) layout level, so streams in-flight on agent A keep running while you read agent B's history. The sidebar shows a subtle pulse on agents with an active turn and a red dot on agents that ended in an error, so background activity is visible without opening every chat.

Existing behavior is preserved on full page reloads: history still rehydrates from OpenClaw, the bundled history cap is now 200 messages, and a transient disconnect bubble shows when the WebSocket drops mid-stream.

Non-image attachments (PDFs and other files) now render as a filename chip in the composer and on sent messages, with the full filename available on hover. Clicking an attachment opens an in-app AttachmentPreview modal with PDF and image preview, instead of forcing a download. The uploads route is now authenticated for both POST and GET, and PDFs/images are routed through OpenClaw's built-in tools rather than inlined.

Chat runs that complete while the user is not actively viewing the agent now emit a chat.background_run_completed audit event with the agent identity, run duration, and turn outcome. This makes background activity auditable without leaking conversation content into the audit log.

None.

v0.5.2 is a maintenance release: a security fix for admin access to personal agents, the long-standing Ollama local-provider setup bug, and several robustness improvements in Settings → Groups.

Upgrade with the standard flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.1/PINCHY_VERSION=v0.5.2/' .env
docker compose pull && docker compose up -d

No database migration, no docker-compose.yml change, and no env-var changes are required.

Security: admin access scope to personal agents

Section titled “Security: admin access scope to personal agents”

Before v0.5.2, an admin could read or modify another user's personal agent by calling GET/PATCH/DELETE /api/agents/:agentId directly, even though the UI did not expose those agents. The admin fast-path in assertAgentAccess now correctly enforces the personal-agent boundary: personal agents are only accessible to their owner, regardless of role. To share an agent with the team, set its visibility to All users (or use a group), which is unaffected by this change.

No action is required on upgrade. If you relied on this behavior in scripts or integrations, switch them to use a shared agent instead.

Ollama local provider works on fresh installs

Section titled “Ollama local provider works on fresh installs”

Setting up a local Ollama provider in the onboarding wizard or Settings → Providers now works without manual .env edits. Pinchy detects local Ollama base URLs (localhost, 127.0.0.1, host.docker.internal) and rewrites them to a Docker-routable hostname (ollama.local, mapped to the host gateway in docker-compose.yml) so the OpenClaw container can reach the model server on the host. The provider config also uses openai-completions with the /v1 suffix, which is what OpenClaw expects for self-hosted OpenAI-compatible endpoints. Existing deployments that already work are unaffected.

Settings → Groups: inline validation, clearer errors

Section titled “Settings → Groups: inline validation, clearer errors”

Group create and edit dialogs now render field-level validation errors inline (matching Pinchy's error-display policy) and surface API failures via toasts instead of leaving the dialog in an ambiguous state. Two-step partial failures — for example, the group is created but the initial member assignment fails — are reported explicitly so you know what to retry.

None.

v0.5.1 is a hotfix release. It fixes a startup loop in OpenClaw caused by a missing baseUrl field in the generated openclaw.json for the Anthropic, OpenAI, and Google providers. Deployments of v0.5.0 that configured any of these providers without setting ANTHROPIC_BASE_URL, OPENAI_BASE_URL, or GOOGLE_BASE_URL env-vars hit a models.providers.<name>.baseUrl: expected string, received undefined error and OpenClaw never came up.

Upgrade with the standard flow:

Terminal window
cd /opt/pinchy
sed -i 's/PINCHY_VERSION=v0.5.0/PINCHY_VERSION=v0.5.1/' .env
docker compose pull && docker compose up -d

No database migration, no config-file change, and no env-var changes are required. Pinchy regenerates openclaw.json on first start with the correct default base URLs, and OpenClaw boots cleanly.

If you previously set ANTHROPIC_BASE_URL (or the OpenAI/Google equivalents) for a proxy deployment, those env-vars continue to override the defaults — no action needed.

None for the standard upgrade path — the new docker-compose.yml you download below already contains the openclaw-secrets tmpfs block needed by the new SecretRef architecture.

If you maintain a custom docker-compose.yml (e.g. for a non-standard deployment, a different orchestrator profile, or a downstream fork), you must add a tmpfs-backed named volume for /openclaw-secrets and mount it into both the pinchy and openclaw services before starting v0.5.0:

services:
pinchy:
volumes:
- openclaw-secrets:/openclaw-secrets
# …rest of the pinchy volumes
openclaw:
volumes:
- openclaw-secrets:/openclaw-secrets
# …rest of the openclaw volumes
volumes:
openclaw-secrets:
driver: local
driver_opts:
type: tmpfs
device: tmpfs
o: "mode=0770,uid=999,gid=999"

The volume must be mounted into both services: Pinchy writes and atomically replaces secrets.json (requires directory write permission — uid=999 grants this as the pinchy system user); OpenClaw reads it. Without this, Pinchy cannot write the secrets file and every agent request fails with an authentication error.

v0.5.0 moves image version pinning from docker-compose.yml into .env. This is a one-time migration — after this, upgrading only means editing PINCHY_VERSION in .env and running docker compose pull && docker compose up -d.

  1. Back up your database (as always):

    Terminal window
    docker compose exec db pg_dump -U pinchy pinchy > backup-$(date +%Y%m%d).sql
  2. Fetch the new docker-compose.yml:

    Terminal window
    cd /opt/pinchy
    curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.5.0/docker-compose.yml -o docker-compose.yml
  3. Add PINCHY_VERSION to your .env:

    Terminal window
    echo "PINCHY_VERSION=v0.5.0" >> /opt/pinchy/.env
  4. Pull and restart:

    Terminal window
    docker compose pull && docker compose up -d

If you skip step 3, docker compose up fails loudly with a clear message telling you exactly what to add — this is by design, so a forgotten pin can't silently pull the wrong version.

Section titled “Recommended: set BETTER_AUTH_URL on HTTPS deployments”

If Pinchy is available on a public HTTPS domain, add the canonical URL to /opt/pinchy/.env before restarting:

Terminal window
BETTER_AUTH_URL=https://pinchy.example.com

The new docker-compose.yml passes this through to the Pinchy container. Better Auth uses it to generate absolute links for password resets, OAuth callbacks, and Telegram pairing redirects. Use the same hostname you lock in Settings → Security, without a trailing slash.

OpenClaw detects the new SecretRef config format and hot-reloads. Telegram channels may be unresponsive for roughly 30 seconds during this reload. They recover automatically — no restart or re-configuration needed.

Before v0.5.0, decrypted API keys were written into openclaw.json on disk. Docker volumes persist across container restarts, which means previous versions of openclaw.json (with decrypted keys inside) may still exist in volume history or backup snapshots taken before v0.5.0. After upgrading, rotate the keys at each provider:

  • Anthropic — Settings → API Keys → revoke old, generate new
  • OpenAI — API Keys → revoke old, generate new
  • Google (Gemini) — Google Cloud Console → API Credentials
  • Ollama Cloud — ollama.com/settings → API Keys
  • Telegram bot — message @BotFather → /revoke/newtoken (only if you suspect exposure; revoking invalidates the previous webhook setup)

Then in Pinchy, go to Settings → Providers and re-enter each new key. Pinchy validates each one against the provider's API before saving. Optionally, delete old volume backups that predate v0.5.0 if you no longer need them.

This is a "nice to do" for most deployments, but if your server was ever compromised or you share volume backups with third parties, treat it as required.

Optional: scan audit logs for historical plaintext

Section titled “Optional: scan audit logs for historical plaintext”

If your compliance requirements demand evidence that no API keys were logged in plain text in your audit trail, run the bundled scan script:

Terminal window
docker compose exec pinchy npx tsx packages/web/scripts/scan-audit-logs-for-plaintext.ts

It checks audit log entries for patterns that look like API keys (Anthropic sk-ant-…, OpenAI sk-…, Google AIza…, Ollama Cloud, Telegram bot tokens). A clean result means your audit trail doesn't contain any key material.

From v0.5.0 onwards, upgrading is just:

Terminal window
# Edit /opt/pinchy/.env → change PINCHY_VERSION to the new tag
docker compose pull && docker compose up -d

The docker-compose.yml only changes when we add new services or volumes, which is rare. Release notes will tell you when a fetch is needed.

  • SecretRef architecture (RAM-only secrets) — API keys no longer touch disk. The openclaw.json config file holds opaque SecretRef pointers; the actual key material lives in a tmpfs volume (/openclaw-secrets/secrets.json) that exists only in RAM and is never persisted. Compliance-friendly default for regulated industries. See Secrets & API Key Storage.

  • Web Search integration — connect Pinchy to the Brave Search API and grant agents per-tool access to search and page fetch. Per-agent filters for domain allow/deny, freshness, language, and region let you scope what each agent can reach. See Set Up Web Search.

  • Gmail integration — connect Google accounts via OAuth and give agents scoped email access: read, create drafts, or send. A guided wizard walks admins through the Google Cloud Console setup. See Connect Email.

  • Per-template model recommendations — agent templates now declare preferred model tiers (fast, balanced, reasoning) and required capabilities (vision, long-context, tools). When creating an agent from a template, Pinchy picks the best match from your installed models automatically.

  • Message delivery status — the chat interface now tracks whether each message reached the agent. A message dims briefly while the network round-trip completes; once the agent acknowledges it, the bubble returns to normal. If delivery fails, a "Couldn't deliver" notice appears.

  • Retry button — when a message fails to deliver, the agent doesn't respond, or a response stream drops mid-way, a Retry button appears directly below the failed message. Pinchy handles the right recovery action automatically — resend, re-trigger, or continue the partial response — depending on what went wrong. See Message Delivery Status & Retry.

  • Chat connection states with auto-recovery — the chat indicator now shows four distinct states (Starting, Ready, Responding, Unavailable) with a 2-second hysteresis that absorbs brief network hiccups. When the agent runtime becomes reachable again after a drop or settings change, Pinchy automatically refreshes the conversation history. See Chat Connection States.

  • Seat-cap enforcement for licensed deployments — Settings → Users now shows current seat usage (active users + pending invites) against the licensed maxUsers cap. The Invite button is disabled when at the cap, and the invite endpoint refuses to issue new invitations with a user.invite_blocked audit entry. License expiry banner refreshes without a page reload.

  • Integration delete with preflight — deleting an integration now shows a dialog with the agent usage count up front. If agents are connected, you can detach-and-delete in one step instead of hunting through every agent. The state machine handles in-flight deletions cleanly so a failed delete doesn't leave orphaned references.

  • Customizing your deployment — new guide documents the supported customization surface: docker-compose.override.yml. Pinchy's docker-compose.yml is owned by the project and replaced on upgrade — overrides go into the override file, which Docker Compose merges automatically and upgrades never touch. See Customizing Your Deployment.

  • OpenClaw runtime updated to 2026.4.27 — the underlying agent runtime gets a significant bump. Notably: spurious gateway restarts on agent-config changes are eliminated (Pinchy now supplements the OpenClaw-managed channels.telegram fields so the runtime sees no diff for Telegram-unrelated changes). The usage poller no longer runs immediately on connect, avoiding a CPU-bound sessions.list scan that was blocking the event loop during startup. No action required on upgrade.

Heads-up: Google template-model realignment

Section titled “Heads-up: Google template-model realignment”

If you create new agents from a template with the Google provider, the balanced tier now picks gemini-2.5-flash instead of gemini-2.5-pro, matching Google's own tier descriptions (Flash is "best price-performance"; Pro is the reasoning tier). The fast tier picks gemini-2.5-flash-lite, and reasoning picks gemini-2.5-pro. Existing agents are unaffected — model IDs are only resolved at agent-creation time and never re-resolved on existing agents.

Standard upgrade — no breaking changes, no new required environment variables.

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.4.4/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d
  • Integrations list no longer blanks out when one row can't be decrypted — if the ENCRYPTION_KEY ever changed (e.g. accidentally overridden via .env), one un-decryptable row in integration_connections silently caused GET /api/integrations to return 500, and the UI fell back to "No integrations configured yet" for every integration — including freshly-added ones that would decrypt fine. Each row is now decrypted in isolation; unreadable rows surface in Settings → Integrations as a warning card with a Delete action so admins can recover without DB access. regenerateOpenClawConfig() got the same per-row isolation, so one broken connection no longer takes down every agent's config.
Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.4.3/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d

Port binding change — action required if you use direct port access

Section titled “Port binding change — action required if you use direct port access”

The default port binding changed from 0.0.0.0:7777 to 127.0.0.1:7777. After upgrading, Pinchy will only accept connections from localhost.

If you have a reverse proxy (Caddy, nginx): No action needed — this is how it should be.

If you access Pinchy directly on port 7777 (no reverse proxy): Add this line to /opt/pinchy/.env to restore the previous behavior:

Terminal window
PINCHY_PORT=0.0.0.0:7777

We strongly recommend setting up a reverse proxy instead. Docker bypasses host firewall rules (UFW), so 0.0.0.0:7777 exposes the port to the internet regardless of your firewall configuration.

Standard upgrade — no breaking changes, no new required environment variables.

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.4.2/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d
  • Pinchy reconnects cleanly after the OpenClaw container is recreated — on upgrades that replaced the OpenClaw container, Pinchy would repeatedly log token_mismatch / token_missing and refuse to connect to the gateway. Root cause: once a device is paired, OpenClaw accepts only the per-device token it issued at pairing, not the gateway bootstrap token from openclaw.json. Pinchy's client library now persists that per-device token alongside the device identity and sends it on reconnect, and discards it automatically if OpenClaw ever rejects it so re-pairing just works. (openclaw-node bumped from 0.3.1 to 0.4.0.)

Standard upgrade — no breaking changes, no new required environment variables.

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.4.1/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d
  • Smithers can read the platform docs again — in every clean v0.4.0 install, Smithers' docs_list and docs_read tools pointed at an empty directory (relative bind-mount in docker-compose.yml resolved to nothing without a co-located source tree). The docs are now baked into the OpenClaw image itself, so this works in every deploy shape.
  • Security patches — transitive-dependency vulnerabilities flagged by osv-scanner were patched.
  • Docs improvements — the Hetzner deploy guide now requires an SSH key at server creation (the old "skip SSH keys" instruction left servers with no login path), and the upgrade guide gained a recovery path for legacy v0.3.0 deployments affected by that gap.

Standard upgrade — no breaking changes, no new required environment variables.

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.4.0/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d

A small number of early Hetzner deployments followed an older version of our guide that said "skip the SSH key." Those servers have no SSH access at all — the upgrade above can't run. Recover access like this:

  1. Reset the root password in Hetzner Cloud

    In the Hetzner Cloud Console, open your server's detail page. In the actions menu (top right, "···"), click Reset Root Password. Hetzner shows a one-time password — copy it.

  2. Log in via the web console

    On the same detail page, click the >_ icon to open a browser terminal. At the login: prompt enter root, then the password from step 1.

  3. Install an SSH key

    If your GitHub account has an SSH key attached (Settings → SSH keys), this is the shortest path:

    Terminal window
    ssh-import-id-gh YOUR_GITHUB_USERNAME

    It fetches every public key on your GitHub profile and writes them to ~/.ssh/authorized_keys with the right permissions.

    No GitHub keys? Create one locally (ssh-keygen -t ed25519) first and upload it to your GitHub account — the command above then works. Manual fallback: mkdir -p ~/.ssh && curl -L github.com/YOUR_USER.keys >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys.

  4. Verify SSH works from your local machine

    Terminal window
    ssh root@YOUR_SERVER_IP

    Once you're in via SSH, proceed with the standard upgrade above.

  • Telegram channels — connect any agent to a Telegram bot. Users link their accounts with a pairing code and chat with agents from their phone. See Set Up Telegram.
  • Odoo ERP integration — give agents scoped, permission-aware access to Odoo with 16 pre-built agent templates. See Connect Odoo.
  • Ollama (local and cloud) — run agents fully air-gapped on your own hardware, or use Ollama Cloud's hosted open-source models. See Set Up Local Ollama and Manage LLM Providers.
  • Usage dashboard improvements — cache-token tracking, source breakdown (chat vs. system vs. plugin), and a background poller that captures OpenClaw usage even for work that doesn't flow through the web UI.
  • Domain lock and insecure-mode banner — lock Pinchy to a canonical HTTPS hostname; a warning banner appears when running without HTTPS on a bound IP/domain. See Lock Pinchy to a Domain.
  • Audit log event status — every audit entry (not just tool calls) now shows success/failure with filterable status. Entries from earlier versions show a neutral placeholder.
  • Disconnect recovery during chat — if the OpenClaw gateway disconnects mid-conversation, Pinchy detects it, tells the user, and recovers automatically when the gateway returns.
  • LLM provider errors surfaced in chat — provider failures (invalid key, rate limit, no credits) now appear as a clear error card in the chat with an admin hint, instead of failing silently.
  • Pre-built Docker images on GHCRdocker compose pull fetches images directly from GHCR (no local build step), making upgrades faster.
  • OpenClaw runtime updated to 2026.4.12.

Standard upgrade — no breaking changes, no new required environment variables.

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.3.0/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d
  • Usage & Cost Stats dashboard — admins can view token usage and estimated costs per agent and per user at /usage.
  • Smart PDF reading — Knowledge Base agents can now extract text from PDFs automatically.
  • Dynamic model selection — the default model is selected from your provider's live model list rather than being hardcoded.
  • Rate limiting on WebSocket connections — protects the gateway from connection floods.
  • Setup password recovery — admins can recover access via the PINCHY_ADMIN_EMAIL environment variable if locked out.
  • Security hardening — timing-safe token validation, fail-closed audit logging.

New optional environment variable: PINCHY_ADMIN_EMAIL

Section titled “New optional environment variable: PINCHY_ADMIN_EMAIL”

If you want to be able to recover admin access via the setup wizard, add this to your .env:

Terminal window
PINCHY_ADMIN_EMAIL=your-admin@example.com

This is optional — Pinchy works fine without it.

This is a docs-only release — no code changes, no database migrations, no breaking changes. Just pull the new tag and rebuild:

Terminal window
curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.2.1/docker-compose.yml -o docker-compose.yml
docker compose pull && docker compose up -d

This section covers what changed and what to expect.

The authentication system was upgraded to Better Auth. Existing login sessions are invalidated during the migration. Passwords are preserved — users just need to log in again.

New environment variable: PINCHY_ENTERPRISE_KEY

Section titled “New environment variable: PINCHY_ENTERPRISE_KEY”

v0.2.0 introduces enterprise features (Groups, RBAC, agent access control). To enable them, set the PINCHY_ENTERPRISE_KEY environment variable in your .env file or docker-compose.yml. This is optional — Pinchy works fine without it, and the key can also be entered via Settings in the UI.

The bundled OpenClaw runtime was updated from 2026.3.7 to 2026.3.13. This happens automatically when you pull the new images with docker compose pull.

Check the Releases page for detailed changelogs and any version-specific upgrade notes.