Windshift 0.9.0
Released 20 October 2026. Published as tag v0.9.0 on GitHub and as ghcr.io/windshiftapp/windshift:v0.9.0. Binaries and the macOS app are on the download page.
Windshift 0.9.0 makes the helpdesk a first-class part of the product. Service levels arrive with metrics, goals, and working calendars. The support queue becomes a configurable workspace view with live counts and bulk actions. Email intake is rebuilt around separate mailbox connections and routing. Tickets can be merged and split, and portal customers can share requests across their organisation.
The release also adds customer data export and retention-aware erasure, turns incidents into work-item state, marks AI chat changes in history, moves workspace bundles and packs between instances, makes navigation configurable, and speeds up large installations. Five rounds of release bug hunting also closed a number of security issues before they shipped.
Service levels
Service levels are here. Every item is evaluated as it changes, so SLA cycles start, pause, and stop immediately, and breaches and warnings are delivered through Windshift's event system.
Workspace admins configure metrics, conditions, and goals under Service levels, using Windshift's query language with validation at save time. Goals can be grouped by priority, and working calendars define timezone, weekly hours, and holidays. Calendar changes preview their impact, and a running cycle keeps the calendar it started with, so recalculation never rewrites history. Teams bind to workspaces, and coverage gaps surface when a team's hours do not line up. Warning thresholds, pause, stop, and start rules, and on-demand recalculation complete the admin surface.
Items show an SLA panel, lists and boards carry SLA indicators, and a compliance report summarizes completed, breached, and average cycles. SLA triggers and events work in automations and notifications, and the configuration is available through API v2 and the ws CLI. Jira SLA configuration and cycles import directly.
The support desk comes together
Support queues become a real workspace view. Queues are scope-aware and configurable: build them with a query-language filter builder, route by collection, choose which columns show, and see live counts for unassigned, team-owned, and waiting tickets. Bulk actions are supported, and the queue is a toggleable navigation entry rather than a fixed tab.
Agents get canned responses to insert into replies, helpdesk triggers and customer actions in the automation editor, and a customer context sidebar on external requests. Request participants appear only on external requests, and comments and attachments can be marked internal so they never reach a customer.
Support metrics arrive as dashboard and workspace widgets: first response, resolution time, reopen rate, volume, backlog trend, and SLA compliance. First response counts the first public agent comment, and resolution time is recorded once, on first close. A built-in helpdesk pack provisions the whole configuration in one apply. Zammad users also get a support overview with ticket history and status counts (@Optic00, #306).
Email intake, redesigned
Email channels are split into two clear concepts. A mailbox is a connection: inbound address and IMAP or OAuth credentials, with no routing or target. An intake is a feed from a folder on a mailbox that turns new mail into items in one workspace (or a portal), with its own item type, request type, rate limit, and processing rules. Credentials belong to the connection, and permissions are checked against both the mailbox and the target. The SMTP AUTH mechanism is selectable per channel, so servers that only offer LOGIN or CRAM-MD5 work without a global override (@m0nt0).
The email and portal conversation loop is closed. A portal submission can email the customer, the customer's reply threads back onto the same ticket, and a new email from someone with open tickets no longer creates a duplicate. The outbound reply queue is visible and operable: retry a stuck reply, discard one that should not send, and watch pending and exhausted counts in the metrics. A per-sender hourly cap holds floods instead of dropping them, and operators can requeue limited mail after raising the limit. An intake can send an optional submission receipt and link the resulting request into the portal.
Reply routing, threading, and reply authorization were reworked, and OAuth callbacks are bound to the account that started the flow, so a forwarded authorization URL can no longer attach someone else's provider credentials to your identity (WI-1641).
Ticket merge and split
Tickets can be merged into a canonical one and split into a subticket. Merging moves comments, attachments, links, watchers, email threading, and pending replies, refuses to orphan subtickets, and marks comments private when requesters differ so one customer never sees another's content. The duplicate remains as a read-only redirect to the canonical ticket. Splitting creates a child ticket from selected comments and attachments with an explicit assignee and requester, with no silent inheritance. Both operations appear in the audit trail like any other change.
Ticket imports improved too. CSV ticket import is available with asset-set portal access, and the Jira import can map onto existing entities interactively instead of only creating new ones. Imported customers record their provenance, and search uses Jira's enhanced JQL API (GH #301).
A portal customers can share
Portal customers belong to organisations, and 0.9.0 gives those organisations a real visibility model. Global admins define contact levels, each organisation chooses who may see shared requests and who decides sharing, and requests can be shared individually, shared automatically, or not shared. The creator and explicit participants always keep access, and shared viewers can participate. Cross-organisation isolation applies to both lists and individual requests, so guessing an ID fails the same way as leaving it out. Customer management appears in navigation as soon as a portal exists.
The customer data lifecycle is much more complete. Auto-created customers record their origin and can be cleaned up in bulk, and a customer can be deactivated for security. Article 15 and 20 data export ships for portal customers, erasure respects retention rules and records DSAR evidence, and background jobs clean up expired portal credentials and knowledge-base events. Requests support attachments and reply notifications, and asset reports can prefill a request type from row actions.
Incidents and on-call
Incidents are now work items with a dedicated team field, so they live in the same views, permissions, and history as everything else. Acknowledge, unacknowledge, and resolve handle concurrent updates safely, and unacknowledging restarts escalation from the current step.
AI you can audit
When the AI chat changes an item, the history entry records it, including the model and cost behind the change (@valentimarco). Chat turns are metered like other provider calls, "catch me up" now includes parent and sub-item context, and the item AI actions menu has a new icon. Agent readiness errors now render properly and point at the permission grants that fix them. OpenCode Go joins the native LLM providers.
Also in 0.9.0
- Workspace bundles, config sets, and packs. Whole workspaces can be exported as bundles and imported into another instance, including their configuration sets, with a conformance check that reports drift and can repair it. Configuration-set templates carry link types, imported config sets are adopted rather than duplicated, and a failed pack apply rolls back instead of leaving a half-provisioned workspace. Framework packs get a manifest and apply flow, and the built-in helpdesk pack ships with the release.
- Navigation you control. A new navigation configuration view lets workspaces and global collections choose what appears in their sidebar and in what order, with per-scope visibility toggles. The support queue is a toggleable entry, workspace-only tools stay hidden where they do not apply, and saved settings carry over cleanly as the toggleable set grows.
- Delegated administration and restricted workspaces. Management surfaces for non-system-admins, such as channel management and asset sets, move behind a delegated admin area that appears only when the user holds a delegated capability. Workspaces can be created with visibility restricted to the creator, and the admin directory gains a Visibility column so the setting is discoverable.
- Collections are shared by default. Collections are now visible to the people who can see their items: workspace members for workspace-linked collections, every authenticated user for global collections, with an owner-only Private opt-out. Marking a collection private also unpublishes its public board.
- A portal knowledge base. A channel manager can publish a workspace's Pages tree, either the whole workspace or a sub-page subtree, into a portal's knowledge base. Published articles get deep-linkable routes and a browse listing, agents can insert knowledge-page links into replies, and the portal resolves those links only for pages it publishes. Usage is recorded for reporting.
- Helpdesk operations. New Prometheus metrics expose outbox depth, the age of the oldest queued reply, exhausted replies, rate-limited intake, and poll errors, with a runbook covering setup, mailbox and outbox recovery, and SLA operations. The audit trail records merge, split, assignment, bulk-update, agent-reply, automation-run, and knowledge-base publish decisions, and automation comments no longer re-trigger the rule that created them.
- @mention emails. Mentioning someone in a comment sends a dedicated email that carries the comment body, so a teammate can act on the mention without opening Windshift (WI-1726).
- One work-item modal. Opening an item from a list, board, dashboard, notification, or link now uses a single global modal with built-in create and edit screens, so navigation is consistent and the URL stays shareable (@danielraab).
- A better work-item list. Shared column configuration for list and tree views, story points and estimates editable inline, a status picker in item details and linked items, and a command palette that understands external links (@danielraab, #325, #331).
- Dashboard and diagnostics. Dashboard items open in the work-item modal as real links, watched feeds follow item activity, the daily briefing reports generation health, and the What's New and Your Activity widgets use the standard work-item card.
- Jira import, hardened. Interactive mapping onto existing entities, enhanced-JQL search, ADF rich-text custom fields rendered as Markdown, paginated Data Center bulk fetches, and resumable imports so an interrupted import continues instead of duplicating.
Performance and polish
Faster with every workspace
Pages load only what they show. The workspace directory pages on the server, admin and settings lists are bounded, picker options are capped, comment threads render a window instead of the whole history, test-case rows load as you scroll, and time tabs load on activation. Worklog reports aggregate on the server, asset-type fields load concurrently, and item detail loads its references, assignees, teams, and milestone options once per open.
Live updates are pushed instead of polled. An open board refreshes when something changes rather than on a timer, and reconnecting reconciles once without duplicating the initial load. Idle import and issue-sync polling was reduced.
Security
Several rounds of bug hunting closed issues before release. OAuth callbacks for user integrations and source control are bound to the account that started them. Child-item reads through the AI tools, REST v1 and v2, and the detail service are scoped to the caller's accessible workspaces, and cross-workspace hierarchy reads are filtered to items the caller can view. Concurrent event streams are capped per user, portal approver access respects served-workspace scope, support-metric segments the caller cannot view are dropped, and discarded replies erase recipient identity. On-call escalation policies and their targets are scoped to the owning team, importing view settings or SLAs requires workspace admin, making a collection private unpublishes its public board, removing a participant revokes their thread reply access, and internal Jira Service Management attachments stay hidden from portal customers. Security libraries were updated, and the responsible-disclosure guide from 0.8.9 remains the place to send findings.
Bug fixes
- Business-time arithmetic now handles DST gaps, skipped midnights, and duplicate holidays, and counts DST transitions in the trailing partial week correctly.
- Removing a mention from a comment cancels its queued email, and editing a comment no longer delivers the pre-edit body.
- GitHub pull requests are correctly treated as merged (@spatialy).
wsaccepts bothcanceledandcancelledfor milestone status flags (@spatialy).- Safe reads rejected by the per-user concurrency limit are retried with backoff instead of failing, so boards and pickers no longer break under request bursts (@dpb97).
- Empty list responses encode as
[]instead ofnull, and canceled requests report as client aborts rather than 500s. - Item detail reloads when the key's workspace route changes, and stale loads no longer break SPA navigation.
- Boards and collections resolve workspaces beyond the cached directory page, and the workspace picker is limited to administered connected workspaces.
- Merged duplicates are hidden from portal lists for the same requester and render as read-only redirects.
- Custom-field rows are unified in the item detail sidebar, whitespace-only descriptions count as blank for required fields, multiselect custom fields stay arrays on create, and linking custom fields stay off create screens.
- Merging enforces the cycle guard against the current parent chain, and SLA badges refresh when they become visible.
- Comment privacy is enforced in automations, and the insert-canned-response and notify-customer actions re-check permissions at run time.
- Email intake deduplication is scoped to the intake folder, keeps deleted tickets deduplicated, and no longer duplicates a sender who already has open tickets.
- Jira imports retain datetime precision, preserve partial comment and worklog fetches, fork comments and attachments on a workspace-changing reimport, and render ADF rich text as Markdown.
Upgrade and compatibility
- Windshift 0.9.0 requires the recorded
0.8.5schema checkpoint. Installations older than 0.8.5 must upgrade to 0.8.5 or 0.8.5-2 first, back up the database, and allow that release to start successfully and record the checkpoint before installing 0.9.0. - Installations already running 0.8.5, 0.8.5-2, 0.8.6, 0.8.7, or a later 0.8.x release can upgrade directly. Direct upgrades from 0.8.4 or earlier are not supported.
Email intake
Existing inbound email channels are migrated automatically: each becomes a mailbox connection plus one intake on its configured folder, preserving workspace or portal routing, item type, rate limit, and processing rules. Nothing needs to be re-entered. If a channel relied on the legacy fallback, review your intakes: a disabled intake now stops processing instead of falling back to the old channel configuration.
Collections are shared by default
Collections used to be visible only to their creator unless marked public. 0.9.0 flips the default: workspace-linked collections are visible to members with item.view, and global collections to every authenticated user. Existing collections are migrated to the shared default; owners can switch one back to Private in the editor. Public (unauthenticated) boards still require an explicit public flag, and making a collection private unpublishes its board.
Attachments and private comments
Attachments can be marked internal and comments private; internal content is hidden from portal customers. This is also applied to Jira Service Management attachments on import.
Service levels
Service levels require no manual migration. Workspace admins configure metrics, conditions, goals, working calendars, and team bindings under Service levels, and Jira SLA configuration and cycles can be imported. The built-in helpdesk pack provisions a working helpdesk configuration in one apply.
Thank you
Thank you to Ben (@Optic00) for the Zammad observability work and security patches, to @valentimarco for AI chat provenance and metering, to Yulian (@spatialy) for the GitHub and milestone fixes, to Daniel (@danielraab) for the work-item list, modal, and command palette improvements, to Dominik (@dpb97) for the concurrency-limit retry fix, and to Pietro (@m0nt0) for per-channel SMTP AUTH. Thanks also to everyone who took the time to report issues and test the release candidates.