August 2026
QOps 3.0.11 ships with Portal 1.0.1.
Three things change how the product feels. QOps and the Portal now run on macOS and Linux, not only on Windows. Panels in the Portal dock beside each other instead of covering the screen you were working on. And a long operation is no longer killed for being long. There is also a new cmdlet, QOps-SetUpdateChannel, which decides which build a machine updates from.
QOps and the Portal now run on macOS and Linux
Previous releases were Windows-only in practice, and failed in different ways on each of the other two platforms. On macOS every cmdlet threw PlatformNotSupportedException before doing anything (QOPS-364), and QOps-StartPortal failed with Exec format error because the package carried a Linux binary only (QOPS-379). On Linux the Portal started but served no interface at all: Portal.zip unpacked flat, so there was no wwwroot for the UI and no docs for the Help panel (QOPS-382). On both, every repository screen answered a 500 unless the Portal ran as root, because QOps kept its Portal data in a system directory (QOPS-389).
All of that is fixed. The full flow — QOps-SetLicense, QOps-SetConfig, adding a repository, Prepare, Build, Publish, Reload and Release — works on macOS and Linux against both Qlik Cloud and Qlik Sense on-prem, and QOps-StartPortal brings up the Portal with its interface and its Help. Related fixes in the same area:
-
QOps-Update -Force works off Windows (QOPS-372), and an update installs into the folder
pwshactually searches. On macOS the path was being built as~/Library/Application Support, so an update could report success and leave the old module in place (QOPS-392). -
The browser opens once the Portal is listening, rather than being handed the URL while the port is still dead and showing “cannot open the page” for a Portal that is starting perfectly well (QOPS-394).
macOS now has an installer of its own: QOps-3.0.11-macos-arm64.pkg, for Apple silicon. It puts the module where pwsh looks for it and the Portal beside it, inside your home folder, with no administrator password.
Starting it takes one step in the Terminal, and the reason is worth stating rather than leaving to be discovered: the package carries no Apple Developer ID signature, so Gatekeeper refuses a plain double-click on a file that arrived through a browser. Either clear the download flag first and then double-click, or install without opening Finder at all.
xattr -d com.apple.quarantine QOps-3.0.11-macos-arm64.pkg # then double-click
installer -pkg QOps-3.0.11-macos-arm64.pkg -target CurrentUserHomeDirectory
Both routes install the same thing. The refusal is what an unsigned package looks like, not a damaged download, and the console step goes away once the package is signed (QOPS-406).
If an older QOps is already on a Mac, install the package rather than running QOps-Update: no release before 3.0.11 can execute a cmdlet on macOS (QOPS-364), and no package built before it carries the Mac build of the Portal (QOPS-379). From 3.0.11 on, QOps-Update keeps a Mac current like any other machine.
One limitation remains on macOS, named here rather than left to be discovered:
-
Licensing another user throws (QOPS-374).
QOps-SetLicense <key>for yourself works; passing-User <someone-else>raisesNotSupportedException, and the same applies toQOps-ActivateandQOps-Deactivate. Single-user setup — the normal case — is unaffected.
The Portal workspace
-
Panels dock instead of taking over the screen. Diff opens as a right-hand panel next to Git rather than a separate screen (QOPS-299); Logs dock to the right of Operations so you watch the stream while it runs (QOPS-300), and below Studio when height is what you need (QOPS-303). Search in Studio is a docked panel instead of an overlay that closed on every click (QOPS-301). Two bottom panels sit side by side, and fall back to tabs on a narrow window without losing either (QOPS-333).
-
Choose a repository folder instead of typing its path. The picker browses the machine, validates as you go, and distinguishes three kinds of folder — a QOps repository, a plain Git repository, and one already added — rather than calling everything “repo” (QOPS-316, QOPS-323, QOPS-325).
-
Editor tabs tell files apart. Two files with the same name now show enough of their folder to distinguish them (QOPS-322).
-
Versions are visible from inside the Portal. The QOps version sits in the status bar, and the badge at the right of the header opens a panel showing the Portal and the installed QOps module together, wired to
QOps-Update(QOPS-324).
Operations you can trust
-
A long operation is no longer killed for being long. Release was being killed at 6.5 minutes for one app and 11 for two — and the estimate behind that limit averaged only runs that completed, so the runs it had just killed never entered the history and it never learned they needed longer. The estimate now learns from real durations (QOPS-318), and passing it produces a warning plus a Stop button rather than a kill — the decision is yours (QOPS-362).
-
The Stop button survives leaving the panel. Going Operations → Logs → Operations while something was running lost the “Operation in progress” card and the Stop button with it: output kept streaming and history kept its spinner, so the panel showed a running operation it gave you no way to stop. The card now comes back, with its estimate and an elapsed counter that continues from when the operation started instead of restarting at zero (QOPS-368).
-
Git commands are serialised per repository. Nothing stopped two git commands running in the same work tree at once, while the interface polled git every five seconds. That is where the
.git/index.lockfailures came from. Commands in one repository now run one at a time, and when a lock does appear the message says what it can still mean (QOPS-319). -
Git is faster. A checkout used to start nine separate PowerShell processes at roughly 400 ms each; simple git commands now run directly (QOPS-317).
-
History records what actually ran. It used to say “All apps” based on the state of the checkboxes rather than on what the operation targeted (QOPS-309).
-
Output stays with its repository. A finished operation’s output no longer leaks into another repository’s panel (QOPS-305).
-
Saving in the editor refreshes the documentation for every app you touched, not just the last one (QOPS-304).
-
Log wording and colouring corrected — “error” that was not an error, and colours that did not match severity (QOPS-311, QOPS-330).
Choosing which build you update from — new cmdlet QOps-SetUpdateChannel
QOps-Update could reach exactly two builds: stable, and -Beta for staging. Every other published channel was unreachable. There are now two ways to name one, and the difference between them is the whole point:
QOps-Update -Channel staging-mcp # install from that channel, THIS RUN only
QOps-SetUpdateChannel staging-mcp # switch this machine to it, until you set it again
QOps-SetUpdateChannel main # back to the supported 3.x line
QOps-SetUpdateChannel is a cmdlet of its own rather than another flag on QOps-Update, because in QOps a flag means “for this run”. Once set, every update follows that channel, including the daily automatic one. The choice belongs to the machine — which build of QOps you are running — and not to a profile, which is about which Qlik you point at, so it is stored beside the other per-machine update markers rather than in a config profile.
-Beta keeps the meaning it always had: staging for one run, with no lasting effect. It will not drag a machine you switched on purpose back to staging — on such a machine, ask for staging by name (-Channel staging). Every update logs the channel it used and where that came from: asked for this run, set on this machine, -Beta, or the default.
Two names are special. ‘main’ means the supported 3.x line. The 2.x builds are published to a branch literally called main, so the most natural word to type would have dropped an up-to-date install back onto the frozen line. That downgrade now has to be asked for by name, as ‘main-2.x’, and asking warns you that the channel is frozen and stops serving updates and fixes on 2027-02-01. An installed 2.x keeps working — only the updates end (QOPS-378).
Going back to 2.x is not a supported path, and one thing about it is worth knowing before you try it: 3.x writes its config as YAML, 2.x reads JSON only, so every 2.x command afterwards fails with Unexpected character encountered while parsing value: A — a message that names neither the file nor the format. Delete the .qopsconfig files (the repository’s, and the one in %USERPROFILE%\qopsconfig, keeping license.key beside it) and 2.x writes itself a fresh one.
Reliability
-
Errors reach the Logs panel. The step that labels output matched the stream name in the wrong case, so every PowerShell error record was dropped on its way to the Portal — a command that failed looked like one that printed nothing. All platforms (QOPS-393).
-
The Portal no longer freezes after a few pages of logging.
QOps-StartPortalcaptured the Portal’s output and then never read it, so once roughly 64 KB had built up the Portal blocked on its next log write and stayed blocked — and the log went nowhere, which is why a misbehaving Portal was so hard to diagnose. Its output is now read and kept in the Portal’s log file, and a failed request names the error, its cause, and an id matching the entry in that log instead of answering with one fixed sentence (QOPS-395). -
The Portal sees a module installed outside PowerShell’s default path.
QOps-StartPortalhad always passed that location on and nothing read it, so one health endpoint reported QOps available and the other reported it missing. Both now report the same module, and when it genuinely is not found they say why and list the paths searched (QOPS-390, QOPS-391, QOPS-400). -
Git commands no longer hang for 15 seconds: the child process inherited the host’s stdin and waited on a pipe nobody was writing to (QOPS-337).
-
No more spurious 403 on Build. The thumbnail step attempted an empty thumbnail and logged a permission warning for something it should not have tried (QOPS-215).