Witty is a Windows-native host shell for the libghostty terminal core.
This repository currently contains:
- Win32 application shell and message loop.
- ConPTY process lifecycle, resize, input, output reader thread, cleanup, and a CTest smoke that verifies child output through the pseudoconsole.
- A terminal model boundary that prefers
ghostty-vt.dllwhen present and falls back to a small VT model when it is not. - Tabs, split panes, per-pane ConPTY sessions, command palette, settings overlay, theme/font controls, scrollback viewing, selected/visible text copy, normalized paste, and client-owned window chrome.
- DirectWrite font measurement and runtime font switching.
- Direct3D11/DXGI-backed Direct2D rendering with DPI-correct cell metrics, SGR cell colors, full cell text payloads for DirectWrite shaping, custom chrome, tabs, panes, overlays, selection highlighting, and renderer smoke coverage.
- CMake, CTest, CPack ZIP packaging, and Windows CI scaffolding.
Requirements:
- Windows 10 or newer.
- Visual Studio 2022 Build Tools with the Desktop C++ workload.
- CMake 3.24 or newer.
cmake --preset vs2026
cmake --build --preset vs2026-release --parallel
ctest --preset vs2026-release
cmake --build --preset vs2026-release --target package
.\scripts\smoke-package.ps1 -PackagePath .\build\vs2026\witty-0.1.0-win64.zip -RequireGhosttyDll:$falseUse vs2022 and vs2022-release instead when building on Visual Studio 2022/Build Tools 2022.
The first app run starts pwsh.exe when available, then falls back to Windows PowerShell, then cmd.exe.
Put ghostty-vt.dll next to witty.exe or somewhere on PATH to exercise the libghostty-backed terminal model. Without that DLL, the app uses the fallback VT model so the Windows shell, ConPTY, font, renderer, tests, and packaging remain usable.
Release builds link the MSVC runtime statically by default so the ZIP package stays standalone. Configure with -DWITTY_STATIC_MSVC_RUNTIME=OFF if you prefer the Visual C++ redistributable dependency.
The Windows icon pipeline uses assets\witty.png by default. Configure -DWITTY_ICON_PNG=C:\path\to\witty.png to use a different source PNG; CMake converts the PNG to an ICO resource for witty.exe.
Witty packages include witty.exe, the console CLI/launcher, and witty-gui.exe, the native GUI host. In PowerShell and cmd.exe, running witty resolves to witty.exe, so stdout, stderr, and exit codes behave like a normal CLI while GUI launches open witty-gui.exe. Running witty with no arguments launches the GUI. These forms print to stdout/stderr and exit without opening a window:
witty +version
witty --version
witty +help
witty --help
witty -hWitty recognizes Ghostty-style +action dispatch with Witty names, paths, and help text. The current Windows action surface is:
- Supported:
+version,+help,+list-fonts,+list-keybinds,+list-themes,+list-colors,+list-actions,+edit-config,+show-config,+explain-config,+validate-config,+show-face,+boo, and+new-window. - Recognized with a clear not-yet-supported response:
+ssh-cacheand+crash-report.
Only one +action is accepted per invocation. Unknown actions return an error. Use witty +help <action> or witty +<action> --help for action-specific help.
Use -e to launch the GUI and pass the remaining arguments to the first child process:
witty -e cmd.exe /d /c dir
witty +new-window -e pwsh.exe -NoLogoEverything after -e is treated as child process argv, so values such as +version after -e are passed to the child process rather than parsed as Witty actions.
Witty config and cache paths are Witty-specific:
- Config directory:
%APPDATA%\Witty - Config file:
%APPDATA%\Witty\config - Data directory:
%LOCALAPPDATA%\Witty - Cache directory:
%LOCALAPPDATA%\Witty\cache
ZIP packages include per-user install helpers:
.\install-witty.ps1
.\uninstall-witty.ps1The default install location is %LOCALAPPDATA%\Programs\Witty. The installer copies the package there and adds that directory to the user PATH, so new PowerShell, cmd.exe, and Windows Terminal sessions can run witty. PATH updates are idempotent, preserve unrelated entries, and avoid duplicate Witty entries. The uninstaller removes only Witty's PATH entry by default.
Use .\install-witty.ps1 -NoPath to copy files without changing PATH, or pass -InstallDirectory <path> to choose another per-user location.
To make the libghostty ABI smoke test and package include a specific DLL, configure with:
cmake --preset vs2026 -DWITTY_GHOSTTY_DLL=C:\path\to\ghostty-vt.dllTo build ghostty-vt.dll from Ghostty tip locally first:
.\scripts\build-libghostty-vt.ps1
cmake --preset vs2026 -DWITTY_GHOSTTY_DLL=.\out\libghostty\install\bin\ghostty-vt.dll
ctest --preset vs2026-release
cmake --build --preset vs2026-release --target package
.\scripts\smoke-package.ps1 -PackagePath .\build\vs2026\witty-0.1.0-win64.zipThe helper builds Ghostty's DLL with Zig's x86_64-windows-gnu target by default, which avoids an extra VCRUNTIME140.dll package dependency. For exact commit refs, it writes a stamp file and reuses an existing matching DLL unless -Force is supplied.
CI pins the Ghostty source ref in .github/workflows/windows-ci.yml; bump WITTY_GHOSTTY_REF there when intentionally moving to a newer libghostty ABI.
See docs/architecture.md for the subsystem boundaries and the remaining hardening work.
The terminal model is intentionally isolated under src/core. src/ghostty/GhosttyTerminalModel.* dynamically loads ghostty-vt.dll, resolves the terminal/render-state exports, and feeds Direct2D from ghostty_render_state_* rows and cells. src/core/FallbackTerminalModel.* keeps ConPTY, windowing, font, and renderer work independently buildable when libghostty is unavailable.