Development, Architecture, Packaging, and Releases
July 12, 2026 · View on GitHub
Version Sources
The desktop app version has one source of truth: build.zig.zon. Build options
export that value as build_options.app_version, and it drives
wispterm --version, package version.txt output, release notes, and the
command center Version entry.
The WispTerm Remote web console/relay under remote/ is a separate package with
its own version surfaces (remote/package.json, remote/package-lock.json,
remote/src/client/version.ts, and the rendered web label). Do not bump Remote
versions for a desktop-only release.
Building
Windows (PowerShell)
zig build # Debug build for development
zig build -Doptimize=ReleaseFast # ReleaseFast build for distribution
Remove-Item -Recurse -Force .\zig-out, .\.zig-cache -ErrorAction SilentlyContinue
The Makefile may still exist as a convenience wrapper, but normal Windows
development should use PowerShell and direct zig commands. Always use
zig build for development; only use zig build -Doptimize=ReleaseFast for
final/shipping builds.
macOS
zig build macos-app -Dtarget=aarch64-macos # Apple Silicon .app bundle
zig build macos-app -Dtarget=x86_64-macos # Intel .app bundle
open zig-out/bin/WispTerm.app # launch the built app
Requires macOS 13+ and Zig 0.15.2. The build produces a .app bundle at
zig-out/bin/WispTerm.app. For distribution, run the packaging script
(packaging/macos/package.sh) which signs and creates a .dmg.
Zig Toolchain
Use Zig 0.15.2 and make sure zig (or zig.exe on Windows) is available on
PATH. Check the active version:
zig version
On Windows, build.zig defaults to x86_64-windows-gnu, so a normal
development build does not need an explicit -Dtarget. On macOS, pass
-Dtarget=aarch64-macos (Apple Silicon) or -Dtarget=x86_64-macos (Intel)
explicitly.
After a successful Windows debug build, the expected artifact is:
Test-Path .\zig-out\bin\wispterm.exe
Get-Item .\zig-out\bin\wispterm.exe
Tests and structural guards
zig build test # fast inner loop: platform-independent logic (src/test_fast.zig)
zig build test-full # complete pre-merge gate; a SUPERSET of `zig build test`
zig build check-sizes # the file-size backstop on its own
zig build test is sub-second when cached and does not recompile the heavy app
binary; zig build test-full is the gate to run before finishing a change and
now also runs the fast suite.
Architecture is enforced by source-scan ratchet tests under src/source_guards/
(file size, top-level g_* globals, AppWindow import-hub re-exports, and
direct UI dirty-writes). Each freezes today's count so it can only shrink —
adding a new occurrence fails the gate. The cohesion/coupling rationale and the
frozen ceilings are in ../AGENTS.md and
decoupling-guide.md §8.
Why The UI Is Custom Drawn
WispTerm's main terminal UI is intentionally custom drawn instead of composed from raw Win32 controls. The terminal surface, tabs, splits, overlays, background image, shader effects, and theme colors all share one OpenGL rendering pipeline, so they can stay visually consistent and behave like one terminal canvas.
Classic Win32 controls such as SCROLLBAR provide native behavior, but they do
not blend well with WispTerm's dark theme, transparency, background images, and
terminal overlays. They also make layout, DPI, and focus behavior harder to keep
consistent with split panes and custom panels. For the primary terminal
experience, WispTerm prefers platform-aware custom controls over embedding
mismatched native widgets directly.
Resize Benchmark
Use the checked-in resize benchmark when investigating reports that live window
resizing feels slower in one release than another. The script launches a real
WispTerm window, enables WISPTERM_UI_PERF=1, drives repeated Win32
SetWindowPos size changes, and writes JSON plus CSV timing summaries under
zig-out\resize-bench.
zig build
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\benchmark-resize.ps1
To compare two release builds, run the same command against each executable and
compare the generated ui_perf_csv files:
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\benchmark-resize.ps1 `
-ExePath .\zig-out-v0.28.1\bin\wispterm.exe -Label v0.28.1
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\benchmark-resize.ps1 `
-ExePath .\zig-out-v0.29.0\bin\wispterm.exe -Label v0.29.0
Important labels include appwindow.on_win32_resize,
appwindow.resize_compute_split_layout, markdown_preview_renderer.render,
markdown_preview_renderer.table_layout, and
markdown_preview_renderer.table_rows. If resize is only slow while a CSV/TSV
preview is visible, the table preview labels should move with the regression.
For that scenario, add -ManualSetupSeconds 15, open the CSV/TSV preview during
the pause, then let the script run the resize sequence.
Performance Benchmarking
wispterm-bench is the CPU-side benchmark CLI (Ghostty-aligned: mirrors
ghostty-bench's --duration case-runner shape). It links ghostty-vt and
drives a synthetic VT byte stream through the same parser the shipped app uses,
so the number is directly comparable across branches and machines. Build and
run it with:
zig build -Demit-bench -Doptimize=ReleaseFast
.\zig-out\bin\wispterm-bench.exe --list
.\zig-out\bin\wispterm-bench.exe --case terminal-stream --duration 1000
Always pass -Doptimize=ReleaseFast for benchmarks — a debug build is not
representative of real performance. Use --duration <ms> to set the per-case
window (default 1000ms) and --case <name> to run a single case.
The CLI writes a machine-readable benchmark-report-<timestamp>.json and a
paste-ready benchmark-report-<timestamp>.md into the WispTerm config dir
(%APPDATA%\wispterm\ on Windows, ~/Library/Application Support/wispterm/ on
macOS), and prints the Markdown to stdout. Paste that Markdown block into a
Performance Report issue (or a Discussion) so we can compare results across
hardware and renderer backends. The JSON is for tooling/regression tracking.
The bench module's own tests (which link ghostty-vt and so cannot run in the lean fast suite) have their own step:
zig build test-bench
An in-app GPU-side benchmark (wispterm --benchmark) measures per-frame render
latency through the real renderer. It spawns a no-shell virtual surface, drives a
synthetic VT stream from the UI thread with vsync off, and records the
rebuild+draw+present pipeline time per frame as latency_ns (p50/p95/max), then
writes the same JSON + Markdown report shape as the CLI. The renderer backend is
fixed at build time (-Dgpu-backend), so a D3D11-vs-OpenGL comparison is two
builds of the same machine:
zig build -Dgpu-backend=opengl -Doptimize=ReleaseFast
.\zig-out\bin\wispterm.exe --benchmark
zig build -Dgpu-backend=d3d11 -Doptimize=ReleaseFast
.\zig-out\bin\wispterm.exe --benchmark
Each run writes benchmark-report-<timestamp>.{json,md} to the config dir and
prints the Markdown to stdout; diff the two reports' scroll-flood /
unicode-heavy rows to see the per-backend render delta. The report carries the
GPU adapter name + PCI ids, window/DPI/grid size, and runner: in-app so it is
distinguishable from a CLI report.
When publishing a desktop release, run wispterm-bench --case terminal-stream --duration 1000 on the release machine and attach the Markdown report to the
release notes as a regression baseline for that version.
Windows UI Automation
When debugging UI behavior, automate WispTerm as a real visible Windows app from PowerShell. Prefer Win32-driven automation over shell-only assumptions.
Use the checked-in automation script for File Explorer regressions:
zig build
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-file-explorer-ui.ps1
The script launches a real WispTerm window, sets DPI awareness, fixes the window
position and size, captures before/after screenshots, crops the right panel,
sends Ctrl+Shift+Alt+E, performs a region-based pixel check, and writes
screenshots plus JSON metrics under zig-out\ui-test\.
When adding more UI automation, follow the same pattern:
- Wait until
MainWindowHandleis non-zero, callShowWindowandSetForegroundWindow, then click inside the client area before sending keys. - Prefer Win32
keybd_eventorSendInputfor shortcuts;System.Windows.Forms.SendKeyscan silently miss GLFW/terminal windows when focus is not exactly right. - Capture both full-window and cropped target-region screenshots, and inspect the crop when a pixel check fails.
- Always clean up test windows with
CloseMainWindow(), thenStop-Process -Forceif the process remains.
For Windows-native D3D11 Phase IV parity, use the normal-session smoke script against an explicitly built D3D11 executable:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1
The script launches a real visible WispTerm window with an isolated %APPDATA%,
enables render diagnostics plus the D3D11 UI/offscreen probes, switches between
two visible tabs, checks tab text, the + icon, active/inactive row states, and
the close-hover affordance, then toggles the tab sidebar, file explorer, and
command palette. It also generates a high-contrast background image, verifies it
through the initial D3D11 screenshot, opens Markdown and image preview panes
from a temporary File Explorer fixture, opens the Copilot assistant sidebar with
a temporary AI profile, opens the startup shortcuts overlay from the Command
Center, opens the Settings page from the titlebar gear, and opens the Skill
Center from the Command Center. It captures
screenshots, writes JSON metrics under
zig-out\d3d11-normal-session-smoke\, and verifies that
render-diagnostic.log contains gpu-backend=d3d11 present=dxgi, D3D11 init
details for swap effect / adapter / fallback reason / healthy policy state, a
D3D11 environment line for adapter description, vendor/device/subsystem,
revision, memory sizes, output count, feature level, and swap effect, a Win32
environment line for remote session, session id, monitor count, mixed-DPI state,
primary DPI, and system DPI, a
successful d3d11-ui-smoke probe, an offscreen round-trip marker, and no D3D11
recovery request in the healthy path. It is a Phase IV and Phase V
diagnostics/policy/recovery-coordination evidence tool only; it does not change
the Windows default renderer.
Use debug\test-d3d11-environment-smoke.ps1 after a D3D11 build to wrap the
normal-session smoke into a matrix evidence package:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-environment-smoke.ps1
The collector writes zig-out\d3d11-env-smoke\<timestamp>\environment.json, a
redacted matrix-summary.md review artifact, a normal-session\ result
directory, copied screenshots under screenshots\, and the original render
diagnostics path. It records adapter/session/monitor facts and smoke health,
plus a record-only matrix section when -MatrixClass is provided. Use classes
such as local-physical, rdp, virtual-machine, hybrid-gpu,
weak-integrated-gpu, single-monitor, multi-monitor-same-dpi, and
multi-monitor-mixed-dpi; add -RequireMatrixClass only when the class can be
proven from collected facts. The collector does not block environments and does
not change fallback policy. The durable ledger format is documented in
windows-native-d3d11-environment-matrix.md.
After collecting one or more environment packages, run
debug\summarize-d3d11-environment-matrix.ps1 to emit a consolidated
matrix-ledger.md / matrix-ledger.json plus a
matrix-collection-plan.md / matrix-collection-plan.json for PR or issue
review. The collection plan lists remaining non-recorded classes and the exact
collector command to run in each matching environment; it is not evidence and
does not accept missing classes.
To audit the collected Phase V artifacts against the default-migration gate
without rerunning smokes, use debug\audit-d3d11-default-gate.ps1; it emits
default-gate-audit.md / default-gate-audit.json and keeps missing evidence
as missing rather than treating it as a pass. If unavailable environment
classes are explicitly accepted under KNOWN_ISSUES.md heading
Accepted D3D11 Phase V Environment Matrix Gaps, the audit marks those matrix
rows and the environment-ledger gate as accepted while preserving the original
ledger status.
If a shorter soak is explicitly operator-accepted, keep its summary under
zig-out\d3d11-accepted-soak\; the audit marks that gate as accepted so it is
visible and distinct from a completed 20-minute automated soak.
To exercise the controlled Phase V device-recreate path, run the same smoke
with -RecreateSmoke after building the D3D11 executable:
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -RecreateSmoke
This sets WISPTERM_D3D11_RECREATE_SMOKE=1, asks the backend to latch one
recreate-class recovery request, and verifies that diagnostics record the
recreate request, a successful single-shot device/swapchain recreate attempt,
and restored feature resources. It still leaves automatic fallback and the
Windows default backend unchanged.
To exercise the failed-recreate escalation path, run:
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -RecreateFailureSmoke
This sets WISPTERM_D3D11_RECREATE_FAILURE_SMOKE=1, asks the backend to latch
one recreate-class recovery request, injects a synthetic failed recreate, and
verifies that diagnostics escalate it to a recreate_failed fallback candidate
exactly once. The smoke also verifies a version+adapter-scoped
d3d11-fallback marker is written to the isolated smoke profile state file,
that feature resources are not reported as restored after the forced failure,
and that automatic fallback plus the Windows default backend remain unchanged.
To add rapid resize stress evidence to the same D3D11 session smoke, use:
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -RapidResizeSmoke
This drives a burst of real Win32 SetWindowPos changes, restores the window
to the baseline smoke size, captures a post-resize screenshot, and verifies that
the session remains nonblank with D3D11 resize diagnostics and no present/resize
failure lines. It is Phase V hardening evidence only; it does not change the
Windows default backend or fallback policy.
To exercise Win32 window-state transitions on D3D11, run:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -WindowStateSmoke
This drives maximize, restore, minimize, and restore-from-minimize through real Win32 window state APIs, captures screenshots after the visible states, verifies the session returns to the baseline window size, and checks that D3D11 resize diagnostics were emitted without present/resize failure lines. It is a Phase V window-state sub-slice only.
To exercise fullscreen startup on D3D11, run:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -FullscreenStartupSmoke
This writes fullscreen = true into the isolated smoke config, launches through
the real startup fullscreen path, captures a fullscreen screenshot, uses
Alt+Enter to exit fullscreen, restores the baseline window rectangle, and
verifies both visible states are nonblank with D3D11 fullscreen/resize
diagnostics and no present/resize failure lines.
To add a D3D11 long-run soak loop to the normal-session smoke, run:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -SoakMinutes 20
The soak mode keeps the real window active after the initial terminal capture, sends a shell output burst when the shell is recognized, loops tab switches and small Win32 resize/restore cycles for the requested duration, captures periodic screenshots plus a final restored-size screenshot, and verifies the process survives with nonblank frames, D3D11 resize diagnostics, and no present/resize failure lines. It is Phase V reliability evidence only; it does not change the Windows default backend or fallback policy.
The Phase VI default migration gate is documented in
windows-native-d3d11-default-gate.md.
Use it as the checklist for collecting evidence, recording matrix gaps, and
keeping the eventual Windows auto default change small and revertible.
D3D11 fallback is a next-launch policy while the renderer backend remains a
comptime selection. Do not implement same-process D3D11-to-OpenGL switching
without first changing the backend architecture. The d3d11-fallback state-file
marker is separate from the older OpenGL+DXGI present d3d-bringup fuse,
scoped by app version and adapter identity, and currently feeds only tests and
future-auto dry-run decisions. Explicit d3d11 must ignore a matching marker
except for diagnostics; current Windows auto still resolves to OpenGL.
To exercise the marker path without changing selection, run:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -FallbackMarkerSmoke
This sets WISPTERM_D3D11_FALLBACK_MARKER_SMOKE=1, writes a synthetic
version+adapter-scoped d3d11-fallback marker into the smoke profile's isolated
state file, verifies explicit d3d11 still wins with a warning-class decision,
verifies current Windows auto remains OpenGL, and verifies a future-auto
dry-run would select OpenGL from the marker. It does not enable live failure
writes or automatic fallback.
To record the future-auto selector dry-run surface without writing a marker, run:
zig build -Dgpu-backend=d3d11
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -AutoDryRunSmoke
This sets WISPTERM_D3D11_AUTO_DRY_RUN_SMOKE=1 and verifies diagnostics for
current Windows auto staying OpenGL, future Windows auto selecting D3D11
when eligible, future-auto selecting OpenGL from a matching marker, explicit
d3d11 ignoring a matching marker with warning semantics, explicit opengl
remaining OpenGL, and stale markers being ignored. It does not change the
Windows default backend, write a fallback marker, or trigger automatic fallback.
To prove the Windows OpenGL fallback path still runs the same normal-session UI subset on the native-render branch, build the default backend and run:
zig build
powershell -NoProfile -ExecutionPolicy Bypass -File .\debug\test-d3d11-normal-session.ps1 -Backend opengl
This reuses the normal-session screenshot workflow for tab chrome, sidebar,
file explorer, Markdown/image previews, assistant panel, command palette,
startup shortcuts, Settings, Skill Center, and background image rendering, but
expects gpu-backend=opengl diagnostics instead of D3D11 probes. It also
verifies that no D3D11 recovery, fallback-marker, UI-probe, or offscreen-smoke
markers fire in the OpenGL fallback session.
macOS UI Smoke Tests
macOS UI debugging is native-target first. Unless a task explicitly asks for
Intel validation, run the native host tests rather than x86_64-macos:
zig build test-macos-ui
The step runs in-process AppKit/overlay smoke tests for macOS-only debugging:
Ctrl+Shift+B toggles the tab sidebar, the Command Center filters and executes
the Settings command, and the Settings page writes to an isolated test config
file. The test intentionally avoids external keyboard/screenshot automation so
it does not depend on macOS Accessibility or Screen Recording permissions.
For the Metal-backend and AppKit-host gotchas surfaced during the macOS port
(deferred MTLBuffer semantics, NSMenu vs. keyDown interception, Zig 0.15
module-path constraints on cross-backend imports, IME swallowing letter keys,
etc.) see macos-ui-lessons.md. Read this before
touching anything under src/renderer/gpu/metal/ or src/platform/*_macos*.
Windows Checkout Safety
This repository must remain safe to check out and develop on Windows. Before finishing changes that add, remove, rename, or move files, check for Windows-incompatible paths:
$paths = git ls-files
$reserved = @('CON', 'PRN', 'AUX', 'NUL') + (1..9 | ForEach-Object { "COM$_"; "LPT$_" })
$violations = [System.Collections.Generic.List[object]]::new()
$collisions = [System.Collections.Generic.List[object]]::new()
$seen = @{}
foreach ($path in $paths) {
foreach ($part in ($path -split '/')) {
$stem = ($part -split '\.')[0].ToUpperInvariant()
$reasons = @()
if ($part.IndexOfAny([char[]]'<>:"\|?*') -ge 0) { $reasons += 'illegal_char' }
if ($part.EndsWith(' ') -or $part.EndsWith('.')) { $reasons += 'trailing_space_or_dot' }
if ($reserved -contains $stem) { $reasons += 'reserved_name' }
if ($reasons.Count -gt 0) {
$violations.Add([pscustomobject]@{ Path = $path; Part = $part; Reasons = ($reasons -join ',') })
}
}
$key = $path.ToLowerInvariant()
if ($seen.ContainsKey($key) -and $seen[$key] -ne $path) {
$collisions.Add([pscustomobject]@{ A = $seen[$key]; B = $path })
} else {
$seen[$key] = $path
}
}
"tracked_files=$($paths.Count)"
"windows_name_violations=$($violations.Count)"
$violations | ForEach-Object { "violation`t$($_.Path)`t$($_.Part)`t$($_.Reasons)" }
"casefold_collisions=$($collisions.Count)"
$collisions | ForEach-Object { "collision`t$($_.A)`t$($_.B)" }
$longest = $paths | Sort-Object Length -Descending | Select-Object -First 1
"max_path_length=$($longest.Length) $longest"
Also check for symlinks, which are often painful on Windows checkouts:
git ls-files -s | Select-String '^120000'
Rules of thumb:
- Do not introduce files whose names differ only by case. Windows checkout is case-insensitive by default.
- Avoid Windows-reserved names (
CON,PRN,AUX,NUL,COM1-COM9,LPT1-LPT9) in any path segment, even with extensions. - Avoid characters illegal on Windows:
< > : " \ | ? *. - Avoid trailing spaces or trailing dots in any path segment.
- Keep paths reasonably short. Current longest tracked path is expected to be well below Windows path limits.
Windows SSH/SCP Compatibility
When changing SSH/SCP code paths (src/ssh/scp.zig, SSH clipboard image paste,
remote file explorer listing/upload/download, or SSH session metadata), test
against the existing real SSH profile in %APPDATA%\wispterm\ssh_hosts whenever
it is available. The profile fields are hex encoded as
name, host, user, password, port, proxy_jump, auth_method, identity_file;
decode them locally for the test, but never print or commit passwords or private
key material. At minimum, verify:
ssh.exe ... user@host pwd
scp.exe ... local-file user@host:/tmp/test-file
ssh.exe -T ... user@host "cat > '/tmp/test-file'" # only if testing the stream fallback
Do not add OpenSSH connection sharing (ControlMaster, ControlPersist,
ControlPath) to helper ssh.exe or scp.exe commands on Windows. Windows
OpenSSH does not provide the Unix-domain socket behavior those options expect
here; it reproduces as getsockname failed: Not a socket,
Read from remote host ...: Unknown error, scp.exe: Connection closed, or
lost connection. This broke SCP uploads even though the same profile and
remote service worked without those options.
Keep stderr visible for helper ssh.exe/scp.exe failures. Do not reduce
failures to a generic "SSH image upload failed"; preserve the underlying
OpenSSH error so regressions can be diagnosed without guessing.
Packaging
Windows
WispTerm supports three portable Windows packages:
portable- default OpenGL portable build, run directly without installationportable-compat- OpenGL portable build for older Windows 10 machines:WebView2Loader.dllfor the embedded browser plus a bundled modern ConPTY (conpty.dll+OpenConsole.exe) so TUI apps like Codex get mouse scrolling and scrollbars on old inbox conhostsportable-native-d3d11- Windows native D3D11 feedback build; use the defaultportablepackage if it shows rendering issues
Build the artifacts with:
powershell -ExecutionPolicy Bypass -File .\packaging\windows\package.ps1
Key outputs include:
zig-out\dist\portable\wispterm.exe
zig-out\dist\portable\version.txt
zig-out\dist\portable\plugins\...
zig-out\dist\portable-compat\wispterm.exe
zig-out\dist\portable-compat\WebView2Loader.dll
zig-out\dist\portable-compat\conpty.dll
zig-out\dist\portable-compat\OpenConsole.exe
zig-out\dist\portable-compat\version.txt
zig-out\dist\portable-compat\plugins\...
zig-out\dist\portable-native-d3d11\wispterm.exe
zig-out\dist\portable-native-d3d11\version.txt
zig-out\dist\portable-native-d3d11\plugins\...
The portable app can add or remove its native Start menu shortcut and enable or disable login startup from Settings. These actions use Windows shell APIs directly; no installer, PowerShell child process, or administrator rights are required.
macOS
Build a signed .dmg image locally (ad-hoc signing) with:
zig build macos-dist -Dtarget=aarch64-macos # Apple Silicon
zig build macos-dist -Dtarget=x86_64-macos # Intel
Key output:
zig-out/dist/macos/wispterm-macos-vX.Y.Z.dmg
For release signing and notarization, set WISPTERM_MACOS_SIGN_IDENTITY and
WISPTERM_MACOS_NOTARY_PROFILE before running the same command. See
packaging/macos/README.md for full signing and notarization instructions.
GitHub Releases
Several GitHub Actions workflows publish release assets whenever a tag matching
vX.Y.Z is pushed:
.github/workflows/windows-release.yml— Windows packages and the diagnostic build.github/workflows/macos-release.yml— Apple Silicon macOS DMG (signed and notarized).github/workflows/macos-release-x86_64.yml— Intel macOS DMG, triggered automatically after the Apple Silicon release workflow succeeds.github/workflows/linux-release.yml— experimental Linux x86_64 AppImage.github/workflows/wisptermctl-release.yml— standalonewisptermctlCLI bundle for all desktop platforms
Windows assets (per tagged release):
wispterm-windows-portable-vX.Y.Z.zipwispterm-windows-portable-compat-vX.Y.Z.zipwispterm-windows-portable-native-d3d11-vX.Y.Z.zipwispterm-windows-debug-vX.Y.Z.zip
When WispTerm detects a newer release on Windows, it downloads the matching portable zip to the Downloads folder and reveals it in Explorer; unzip it over your existing install to update.
WispTerm does not build or publish a Windows installer. Use the default portable
zip release asset; the portable-compat zip when using the embedded browser panel
or on older Windows 10 machines (its bundled ConPTY restores TUI mouse support);
or the portable-native-d3d11 zip when intentionally testing the Windows native
D3D11 renderer. If the native D3D11 package shows a black window, crash, missing
UI, resize failure, RDP issue, or multi-monitor/DPI issue, switch back to the
default portable package and include diagnostics in the bug report. The bundled
ConPTY is preferred automatically when its files sit next to wispterm.exe; set
windows-conpty = system in the config to force the OS inbox ConPTY.
macOS assets (per tagged release):
wispterm-macos-aarch64-vX.Y.Z.dmg— Apple Siliconwispterm-macos-x86_64-vX.Y.Z.dmg— Intel
Both DMGs are signed with a Developer ID Application certificate and notarized
by Apple. Open the DMG and drag WispTerm.app to Applications to install.
Linux asset (per tagged release):
WispTerm-X.Y.Z-x86_64.AppImage— experimental x86_64 Linux build that bundles SDL3. It is published for community testing and is not yet considered stable.
CLI asset (per tagged release):
wisptermctl-vX.Y.Z.zip— standalone agent terminal-control CLI builds for Linux x86_64/aarch64, macOS Intel/Apple Silicon, and Windows x86_64.
Release notes are checked in under release-notes/vX.Y.Z.md when a release
needs curated notes. If a matching file is present, the workflow prepends it to
the GitHub release body; otherwise GitHub generated notes are used with the
asset summary.