fix(graphics): support high-dpi direct file frames - #2680
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughPane graphics now expose and enforce a separate 400 MiB direct-file limit for eligible primary-layer RGBA frames. Kitty control validation checks payload dimensions and profiles. Hidden placement, fallback, cache cleanup, and oversized-transfer behavior are covered. ChangesPane graphics direct-transfer flow
Estimated code review effort: 4 (Complex) | ~45 minutes Mergeability Score: ⚪ Minimal · up to The change expands support for high-DPI direct file frames while preserving existing frame limits and fallback behavior; no actionable merge-blocking risk remains beyond normal checks and review. Sequence Diagram(s)sequenceDiagram
participant PaneGraphicsAPI
participant KittyGraphics
participant DirectGraphicsValidator
participant HeadlessPaneGraphics
participant ProducerResponse
PaneGraphicsAPI->>KittyGraphics: Prepare eligible direct file
KittyGraphics->>DirectGraphicsValidator: Validate control and RGBA length
DirectGraphicsValidator-->>KittyGraphics: Accept transmit or display profile
KittyGraphics->>HeadlessPaneGraphics: Send direct file
HeadlessPaneGraphics-->>ProducerResponse: Acknowledge successful transfer
HeadlessPaneGraphics->>HeadlessPaneGraphics: Clear cache after failed transfer
HeadlessPaneGraphics-->>ProducerResponse: Disconnect oversized terminal transfer
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
1c5a16e to
34bb27e
Compare
Greptile SummaryThe PR extends direct Kitty file transport to support high-DPI primary-layer RGBA frames while retaining the existing inline fallback limit.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains in the eligible follow-up review scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/app/api/pane_graphics.rs | Adds the direct-file capability limit and permits larger primary-layer RGBA file frames only when direct transport is available. |
| src/client/direct_graphics.rs | Validates direct graphics commands against the expected image dimensions and the supported upload or upload-and-placement profiles. |
| src/client/mod.rs | Applies direct-control validation only after validating the transferred file. |
| src/kitty_graphics.rs | Separates upload-only command generation from upload-and-placement generation so placement can be deferred. |
| src/server/headless/pane_graphics.rs | Coordinates direct transfers, inline fallback, delayed placement, acknowledgement, and rejection cleanup. |
| src/server/headless/tests/pane_graphics.rs | Adds coverage for high-DPI transfers, hidden panes, redraw timing, delayed placement, and oversized rejection. |
| src/api/schema/response.rs | Adds the optional direct-file byte limit to the public capability response. |
| docs/next/api/herdr-api.schema.json | Updates the generated API schema for the new direct-file capability field. |
Sequence Diagram
sequenceDiagram
participant Producer
participant Server
participant Client
participant Terminal
Producer->>Server: Direct RGBA file frame
alt Placement currently allowed
Server->>Client: "GraphicsFile a=T (upload and place)"
else Pane hidden or redraw active
Server->>Client: "GraphicsFile a=t (upload only)"
end
Client->>Terminal: Validated direct-file command
Terminal-->>Client: Transfer acknowledgement
Client-->>Server: GraphicsTransmissionResult
Server-->>Producer: Frame acknowledgement
opt Placement was deferred
Server->>Client: "Replay a=p after visibility/redraw"
Client->>Terminal: Place resident image
end
Reviews (5): Last reviewed commit: "Merge branch 'master' into shared-pane-t..." | Re-trigger Greptile
34bb27e to
4851fc9
Compare
bd9f8d0 to
82807f4
Compare
* fix: preserve claude settings formatting (herdrdev#2089) refs herdrdev#2066 Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * fix(client): query host cell size when the ioctl reports no pixels (herdrdev#2160) * fix(cli): report non-UTF-8 arguments instead of panicking (herdrdev#2207) * fix(cli): report non-UTF-8 arguments instead of panicking * fix(cli): avoid echoing malformed arguments --------- Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * fix: avoid blocking on foreground cwd checks (herdrdev#2213) refs herdrdev#2206 * fix(docs): publish only released documentation * fix(docs): support older git in snapshot checks * fix(input): preserve hover during extended-button drags * fix: propagate host color scheme to pane apps (herdrdev#2214) refs herdrdev#714 * fix(pi): restrict state reporting to tui sessions (herdrdev#2159) Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix: page keys scroll pane scrollback at zsh and REPL prompts (herdrdev#2191) * fix: page keys scroll pane scrollback at zsh and REPL prompts PageUp/PageDown were forwarded to the pane whenever DECCKM (application cursor) was on, assuming only primary-screen pagers enable it, but zsh's line editor also enables DECCKM, as do REPLs such as python3. The result was PageUp scrolling shell history instead of Herdr scrollback. Bracketed paste discriminates the two: it means the app accepts typed or pasted text at a prompt, so line editors enable it and pagers do not. * test: update page key state fixture --------- Co-authored-by: Can Celik <ogulcancelik@gmail.com> * feat(website): rebuild marketing pages on new brand chassis * docs: finalize 0.8.0 release documentation * release: v0.8.0 * docs: update website manifest for v0.8.0 * docs: refine cpu optimization blog post * fix(ui): keep collapsed workspace status visible (herdrdev#2239) refs herdrdev#2216 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * docs: publish preview documentation * feat(plugins): index marketplace manifests * fix(docs): allow corrections to published versions refs herdrdev#916 * fix(input): preserve shift-tab in pane automation (herdrdev#2259) refs herdrdev#1561 * fix(ui): preserve sidebar scroll across clients (herdrdev#2280) refs herdrdev#2255 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * fix(website): copy heading links to clipboard * fix: detect claude confirmation prompts refs herdrdev#2268 * feat(ui): add distinct status indicators (herdrdev#2282) refs herdrdev#2260 * fix(input): keep pending url clicks across host focus loss (herdrdev#2291) Opening a URL raises the browser, which takes focus away from the host terminal before the mouse release arrives. release_input_source(_headless) cleared pending_url_click_sources on that focus loss, so the release was forwarded to the pane and the agent opened the same URL again. Clear the set in clear_input_source instead, whose only production caller is remove_client. refs herdrdev#2290 Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com> * fix(cli): resolve pane query --current from caller (herdrdev#2298) refs herdrdev#2297 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * fix(input): parse default mouse reports (herdrdev#2312) * fix(input): parse default mouse reports refs herdrdev#2309 * fix(input): preserve split default mouse reports refs herdrdev#2309 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(ui): search single-tab names in navigator (herdrdev#2320) * fix(layout): return focus to the pane a split was opened from (herdrdev#2266) Closing a focused pane handed focus to the next pane in tree order. For a pane opened beside another one -- a plugin split, a file viewer, any transient tool pane -- that is rarely where the user was: it lands on some unrelated neighbour rather than the pane that opened it. Track the pane focus came from in TileLayout and prefer it when the focused pane closes, falling back to tree order when there is no history, when it points at the pane being closed, or when it points at a pane that has since gone away. The history lives in the layout, so it can only ever name a pane in the same tab. A one-slot history is only sound if internal focus excursions never write it, so the tree edits that used to bounce focus around now go through target-taking primitives instead. close_pane removes a background pane directly, so detach_pane and take_pane_for_move stop focus-close-refocusing. split_pane splits a target without moving focus: the runtime split path only focuses the new pane once the spawn succeeds, which makes a failed split a pure rollback, and the targeted and unfocused workspace split paths stop fabricating history. insert_pane_near now takes the focus intent, so an unfocused pane move leaves the target tab's history alone. The layout-level focused-split helpers become test-only; production splits all flow through the target-taking path. Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(terminal): render halfwidth katakana voiced marks (herdrdev#2257) Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(ci): make issue gate structural * fix(input): preserve modifyOtherKeys key releases (herdrdev#2303) refs herdrdev#2302 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(config): accept retired agent panel scope (herdrdev#2295) refs herdrdev#2292 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * feat(theme): add optional sidebar background * docs: refresh readme and sponsors * chore: remove project-local worktree extension refs herdrdev#2325 * fix(website): update author X profile * feat(windows): support remote attach to unix hosts (herdrdev#2329) * feat(windows): support remote attach to unix hosts * fix(remote): preserve unix bridge behavior * fix(sidebar): highlight active agent in collapsed sidebar (herdrdev#2382) The collapsed sidebar renders agent rows with an unconditional Style::default().fg(p.overlay0), so the active agent is indistinguishable from the others. The workspace list directly above it, and render_agent_detail in the expanded sidebar, both mark the active entry. Reuse the existing active treatment: resolve the active entry with the same is_active_pane call the expanded agent panel uses, then paint the row background with surface_dim and the position number with text, the same tokens the collapsed workspace rows already use. Assisted-By: devx/717e5259-915f-4a7b-af07-6abe46da5b90 * ci: restore approved contributor gate * chore: update canonical repository references * fix(ci): repair contributor gate handling * fix: avoid ctrl-tab escape sequences in legacy panes refs herdrdev#2296 * fix: render OSC 4 palette overrides instead of forwarding the index (herdrdev#2162) Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix: keep plugin marketplace counts current * fix(cli): accept --flag=value and reordered options in pane read/wait-output (herdrdev#2183) * fix(cli): accept --flag=value and reordered options in pane read/wait-output * test(cli): trim redundant pane parser coverage --------- Co-authored-by: Can Celik <ogulcancelik@gmail.com> * docs: document custom agent integrations * fix(detect): recognize versioned Python agent wrappers (herdrdev#2188) Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(terminal): restore keyboard reporting on detach (herdrdev#2395) refs herdrdev#2393 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * feat(copy-mode): add big-word motions (herdrdev#2270) Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix: add positive idle detection for kiro-cli prompt (herdrdev#2301) * fix: add positive idle detection for kiro-cli prompt refs discussion herdrdev#982 * fix: remove manifest integration tests per reviewer request --------- Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(detect): ignore Cursor Run Everything status (herdrdev#2220) * fix(detect): ignore Cursor Run Everything status refs herdrdev#1763 * fix(detect): constrain Cursor approval controls refs herdrdev#1763 * test(detect): remove cursor manifest behavior fixture --------- Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * fix(theme): refresh host appearance on focus (herdrdev#2417) * fix(theme): refresh host appearance on focus refs herdrdev#2416 * fix(input): preserve split appearance replies refs herdrdev#2416 * fix(input): retain fragmented appearance reports refs herdrdev#2416 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * feat(marketplace): track star history for trending and new plugin surfaces * chore: update website * fix: publish stable release checksums * fix: verify stable release checksums * feat(website): rebuild compare page in new design with runtime positioning * fix(remote): restore blocking bridge streams (herdrdev#2485) refs herdrdev#2478 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * fix(input): preserve shift in kitty alternate reports (herdrdev#2479) refs herdrdev#2435 * fix: avoid redundant Windows recent-history snapshots (herdrdev#2474) refs herdrdev#962 Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(config): report unknown theme names (herdrdev#2488) refs herdrdev#2452 * fix(windows): share Git Bash agent candidate scans (herdrdev#2494) refs herdrdev#2459 * feat: support all agent integrations on windows (herdrdev#2496) * fix: forward pane terminal bells (herdrdev#2498) refs herdrdev#2453 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * chore: approve dhh as contributor * feat(input): add per-pane right-click routing (herdrdev#2504) * fix: make windows installer swaps atomic (herdrdev#2530) refs herdrdev#2356 * feat: make outer pane borders configurable (herdrdev#2535) * feat(graphics): add direct pane frame streaming (herdrdev#2523) * feat(graphics): add direct pane frame streaming * feat(graphics): expose pane visibility * test(graphics): preserve legacy terminal image output * fix(graphics): harden streaming lifecycle * fix(input): preserve mouse releases outside panes * fix(ui): reclaim scrollbar gutter in alternate screen (herdrdev#2538) * fix(website): improve plugins page readability on dark ground * fix(input): preserve alt-prefixed control keys (herdrdev#2543) refs herdrdev#2514 * perf(ui): avoid full pane mode reads for scrollbars (herdrdev#2554) * fix(client): avoid abort on terminal hangup (herdrdev#2427) * fix(client): avoid abort on terminal hangup refs herdrdev#2424 * test(client): gate PTY integration on unix refs herdrdev#2424 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * feat: add direct pane resize keybindings (herdrdev#2558) * test: guard pane-scaled render performance refs herdrdev#2550 * feat: add configurable tab bar status (herdrdev#2586) * feat: show a zoom indicator in the desktop tab bar Reserve the right edge of the tab row for a ZOOM pill while the focused pane is zoomed, matching the accent style of the mode bars. The per-tab Z suffix stays; the pill makes the zoomed state visible at a glance like tmux's status-right flag. * feat: optionally show the hostname in the desktop tab bar Add ui.tab_bar_hostname to display the machine's hostname at the right edge of the tab row, like tmux's #h in status-right. The value resolves where the server renders, so remote sessions show the remote host. Off by default. * fix: strip control characters from the tab bar hostname * fix: hide the hostname when it would squeeze out the tab strip * feat: add configurable tab bar status * fix: harden tab bar status updates * fix: terminate tab bar status process trees * fix: disable status commands on unsupported platforms * fix: skip unchanged status command renders * fix: keep tab bar status opt-in by default --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> * feat: add move tab keybind actions (herdrdev#2561) * feat: add move tab keybind actions Add optional keys.move_tab_previous/move_tab_next actions that reorder the active tab one position, wrapping at either end. Reuses the existing tab.move runtime path that mouse drag reordering already drives. * fix: exit navigate mode on single-tab move attempts * fix: center tab labels for symmetric highlight padding (herdrdev#2570) * fix: center tab labels for symmetric highlight padding * docs: note centered tab labels in the changelog * fix: center tab labels by display width, not char count * fix(ui): anchor the host cursor to modal name inputs (herdrdev#2569) * fix(ui): anchor the host cursor to modal name inputs IMEs draw their composition preview at the host terminal cursor. The rename and new-worktree dialogs drew a block glyph instead of setting one, so the frame carried no cursor and the client kept the position the focused pane last reported. Japanese composition appeared behind the dialog and only reached the field on Enter. Set the cursor to the caret column instead, counting wide characters as two cells. refs herdrdev#1755 * fix(ui): keep the clamped caret cell blank A name that fills the field left the clamped caret sitting on the last rendered glyph. A terminal inverts the cell under its cursor and an IME composes there, so the glyph was hidden and composition overlapped it. Render the text one column short of the field. The field is still cleared in full, so the clamped caret always lands on a blank cell. refs herdrdev#1755 --------- Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix: track opencode tui session selection (herdrdev#2455) refs herdrdev#2450 Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * test(windows): serialize media player environment access (herdrdev#2619) * fix(server): prioritize shutdown requests (herdrdev#2624) refs herdrdev#2612 * fix(windows): strip elevated terminal title decoration (herdrdev#2632) * ci: remove automatic issue gate * fix(input): ignore modified j/k/up/down in session navigator (herdrdev#2377) The Char('j')/Char('k')/Down/Up match arms in handle_navigator_key had no modifier guard, unlike every sibling arm in the same match block, so Ctrl+K, Alt+J, etc. also moved the navigator selection. refs herdrdev#1981 Co-authored-by: Can Celik <ogulcancelik@gmail.com> * refactor(website): clean up homepage * feat: keep the outer terminal window title in sync with the session (herdrdev#2627) * feat: keep the outer terminal window title in sync with the session Herdr emulates the terminals in its panes, so an OSC 0/OSC 2 title written inside a pane stops at Herdr and never reaches the terminal Herdr itself runs in. That outer title is what window managers read for title bars, tab bars, and group bars, so it kept showing whatever the shell or ssh happened to leave behind. Add `ui.window_title`, rendered from {hostname}, {workspace}, {tab}, {pane}, and {terminal_title}, and push it to the foreground client whenever it changes. It renders on the server, so {hostname} names the machine the panes actually run on rather than the machine a thin remote client runs on, and it is gated on a pending render so an idle loop never pays for it. A title is only remembered as delivered once a foreground client takes it, so the first client to attach is written to rather than skipped. `client.window_title.set` still wins over the configured title, and clearing it now hands the title back to `ui.window_title` instead of only "herdr". * fix: deliver the outer window title to a newly attached client ClientConnected assigns the foreground client directly rather than going through promote_client_to_foreground, so clearing the sent-title cache there missed the case that matters most: attaching a second terminal to a running session. The title was usually unchanged, so the sync returned early and the new terminal kept whatever its shell or ssh had left. Key the cache on the client that received the title instead of relying on every foreground assignment to invalidate it. * perf: keep hidden pane output off the window title path Output from a hidden or background pane sets needs_render without setting needs_full_render, and the retained render plan then skips presentation for it entirely. Syncing the title on needs_render meant every coalesced hidden-output tick still formatted, sanitized, and allocated a title that could not have changed, against the hidden-source early exit AGENTS.md requires. Every input to the title is app state, which always requests a full render, so gate on that instead. The one exception is the focused pane's own terminal title, which arrives through PTY parsing, so ask for a full render when that changes and the configured title uses it. * fix: only cache a window title a client writer received * fix: carry an api set window title across a live handoff * fix: make outer window title updates event-driven --------- Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * fix: wait for agent prompt readiness (herdrdev#2537) * fix: wait for agent prompt readiness refs herdrdev#2410 * fix: return pane updates after tab bar command refs herdrdev#2410 --------- Co-authored-by: Can Celik <ogulcancelik@gmail.com> * chore: refresh english documentation * fix: derive repo name for embedded bare layouts (herdrdev#2660) refs herdrdev#2657 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * fix: make just build cross-platform (herdrdev#2647) Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(windows): reduce idle agent detection CPU (herdrdev#2651) * fix(windows): reduce idle agent detection CPU refs herdrdev#2642 * fix(windows): gate agent process discovery refs herdrdev#2642 --------- Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com> * fix(render): compact large terminal redraws (herdrdev#2675) refs herdrdev#2670 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> * fix: disambiguate shifted punctuation keybinds (herdrdev#2676) refs herdrdev#2674 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix: detect claude 2.1.228 half-circle busy spinner * fix: synchronously terminate cancelled status commands * perf: avoid repeated Git config reads (herdrdev#2688) refs herdrdev#2643 Co-authored-by: Can Celik <ogulcancelik@gmail.com> * chore: update contributor list * fix: preserve workspace labels for root repositories (herdrdev#2727) refs herdrdev#2594 * fix: use the running binary in agent hooks (herdrdev#2722) * fix: strip claude title spinner frames (herdrdev#2709) * fix: source title activity glyphs from manifests refs herdrdev#2707 * fix: simplify manifest-driven title stripping refs herdrdev#2707 * fix: reconcile handoff title policies refs herdrdev#2707 * fix: strip claude title spinner frames refs herdrdev#2707 * fix: keep claude detection manifest unchanged --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> * fix(agent): focus Copilot before prompting (herdrdev#2734) * fix(agent): focus Copilot before prompting refs herdrdev#1698 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(agent): cover stale focus-reporting state refs herdrdev#1698 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add qwen code detection and restore (herdrdev#2743) refs herdrdev#2730 * fix: preserve logical lines in scrollback editor (herdrdev#2735) refs herdrdev#2733 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Can Celik <ogulcancelik@gmail.com> * fix(graphics): support high-dpi direct file frames (herdrdev#2680) --------- Co-authored-by: akbash <akbash@herdr.dev> Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com> Co-authored-by: WakaTaira <50697207+WakaTaira@users.noreply.github.com> Co-authored-by: Florian <13469873+VialFlorian@users.noreply.github.com> Co-authored-by: Rhys <105699450+rhjoh@users.noreply.github.com> Co-authored-by: Michael Hackner <mhackner@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: kangal-bot <285672167+kangal-bot@users.noreply.github.com> Co-authored-by: Kataoka Katsuki <49934462+kataokatsuki@users.noreply.github.com> Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com> Co-authored-by: Jon Kinney <jonkinney@gmail.com> Co-authored-by: Kazunari Kamata <14287197+kazunari-kamata@users.noreply.github.com> Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local> Co-authored-by: Ian Ker-Seymer <i.kerseymer@gmail.com> Co-authored-by: Mo <77584024+hamidi-dev@users.noreply.github.com> Co-authored-by: Kyle Corbeille <kcorbeille76@gmail.com> Co-authored-by: Phil Larson <hello@phillarson.xyz> Co-authored-by: JP Lew <462836+jplew@users.noreply.github.com> Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal> Co-authored-by: Sam Biggins <sambiggins@gmail.com> Co-authored-by: Jesse Zhang <j3ssezhang102@gmail.com> Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com> Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: PISIT KOOLPLUKPOL <pisit.koolplukpol@outlook.com> Co-authored-by: Erik Krogen <erikkrogen@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Documented the stack layout node (`panes`, `active`) in socket-api so clients can round-trip a stacked tab through layout.export and layout.apply
- Added stacking to the pane concepts, quick-start and keyboard pages in English, Japanese and Simplified Chinese
- Added the `split_stacked` binding to the keyboard and configuration samples in all three locales
- Corrected the `pane split` and `plugin pane open` usage strings to read `right|down|stacked`, which the parsers already accepted
- Taught the embedded agent skill to reach for `--direction stacked` when another split would leave panes unusably small
- Left `pane move --split` as `right|down` because the server rejects moving a pane into a stack
chore: import fork-local justfile recipes
An optional import keeps local recipes in an ignored directory, so the
tracked justfile carries one line instead of a growing fork-only block
and a rebase has one place to conflict.
fix(input): give stack title rows priority over the split resize handle
A stack's first title row sits on the region's top border, which is the
same row a vertical split above it uses as its resize handle. Border
lookup runs before the pane hit test, so clicking the top member of a
stack below a split started a resize instead of focusing it, leaving that
member unreachable by mouse.
feat(ui): offer a stacked split in the pane menu
The pane menu offered split right and split down, so stacking was
reachable only from the keyboard. The placement enum already had the
variant, so this is wiring rather than new capability.
fix(server): keep hidden stack members out of their own title rows
The retained renderer applied every pane's dirty patch at its inner rect.
A collapsed member's inner rect is its one row title row, and collecting
a patch has no size check, so asking for one row handed back the first
row of that hidden terminal to be painted over the member's own name.
Only the span between the corners was overwritten, which is why the frame
survived while the name did not, and only while that agent was producing
output.
A collapsed member also reports its whole screen dirty for as long as it
stays hidden, because nothing else refreshes a hidden pane's render
state, so one stack was enough to drop a whole tab back to full redraws.
Skipping it fixes both, and matches what pane rendering and kitty
graphics already do.
feat(ui): draw stacked pane titles on the frame
Each member of a stack was named twice: once on the box's top border and
again on a title row of its own directly below it. The first member's
title row is now the region's own top border, so a stack costs one row
less than a box plus a row per member, and the name sits where a pane's
name already sits.
A title row is drawn as a ruled frame line opening its own corner rather
than tee-ing into one continuous box, so a stack reads as a deck of cards
rather than as one pane chopped into strips. The region's top border row
is shared with the pane above and is left to the border pass, which has
already drawn its junctions and its colour; only the title text goes
there.
A collapsed member takes a muted version of the accent instead of the
generic border grey, so a stack reads as one group of related panes.
StackSlot carries the region's borders because only the visible member
holds them, and rescanning the pane list for it would be quadratic inside
a render loop.
docs: document stacked panes and the stacked split keybind
Covers prefix+shift+s and the agent panel row change in the sample
config, the keyboard page and the config reference.
feat(ui): name panes after the agent session
A pane's name is now resolved in one place, TerminalState::display_name:
a title the agent pushed, then an explicit rename, then the agent session
name, then the terminal's own title. Pane chrome, stack title rows and
the agent panel all read it, so they cannot drift. Two of them already
had, which is how a renamed session showed on a stack row but not in the
panel.
An agent renaming its own session arrives as a terminal title, so leaving
that out of the chain made a renamed session look unnamed. The agent
session name reaches the panel through the existing pane token, and the
default second row is now agent then pane name.
pi prefixes its title with a lone glyph the same way claude does, so it
joins the set that is stripped before a title is shown. An unnamed pi
session is nothing but that glyph, which now leaves no name and falls
back to the agent label.
feat(input): add a stacked split action
prefix+shift+s puts a new pane in the focused pane's stack, creating one
if the pane is not stacked yet. It sits alongside split_vertical and
split_horizontal as a third way to place a pane, and stays prefix-first
so herdr does not start swallowing keys from shells and editors.
Moving between members needs no new action: collapsed title rows are
ordinary rects stacked vertically, so prefix+j and prefix+k already walk
a stack.
SplitDirection gains a stacked variant, which the cli accepts as
herdr pane split --direction stacked. It has no split axis, so the
conversion to a layout direction is now fallible, and pane move rejects
it before taking the source pane out of its tab rather than after.
feat(ui): render stacked pane title rows
Every member of a stack gets a title row, the visible one included, and
its terminal starts on the row directly below. Without a row of its own
the last collapsed title sat right above the visible terminal and read as
that terminal's label.
The box is drawn once around the whole region and carried by the visible
member, so the existing border joining code handles it like any other
pane. Collapsed rows carry no chrome. Chrome is decided for the region
rather than per member, otherwise the top, middle and bottom of a stack
get different borders and the visible pane's terminal changes height as
focus moves.
Kitty graphics bypass the cell buffer, so a collapsed member is skipped
when collecting placements too; otherwise a hidden pane draws images over
its own title row. A layout with no stacks costs one scan and no
allocation.
feat(layout): add a stacked pane node
Panes in a stack share one region. One shows its terminal and the rest
collapse to a single title row, so a tab with six agents no longer gives
each of them a sixth of the screen.
Unlike zellij, a collapsed pane keeps a full size terminal behind its
title row. Every member is sized to the region the visible member
occupies, so moving through a stack never resizes a pty, never reflows a
running agent, and leaves the bottom buffer that detection reads intact.
The visible member also keeps a floor of content rows, so adding members
drops title rows rather than shrinking every terminal toward nothing.
Stack membership is a session fact, so it is saved with the layout and
reported by the layout API. Restore drops dead members, keeps the visible
one in range, and turns a stack that is down to one pane back into a
plain pane. A stack holds panes rather than subtrees, and applying a
layout restores the member the caller marked visible, so exporting a
layout and applying it back reproduces the same stack.
fix: speed up alternate-screen history reads (#2426)
refs #2387
fix: keep active sidebar rows visible (#2794)
refs #2792
feat(cli): guide agents to Herdr resources
fix(docs): publish channel-aware documentation indexes
fix(docs): apply llms patch during website builds
feat(docs): publish agent-readable documentation
fix: reject prompts to blocked agents (#2790)
* fix: reject prompts to blocked agents
refs #2788
* docs: clarify agent prompt timing
refs #2788
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: detect all claude half-circle spinner frames (#2762)
refs #2760
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: wait for new pane shell readiness (#2774)
* fix: wait for new pane shell readiness
refs #2773
* refactor: share agent startup bounds
refs #2773
* fix: reconcile agent names after startup timeout
refs #2773
* fix: cover agent cleanup scheduling skew
refs #2773
* fix: bound pane shell readiness retries
refs #2773
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: keep tab and sidebar clicks when the terminal reports a stray drag (#2736)
* fix: keep tab and sidebar clicks when the terminal reports a stray drag
This works around a Ghostty bug that causes herdr tabs to be unclickable
in fullscreen mode.
Ghostty on macOS in native fullscreen emits one motion report after a
fresh press in the strip where the menu bar reveals, with the row
shifted to near the bottom of the grid. The cause is upstream: macOS
delivers one mouse event whose y is nearly a window height away from the
real pointer, and Ghostty reports it as it arrives (iTerm2 and
Terminal.app report the same clicks correctly).
Herdr treated the stray report as a real drag and lost the click two
ways: it opened a tab reorder with no drop target, making the release a
no-op, and it handed the release to the pane under the bogus
coordinates.
Now, a press on the tab bar or sidebar owns the gesture until release,
and a tab drag only starts once the pointer is over a real drop target.
refs #796
* fix: scope chrome mouse gestures to their input source
* fix: preserve chrome drag input source
* fix: preserve concurrent chrome presses
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(graphics): support high-dpi direct file frames (#2680)
fix: preserve logical lines in scrollback editor (#2735)
refs #2733
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: add qwen code detection and restore (#2743)
refs #2730
fix(agent): focus Copilot before prompting (#2734)
* fix(agent): focus Copilot before prompting
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(agent): cover stale focus-reporting state
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: strip claude title spinner frames (#2709)
* fix: source title activity glyphs from manifests
refs #2707
* fix: simplify manifest-driven title stripping
refs #2707
* fix: reconcile handoff title policies
refs #2707
* fix: strip claude title spinner frames
refs #2707
* fix: keep claude detection manifest unchanged
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: use the running binary in agent hooks (#2722)
fix: preserve workspace labels for root repositories (#2727)
refs #2594
chore: update contributor list
perf: avoid repeated Git config reads (#2688)
refs #2643
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: synchronously terminate cancelled status commands
fix: detect claude 2.1.228 half-circle busy spinner
fix: disambiguate shifted punctuation keybinds (#2676)
refs #2674
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(render): compact large terminal redraws (#2675)
refs #2670
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): reduce idle agent detection CPU (#2651)
* fix(windows): reduce idle agent detection CPU
refs #2642
* fix(windows): gate agent process discovery
refs #2642
---------
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
fix: make just build cross-platform (#2647)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: derive repo name for embedded bare layouts (#2660)
refs #2657
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: refresh english documentation
fix: wait for agent prompt readiness (#2537)
* fix: wait for agent prompt readiness
refs #2410
* fix: return pane updates after tab bar command
refs #2410
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: keep the outer terminal window title in sync with the session (#2627)
* feat: keep the outer terminal window title in sync with the session
Herdr emulates the terminals in its panes, so an OSC 0/OSC 2 title
written inside a pane stops at Herdr and never reaches the terminal
Herdr itself runs in. That outer title is what window managers read for
title bars, tab bars, and group bars, so it kept showing whatever the
shell or ssh happened to leave behind.
Add `ui.window_title`, rendered from {hostname}, {workspace}, {tab},
{pane}, and {terminal_title}, and push it to the foreground client
whenever it changes. It renders on the server, so {hostname} names the
machine the panes actually run on rather than the machine a thin remote
client runs on, and it is gated on a pending render so an idle loop
never pays for it.
A title is only remembered as delivered once a foreground client takes
it, so the first client to attach is written to rather than skipped.
`client.window_title.set` still wins over the configured title, and
clearing it now hands the title back to `ui.window_title` instead of
only "herdr".
* fix: deliver the outer window title to a newly attached client
ClientConnected assigns the foreground client directly rather than going
through promote_client_to_foreground, so clearing the sent-title cache
there missed the case that matters most: attaching a second terminal to a
running session. The title was usually unchanged, so the sync returned
early and the new terminal kept whatever its shell or ssh had left.
Key the cache on the client that received the title instead of relying on
every foreground assignment to invalidate it.
* perf: keep hidden pane output off the window title path
Output from a hidden or background pane sets needs_render without setting
needs_full_render, and the retained render plan then skips presentation
for it entirely. Syncing the title on needs_render meant every coalesced
hidden-output tick still formatted, sanitized, and allocated a title that
could not have changed, against the hidden-source early exit AGENTS.md
requires.
Every input to the title is app state, which always requests a full
render, so gate on that instead. The one exception is the focused pane's
own terminal title, which arrives through PTY parsing, so ask for a full
render when that changes and the configured title uses it.
* fix: only cache a window title a client writer received
* fix: carry an api set window title across a live handoff
* fix: make outer window title updates event-driven
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
refactor(website): clean up homepage
fix(input): ignore modified j/k/up/down in session navigator (#2377)
The Char('j')/Char('k')/Down/Up match arms in handle_navigator_key
had no modifier guard, unlike every sibling arm in the same match
block, so Ctrl+K, Alt+J, etc. also moved the navigator selection.
refs #1981
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
ci: remove automatic issue gate
fix(windows): strip elevated terminal title decoration (#2632)
fix(server): prioritize shutdown requests (#2624)
refs #2612
test(windows): serialize media player environment access (#2619)
fix: track opencode tui session selection (#2455)
refs #2450
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(ui): anchor the host cursor to modal name inputs (#2569)
* fix(ui): anchor the host cursor to modal name inputs
IMEs draw their composition preview at the host terminal cursor. The rename
and new-worktree dialogs drew a block glyph instead of setting one, so the
frame carried no cursor and the client kept the position the focused pane
last reported. Japanese composition appeared behind the dialog and only
reached the field on Enter.
Set the cursor to the caret column instead, counting wide characters as two
cells.
refs #1755
* fix(ui): keep the clamped caret cell blank
A name that fills the field left the clamped caret sitting on the last
rendered glyph. A terminal inverts the cell under its cursor and an IME
composes there, so the glyph was hidden and composition overlapped it.
Render the text one column short of the field. The field is still cleared
in full, so the clamped caret always lands on a blank cell.
refs #1755
---------
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: center tab labels for symmetric highlight padding (#2570)
* fix: center tab labels for symmetric highlight padding
* docs: note centered tab labels in the changelog
* fix: center tab labels by display width, not char count
feat: add move tab keybind actions (#2561)
* feat: add move tab keybind actions
Add optional keys.move_tab_previous/move_tab_next actions that reorder
the active tab one position, wrapping at either end. Reuses the
existing tab.move runtime path that mouse drag reordering already
drives.
* fix: exit navigate mode on single-tab move attempts
feat: add configurable tab bar status (#2586)
* feat: show a zoom indicator in the desktop tab bar
Reserve the right edge of the tab row for a ZOOM pill while the
focused pane is zoomed, matching the accent style of the mode bars.
The per-tab Z suffix stays; the pill makes the zoomed state visible
at a glance like tmux's status-right flag.
* feat: optionally show the hostname in the desktop tab bar
Add ui.tab_bar_hostname to display the machine's hostname at the right
edge of the tab row, like tmux's #h in status-right. The value resolves
where the server renders, so remote sessions show the remote host. Off
by default.
* fix: strip control characters from the tab bar hostname
* fix: hide the hostname when it would squeeze out the tab strip
* feat: add configurable tab bar status
* fix: harden tab bar status updates
* fix: terminate tab bar status process trees
* fix: disable status commands on unsupported platforms
* fix: skip unchanged status command renders
* fix: keep tab bar status opt-in by default
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
test: guard pane-scaled render performance
refs #2550
feat: add direct pane resize keybindings (#2558)
fix(client): avoid abort on terminal hangup (#2427)
* fix(client): avoid abort on terminal hangup
refs #2424
* test(client): gate PTY integration on unix
refs #2424
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
perf(ui): avoid full pane mode reads for scrollbars (#2554)
fix(input): preserve alt-prefixed control keys (#2543)
refs #2514
fix(website): improve plugins page readability on dark ground
fix(ui): reclaim scrollbar gutter in alternate screen (#2538)
feat(graphics): add direct pane frame streaming (#2523)
* feat(graphics): add direct pane frame streaming
* feat(graphics): expose pane visibility
* test(graphics): preserve legacy terminal image output
* fix(graphics): harden streaming lifecycle
* fix(input): preserve mouse releases outside panes
feat: make outer pane borders configurable (#2535)
fix: make windows installer swaps atomic (#2530)
refs #2356
feat(input): add per-pane right-click routing (#2504)
chore: approve dhh as contributor
fix: forward pane terminal bells (#2498)
refs #2453
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: support all agent integrations on windows (#2496)
fix(windows): share Git Bash agent candidate scans (#2494)
refs #2459
fix(config): report unknown theme names (#2488)
refs #2452
fix: avoid redundant Windows recent-history snapshots (#2474)
refs #962
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve shift in kitty alternate reports (#2479)
refs #2435
fix(remote): restore blocking bridge streams (#2485)
refs #2478
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat(website): rebuild compare page in new design with runtime positioning
fix: verify stable release checksums
fix: publish stable release checksums
chore: update website
feat(marketplace): track star history for trending and new plugin surfaces
fix(theme): refresh host appearance on focus (#2417)
* fix(theme): refresh host appearance on focus
refs #2416
* fix(input): preserve split appearance replies
refs #2416
* fix(input): retain fragmented appearance reports
refs #2416
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(detect): ignore Cursor Run Everything status (#2220)
* fix(detect): ignore Cursor Run Everything status
refs #1763
* fix(detect): constrain Cursor approval controls
refs #1763
* test(detect): remove cursor manifest behavior fixture
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: add positive idle detection for kiro-cli prompt (#2301)
* fix: add positive idle detection for kiro-cli prompt
refs discussion #982
* fix: remove manifest integration tests per reviewer request
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat(copy-mode): add big-word motions (#2270)
Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(terminal): restore keyboard reporting on detach (#2395)
refs #2393
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize versioned Python agent wrappers (#2188)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: document custom agent integrations
fix(cli): accept --flag=value and reordered options in pane read/wait-output (#2183)
* fix(cli): accept --flag=value and reordered options in pane read/wait-output
* test(cli): trim redundant pane parser coverage
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: keep plugin marketplace counts current
fix: render OSC 4 palette overrides instead of forwarding the index (#2162)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: avoid ctrl-tab escape sequences in legacy panes
refs #2296
fix(ci): repair contributor gate handling
chore: update canonical repository references
ci: restore approved contributor gate
fix(sidebar): highlight active agent in collapsed sidebar (#2382)
The collapsed sidebar renders agent rows with an unconditional
Style::default().fg(p.overlay0), so the active agent is
indistinguishable from the others. The workspace list directly above
it, and render_agent_detail in the expanded sidebar, both mark the
active entry.
Reuse the existing active treatment: resolve the active entry with the
same is_active_pane call the expanded agent panel uses, then paint the
row background with surface_dim and the position number with text, the
same tokens the collapsed workspace rows already use.
Assisted-By: devx/717e5259-915f-4a7b-af07-6abe46da5b90
feat(windows): support remote attach to unix hosts (#2329)
* feat(windows): support remote attach to unix hosts
* fix(remote): preserve unix bridge behavior
fix(website): update author X profile
chore: remove project-local worktree extension
refs #2325
docs: refresh readme and sponsors
feat(theme): add optional sidebar background
fix(config): accept retired agent panel scope (#2295)
refs #2292
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve modifyOtherKeys key releases (#2303)
refs #2302
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): make issue gate structural
fix(terminal): render halfwidth katakana voiced marks (#2257)
Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(layout): return focus to the pane a split was opened from (#2266)
Closing a focused pane handed focus to the next pane in tree order.
For a pane opened beside another one -- a plugin split, a file viewer,
any transient tool pane -- that is rarely where the user was: it lands
on some unrelated neighbour rather than the pane that opened it.
Track the pane focus came from in TileLayout and prefer it when the
focused pane closes, falling back to tree order when there is no
history, when it points at the pane being closed, or when it points at
a pane that has since gone away. The history lives in the layout, so it
can only ever name a pane in the same tab.
A one-slot history is only sound if internal focus excursions never
write it, so the tree edits that used to bounce focus around now go
through target-taking primitives instead. close_pane removes a
background pane directly, so detach_pane and take_pane_for_move stop
focus-close-refocusing. split_pane splits a target without moving
focus: the runtime split path only focuses the new pane once the spawn
succeeds, which makes a failed split a pure rollback, and the targeted
and unfocused workspace split paths stop fabricating history.
insert_pane_near now takes the focus intent, so an unfocused pane move
leaves the target tab's history alone. The layout-level focused-split
helpers become test-only; production splits all flow through the
target-taking path.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ui): search single-tab names in navigator (#2320)
fix(input): parse default mouse reports (#2312)
* fix(input): parse default mouse reports
refs #2309
* fix(input): preserve split default mouse reports
refs #2309
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(cli): resolve pane query --current from caller (#2298)
refs #2297
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): keep pending url clicks across host focus loss (#2291)
Opening a URL raises the browser, which takes focus away from the host
terminal before the mouse release arrives. release_input_source(_headless)
cleared pending_url_click_sources on that focus loss, so the release was
forwarded to the pane and the agent opened the same URL again.
Clear the set in clear_input_source instead, whose only production caller
is remove_client.
refs #2290
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
feat(ui): add distinct status indicators (#2282)
refs #2260
fix: detect claude confirmation prompts
refs #2268
fix(website): copy heading links to clipboard
fix(ui): preserve sidebar scroll across clients (#2280)
refs #2255
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): preserve shift-tab in pane automation (#2259)
refs #1561
fix(docs): allow corrections to published versions
refs #916
feat(plugins): index marketplace manifests
docs: publish preview documentation
fix(ui): keep collapsed workspace status visible (#2239)
refs #2216
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: refine cpu optimization blog post
docs: update website manifest for v0.8.0
release: v0.8.0
docs: finalize 0.8.0 release documentation
feat(website): rebuild marketing pages on new brand chassis
fix: page keys scroll pane scrollback at zsh and REPL prompts (#2191)
* fix: page keys scroll pane scrollback at zsh and REPL prompts
PageUp/PageDown were forwarded to the pane whenever DECCKM (application
cursor) was on, assuming only primary-screen pagers enable it, but zsh's
line editor also enables DECCKM, as do REPLs such as python3. The result
was PageUp scrolling shell history instead of Herdr scrollback.
Bracketed paste discriminates the two: it means the app accepts typed or
pasted text at a prompt, so line editors enable it and pagers do not.
* test: update page key state fixture
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(pi): restrict state reporting to tui sessions (#2159)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: propagate host color scheme to pane apps (#2214)
refs #714
fix(input): preserve hover during extended-button drags
fix(docs): support older git in snapshot checks
fix(docs): publish only released documentation
fix: avoid blocking on foreground cwd checks (#2213)
refs #2206
fix(cli): report non-UTF-8 arguments instead of panicking (#2207)
* fix(cli): report non-UTF-8 arguments instead of panicking
* fix(cli): avoid echoing malformed arguments
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(client): query host cell size when the ioctl reports no pixels (#2160)
fix: preserve claude settings formatting (#2089)
refs #2066
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: stop advertising worktree json flag (#2174)
refs #2171
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize opencode2 as opencode
refs #2169
fix: route vscode remote copies through osc52 (#2173)
refs #2015
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): detect agents across git bash exec boundaries (#2170)
refs #2107
fix(socket_paths): remove dead if-branch in derive_client_socket_from_api_socket (#2157)
fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard (#2165)
* fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard
refs #2164
* fix(input): update control-byte matrix test for 0x1f -> Ctrl+_
feat: add antigravity-cli integration (#2087)
* feat: add antigravity_cli integration harness
Register the `antigravity_cli` target, resolve its configuration
directory to `~/.gemini/antigravity-cli/`, wire target actions,
and add lifecycle hook scripts for Unix and Windows.
* feat: support session resume for antigravity-cli
* fix: correct antigravity-cli hook config path, shape, and agent label
Antigravity CLI reads global customizations from ~/.gemini/config, keys
hooks.json by hook name, and only accepts the matcher/hooks wrapper for
the tool events. The previous install wrote event arrays at the top level
of ~/.gemini/antigravity-cli/hooks.json, which agy never reads and would
reject anyway, so no Herdr hook ever ran.
Session reports were dropped for a third reason: the hooks reported the
agent as antigravity-cli, but the server normalizes that to the canonical
label agy before matching, so is_official_agent_source never matched and
agy --conversation resume was unreachable.
- Resolve the config dir to ~/.gemini/config
- Nest Herdr entries under a Herdr-owned "herdr" block that install
rewrites and uninstall removes, leaving other named hooks untouched
- Emit grouped entries for PreToolUse/PostToolUse and flat handler lists
for PreInvocation/PostInvocation/Stop
- Report the canonical agy label from both hook assets and match it in
agent_resume
- Compile-gate the hook asset constants and stop shadowing $args in the
PowerShell hook
- Document the real directory, that it must already exist, and the
named-block behavior
refs #1011
refs #1571
* fix: make antigravity-cli integration session-only
antigravity cli cannot express lifecycle safely: there is no blocked
event, postinvocation is skipped on interruption, and stop fires at the
end of a turn rather than on process exit, which left stale state and
released authority at the wrong time.
report only the conversation on preinvocation and let screen detection
own agent state. resume via `agy --conversation <id>` is unchanged.
* fix: update antigravity session after conversation switch
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): skip pr gate in forks
feat(ui): make pane scrollbars optional (#2166)
refs #2167
fix: expand copy-mode word-end window past a final wide glyph (#2145)
point_is_final_atom compared an atom's terminating column against a
word-motion target's starting column. The two are equal for narrow
cells but never for wide ones, so the read window stopped expanding
and copy-mode `e` halted at the soft-wrap boundary on CJK text.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: report a clear cli error when no herdr server is running (#1963)
* fix: report a clear cli error when no herdr server is running
socket cli commands surfaced a raw io::Error debug string
(`Error: Os { code: 2, ... }`) when nothing was listening on the
api socket, which read like a bad --cwd path. map dead-socket
connect failures to a `server_not_running` json error carrying the
resolved socket path, printed once at the edge that surfaces the
error; recovering callers (plugin offline registry fallback, agent
start polling) recognize the marker and keep their existing
behavior.
refs #1941
* fix: map dead-socket errors on the unchecked cli request path
refs #1941
* fix: make server-not-running guidance session-aware
refs #1941
fix(windows): preserve semantic escape key taps
fix(input): preserve native key lifecycle across routing (#2142)
refs #2077
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
chore: remove experiments from settings tui
feat: support bottom tab bar placement (#2118)
* feat: support bottom tab bar placement
* fix: preserve mouse cleanup under bottom mode bar
refs #2117
chore: update agentmd for protocol changes
fix: read alternate-screen agent history
fix(sidebar): keep worktree groups packed
fix(client): restore terminal on sighup and sigterm
Enable termination-signal handling so SIGHUP and SIGTERM follow the graceful
quit path and restore terminal state. Log handler registration failures and
add PTY coverage for direct SIGHUP and server EOF restoration
Co-authored-by: Matt Coles <macols@amazon.com>
fix: preserve windows sessions after ssh logout (#2098)
* fix: preserve windows sessions after ssh logout
refs #2008
* chore: document windows wmi safety
refs #2008
fix(omp): support Windows session paths (#2092)
fix: resume agents after headless restore (#2088)
refs #2064
ci: consolidate ai review trigger label
fix: launch argument-free agents on windows (#2075)
refs #2072
fix: add opt-in child-group process detection (#2052)
* fix: add opt-in child-group process detection
refs #1982
* fix: preserve lifecycle probes without foreground groups
refs #1982
fix: preserve kitty associated text (#2051)
refs #2020
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: finish repository organization migration
Update rose pine surface_dim colour to "Overlay" (#2002)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: update repository links after organization transfer
ci: allow repository organization migration
fix: scope agent skill installation
refs #2022
docs: update preview manifest
fix(windows): preserve parent agent ownership
refs #1514
fix: preserve windows path variables during install
refs #1947
test(windows): remove flaky sound timing assertion
refs #1330
fix(windows): restore system notifications and sound playback (#2019)
ci: remove approved contributor bypass
chore: approve merged contributor we11adam
fix: preserve navigate mode after pane focus (#1993)
refs #1850
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: approve merged contributor patrick-xin
docs: add simplified chinese readme (#1990)
* docs: add simplified chinese readme
* fix: publish simplified chinese readme
* fix: require localized readme for releases
* docs: publish simplified chinese readme
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: restore python3 commit hook
fix: select windows python command in commit hook (#1994)
chore: approve merged contributor bioform
fix: count ptmx master fds under devpts layouts (#1984)
live_server_holds_one_pty_master_fd_per_pane counted only /proc/<pid>/fd links
resolving to exactly /dev/ptmx. On devpts setups such as WSL2 and many
containers, a PTY master fd resolves to /dev/pts/ptmx instead, so the test found
zero masters and failed with "had 0 ptmx master fds; expected 1" even though the
server held the pane's master fd. Match both ptmx node paths; pty slaves still
resolve to /dev/pts/<N> and stay uncounted, so the one-master-per-pane invariant
is unchanged.
perf: skip rendering hidden pty updates
fix: preserve linked worktree workspace labels
perf: replace agent spinners with static status marks
fix: ignore nested codex session reports (#1927)
* fix: ignore nested codex session reports
refs #1789
* test: cover matching codex thread id
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: resolve relative plugin commands from plugin root
refs #1949
docs: update sponsor acknowledgements
fix: keep focus on the current workspace when another self-closes (#1912)
handle_pane_died only clamped the stale active/selected indices after
removing a workspace that closed itself, so it never shifted them down
when the removed workspace sat before the focused one. With workspaces
[x, y, z] and focus on y, removing x left active pointing at z, silently
moving the user into a workspace they did not select.
Resolve both indices by workspace id across the removal, as
close_selected_workspace already does, keeping the clamp as the fallback
for when the removed workspace was the focused one. Also scroll the
focused workspace back into view, which the explicit-close path already
did and this one did not.
refs #1621
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: make native windows checks reliable (#1925)
chore: approve merged contributor season179
fix: close workspace when api closes its last tab (#1899)
herdr tab close on a workspace's only tab returned tab_close_failed,
while the TUI close-tab action on the same tab closes the tab and
cascades to closing the workspace. Cascade in the API too, emitting
tab.closed then workspace.closed. When the cascade would close a whole
worktree group, return confirmation_required instead, matching
pane.close and the TUI prompt.
refs #1760
chore: approve merged contributor Pimpmuckl
fix: preserve shift-enter in windows panes (#1909)
refs #1743
fix: delay agent prompt submission
refs #1878
fix: ignore empty clipboard writes
refs #1893
fix: restrict unapproved pull requests to bug fixes
ci: harden pull request workflow execution
chore: approve merged contributor olafkfreund
fix(nix): include SKILL.md in the package fileset (#1890)
refs #1889
fix: repaint after transient terminal resizes
fix: preserve prefix mode for modifier events
refs #1870
feat: print bundled agent skill and hint next cli steps
chore: approve merged contributor yianL
fix: preserve focus when closing a non-focused workspace (#1877)
refs #1328
fix: support non-us shifted keybindings (#1876)
* fix: support non-us shifted keybindings
refs #1870
* docs: require current pull request base
fix: improve sidebar worktree hierarchy and reordering (#1873)
* fix: clarify sidebar worktree hierarchy
refs #1694
* feat: reorder worktree groups as a unit
refs #1694
fix: avoid renders for passive mouse motion (#1872)
refs #1865
perf: avoid full pane renders for spinner animation (#1868)
ci: gate pull request review by scope
fix(nix): add rust-analyzer to development shell
chore: consolidate project skills
docs: define maintainer and agent contribution workflows
feat: switch IME to ASCII in prefix mode on Windows (Korean IME) (#1823)
* feat: switch IME to ASCII in prefix mode on Windows
Extend switch_ascii_input_source_in_prefix to Windows: detect IME state
via WM_IME_CONTROL and toggle to ASCII with SendInput for the Korean IME.
Other IME languages are detected and left unchanged.
refs #1802
* docs: clarify Windows (Korean IME) support for prefix ASCII switching
Follow-up to the Windows prefix ASCII switch, which extended
switch_ascii_input_source_in_prefix to Windows but left the surrounding
text describing macOS only.
- Settings row label: "(macOS)" -> "(macOS/Windows)", plus its test.
- Generalize the Windows behavior wording to "switches the IME to
English (ASCII) input" in the config-reference.json entry and the
model.rs doc comment, and state that Windows support is currently
limited to the Korean IME.
- Add a :::caution aside noting the Korean-IME-only limitation to the
en/ja/zh preview docs, keeping the three translations in sync.
refs #1802
* fix: warn when prefix IME toggle injection is incomplete
SendInput can queue fewer events than requested (for example when blocked
by UIPI), which would otherwise leave the IME silently stuck in ASCII or
native mode. Log a warning with the sent and expected counts so the failure
is diagnosable.
refs #1802
* fix: guard prefix IME restore and correct open-status naming
Address maintainer review on the Windows prefix ASCII switch:
- Restore only when safe: store the foreground window at switch time and,
before toggling back, require that the same window is still focused and
the IME is still in English. This stops restore from toggling another
application or overriding a manual return to Hangul during prefix mode.
- Report injection success from send_vk_tap and only arm restoration when
the initial toggle landed; on a partial injection retry the dropped
key-up so a key is not left logically held down. The injection policy is
split into send_vk_tap_with(inject) so the success, partial, and failure
branches are unit-tested without the real SendInput.
- Correct the WM_IME_CONTROL sub-command naming: 0x0005 is IMC_GETOPENSTATUS
(IME open state), not IMC_GETCONVERSIONMODE. Behavior is unchanged; the
constant, comments, and tests now describe the open-status read.
refs #1802
* fix: bound IME open-status read with a timeout
The prefix IME switch reads IMC_GETOPENSTATUS via WM_IME_CONTROL, which
crosses into the terminal-emulator process. A plain SendMessageW would block
herdr's client thread until that process responds, indefinitely if it hangs.
Read through SendMessageTimeoutW with SMTO_ABORTIFHUNG and a short timeout
instead; on timeout the switch is skipped and restore does nothing, so a hung
host process can no longer freeze prefix-mode entry or exit.
refs #1802
* fix: preserve windows ime restoration after partial injection
refs #1802
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
perf: eliminate repeated workspace git discovery (#1842)
* perf: eliminate repeated workspace git discovery
refs #1838
* fix: keep workspace labels current without extra redraws
refs #1838
* fix: retain discovered workspace git metadata
refs #1838
fix: copy retained mouse selections with keyboard shortcuts
refs #1782
fix: run pi worktree ext on background
chore: approve merged contributor ogulcancelik
fix: bundle modern ConPTY on Windows (#1828)
refs #1533
refs #1644
fix: harden hermes lifecycle detection
feat: filter keybind help (#1832)
* feat: filter keybind help
refs #1825
* fix: recognize shifted slash in keybind help
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add grok cli integration for native session restore (#1807)
* feat: add grok cli integration for native session restore
tl;dr: adds `herdr integration install grok` (session-identity tier: a
SessionStart hook reports the grok session id for native restore; state
stays screen-detected via the bundled manifest).
Grok merges every ~/.grok/hooks/*.json, so install writes a
self-contained hooks/herdr.json registering a SessionStart hook next to
hooks/herdr-agent-state.sh, and never touches other hook files. The hook
prefers $GROK_SESSION_ID (injected into every grok hook process) and
reports through the socket API; herdr:grok is a reserved-native-state
source so screen detection stays authoritative. Restore uses
`grok --resume <id>`. Additive JSON API change; no protocol bump; the
schema artifact is regenerated.
refs #1800
* fix: honor GROK_HOME and validate grok hook config in status
Review follow-ups: grok_dir now resolves GROK_CONFIG_DIR (herdr test
seam) before GROK_HOME (the grok CLI's own config-home override) before
~/.grok, so hook installs land where grok actually looks. Integration
status now also validates the herdr-owned hooks/herdr.json next to the
hook script — missing, corrupt, or no-longer-referencing configs report
the install as outdated instead of masking a hook grok never invokes.
refs #1800
* fix: validate the exact grok session hook command in status
The config validator matched on a filename substring, so a SessionStart
command like `echo herdr-agent-state.sh`, or one invoking the script
without the `session` action, still reported the integration as current
while grok never delivered a session id. Status now compares against the
exact command the installer writes, via a shared builder, and the
degradation tests cover both nonfunctional shapes.
refs #1800
* fix: require a command-type grok session hook in status validation
A config entry carrying the exact generated command under a non-command
hook type (e.g. "http") is never executed by grok, so it must not report
the integration as current. The validator now also requires
type = "command", with a degradation test for the mismatched-type shape.
refs #1800
* fix: validate the complete grok hook config
refs #1800
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor corrius
chore: approve contributor adamkrellenstein
fix: report truncated pane reads
refs #1717
fix: make known-agent exit process-owned
refs #1792
refs #1648
fix: answer XTWINOPS size queries in panes
refs #835
chore: approve contributor joonhwan
fix: prefer branded homepage search image
fix: consume handled url click gestures
refs #1761
fix: preserve kitty graphics during host repaints
refs #1628
fix: inherit host palette in pane queries (#1759)
refs #1752
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor carlesso
chore: approve contributor badlogic
fix: preserve kitty printable key releases
refs #1746
fix: preserve physical escape on windows
refs #1736
fix: respect OMP config directory override
refs #1696
chore: relicense herdr under apache-2.0
refactor: centralize new terminal cwd selection
replaces contributions from Pitchfork-and-Torch
refactor: name darwin nix toolchain inputs
replaces contributions from DeevsDeevs
refactor: simplify macos input source ownership
replaces contributions from sf-jin-ku
refactor: clarify opencode event state mapping
replaces contributions from soar
refactor: simplify cursor session reporting
replaces contributions from udirom
refactor: simplify kimi lifecycle reporting
replaces contributions from wbxl2000
refactor: simplify qoder session reporting
replaces contributions from wayneleelwc
refactor: replace pane mouse and clipboard internals
replaces contributions from othavi0
feat(docs): publish versioned release documentation
fix: keep reading while pty input is blocked
refs #1295
fix: fall back to sh for remote path discovery
refs #1201
docs: add alternate-screen output fallback
docs: update preview manifest
fix(website): add agent automation to docs sidebar
docs: update website manifest for v0.7.5
release: v0.7.5
docs: finalize release docs and refresh agent skill
docs: document alternate-screen automation limits
fix: link plugins without a running server
refs #1670
fix: reject oversized text pastes safely (#1676)
refs #1665
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: bound linux sound player lifetime (#1677)
refs #1622
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: discover canonical mise remote installs
refs #1201
fix: use pi settled lifecycle event
docs: explain Windows cursor and IME trade-off
refs #1637
fix: make plugin state global across sessions
refs #1174
fix: show agent targets before options in help
fix: bound stalled agent prompt waits
fix: report kimi questions as blocked
fix: avoid rechecking cached pane cwd (#1616)
refs #1603
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: add plugin-driven agent views and startup hooks
feat: make agent automation a first-class cli primitive
fix: preserve plugin command arguments (#1613)
fix: show current workspace name in close confirmation
refs #1364
feat: connected tree glyphs, workspace grouping, and search auto-select in navigator
refs #1611
perf: cache windows foreground process snapshots
refs #1158
fix: preserve terminal live follow through resize
fix: support javascript integrations on windows
refs #1531
fix: serialize opencode lifecycle reports
refs #1519
fix: detect codex working with static titles (#1574)
* fix: detect codex working with static titles
refs #1563
* fix: ignore interrupted codex footer
refs #1563
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: report unknown config keys (#1575)
* fix: report unknown config keys
refs #1573
* fix: preserve mixed config warning context
refs #1573
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: batch contiguous terminal diff writes
refs #283
fix: preserve lone escape input boundaries
refs #541
feat: add optional workspace name prompt
fix: update windows conpty smoke for pane-first agents
feat: harden named agent cli workflows
refs #1525
docs: update preview manifest
test(windows): support headless console runners
fix(windows): prevent remaining subprocess console flashes
refs #1468
perf: adopt libghostty integration improvements
refs #276
ci: gate Greptile reviews by contributor approval
fix: detect grok background work from pinned status
fix: detect grok state from terminal signals
chore: update vendored libghostty-vt
refs #276
fix: follow foreground process group leader cwd
refs #1472
refactor: extract active tab surface rendering
fix: preserve selection when auto-copy is disabled (#1496)
refs #1471
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): suppress noninteractive process windows
refs #1468
docs: update preview manifest
fix(windows): hide agent manifest curl windows
refs #1468
fix: stop agent wait when pane closes (#1488)
chore: enable zed lsp
feat: configure collapsed sidebar startup state
refs #1463
feat: add configurable sidebar token styles
feat(macos): support agent environment hints
refs https://github.com/ogulcancelik/herdr/discussions/679
fix: preserve plugins during live handoff
refs #893
fix: handle pane graphics stream disconnect race
fix: guard cli requests against protocol mismatches (#1453)
refs #1435
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
test: wait for multi-client resize propagation
docs: update preview manifest
docs: update website manifest for v0.7.4
release: v0.7.4
docs: finalize next release documentation
docs: add popup pane usage examples
refs #1125
test: shorten pane graphics socket fixture paths
feat: add floating popup panes
refs #1125
feat: add isolated pane graphics streaming
fix: preserve escape before sgr mouse reports
refs #1334
feat(website): homepage plugin showcase, live star count, faithful claude code mock
fix(linux): scope foreground process discovery to panes
refs #1399
fix: reassemble split sgr mouse input
refs #1382
fix: preserve associated emoji input (#1410)
refs #1404
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
test: shorten macos api socket fixture path
ci: restore fast reliable checks
fix: flush live handoff responses before exit
feat: configure sidebar entry gaps
fix: stop copy mode line-end at text (#1411)
fix: forward horizontal wheel events to panes (#1402)
refs #1349
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: retry dropped omp lifecycle reports
refs #1310
fix(website): scope docs search by locale and channel
fix: forward outer focus events to panes (#1388)
* fix: forward outer focus events to panes
refs #1337
* fix: preserve ordered focus forwarding
refs #1337
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: show renamed single tabs in agents sidebar
refs #1369
fix: reap detached custom command children (#1384)
* fix: reap detached custom command children
refs #1360
* test: harden child cleanup and sidebar metrics
refs #1360
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: explain modified-arrow shell bindings
refs #1370
fix: keep Claude working during /btw
refs #1366
docs: streamline configuration guide
fix: allow slow server shutdowns
fix: detect reordered codex title spinners
refs #1281
feat: add configurable sidebar metadata tokens
docs: add versioned config reference
refactor: centralize agent identity lookup
docs: add troubleshooting guide
refs #1116
fix: number collapsed agent rows by list position
refs #1344
fix: keep windows api connections open
refs #1279
fix: match homepage mock pane chrome and sidebar to tui rendering
fix: clarify config fallback diagnostics
fix: detach windows server from host terminal
refs #1329
chore: remove unmerged approved contributors
feat: add copy-on-select setting
feat: add maki agent support (#1302)
* feat: add maki detection support
Maki always draws a one-line status bar at the bottom of the screen, so the manifest reads just that row: a braille spinner before the `[BUILD]`/`[PLAN]`/`[BASH]` mode label means working, the bare label means idle.
Blocked states come from the panels that replace the input box, the `Permission Required` dialog with its `y Allow`/`n Deny` hint rows and the `Plan complete` form. Maki emits no OSC title or progress, so these screen rules are the only evidence.
Also wires `maki` through process-name identification, per-agent sound overrides, and the website manifest catalog.
* docs: stage maki detection docs
chore: approve contributor tontinton
docs: refresh herdr agent skill
refs #1297
fix: improve config diagnostic delivery
fix: stop windows installer from rewriting config
refs #1162
fix: follow foreground cwd for new terminals
refs #1245
feat: add copy mode search and tmux word motions
refs #1230
docs: document windows config path
ci: pin rust toolchain to 1.96.1
fix: preserve explicit session sockets during live handoff
refs #1180
reported-by: dvic
based-on: https://github.com/dvic/herdr/pull/3
fix: use drawn cursor by default in wsl
refs #930
fix: reanchor pi status after session replacement (#1189)
* fix: reanchor pi status after session replacement
refs #943
* fix: guard active pi sessions from nested startup
refs #943
* fix: serialize pi session replacement reports
refs #943
fix: detect active amp turns
refs #1208
chore: approve merged contributor kovalov
fix: refresh tab bar after plugin-driven tab rename (#1179)
refs #1111
Co-authored-by: Vlad Kovalov <kovalov@users.noreply.github.com>
fix: make remote helper installs shell-portable
refs #1203
fix: match shifted indexed number keybinds
refs #1184
fix: align collapsed sidebar agent rows (#1182)
refs #1168
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: link plugin marketplace from readme
docs: lean readme, add terminal trove gold sponsor
docs: enforce localized release doc parity
refs #1151
docs: update website manifest for v0.7.3
release: v0.7.3
docs: stage 0.7.3 release notes
fix: restore workspace picker keyboard navigation
refs #1149
fix: avoid render-time plain url scans
docs: change sponsorships tiers and add lead sponsor
docs: update preview manifest
ci: ignore microsoft apt repos in artifact builds
ci: clear zig cache before windows checks
fix: keep cursor hide inside sync output
refs #967
fix: guard windows process tree cycles
refs #1083
fix: clear done status on repeated pane focus
fix: preserve navigator search commands (#1140)
Navigator search treated Escape as either modal close or query reset,
which left no way to return to command mode while keeping the filtered
row set. `/` also rebuilt search mode by clearing the query, so a user
could not resume editing the same filter after backing out.
Make Escape leave search focus only, reserve command-mode Escape for
closing the picker, and let `/` refocus the existing query. The footer
now lists the shortcuts for the active mode so command keys are not
advertised while text input owns them.
refs #1115
docs: update website manifest for v0.7.2
release: v0.7.2
docs: finalize release docs
fix: send shifted punctuation as text in kitty mode
refs #1105
fix: preserve alt-shift letters (#1102)
refs #1088
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: move session autosaves off main loop
fix: stop windows server over named pipes
refs #1113
fix: support esc
interrupt for github copilot (#1120)
* fix: support esc interrupt for github copilot
Github Copilot CLI version v1.0.69-2 introduces the "esc interrupt" prompt.
Update the Github Copilot agent detection manifest to match this prompt and correctly report the agent as working.
Add test cases in tests.rs to verify state detection.
Synchronize the website's copy of the manifest.
refs #1119
* test: clean up github copilot detection rules and tests
Clean up formatting and comments for the github copilot detection rule and tests.
refs #1119
* test: remove copilot manifest literal test
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor liby
docs: remove star history embed
fix: honor prefix in copy mode
refs #681
Based on PR #1092 by @reobin.
Co-authored-by: Robin Gagnon <me@reobin.dev>
fix: preserve wrapped pane links (#1099)
refs #1098
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: expose pane scroll state
docs: update sponsors
fix: bridge remote image file drops (#1085)
refs #828
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: add community video section
test: synchronize multi-client resize assertion
fix: clarify remote ssh auth failures (#1084)
refs #1034
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: preserve shifted punctuation for alt legacy input (#1076)
refs #1066
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: expose stats page in website nav
fix: write pane copies to native windows clipboard (#1082)
refs #1067
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: approve merged contributor akbash-bot
fix: focus parent after worktree removal (#1075)
refs #1004
Co-authored-by: akbash-bot <akbash-bot@users.noreply.github.com>
docs: update preview manifest
ci: use homebrew zig for preview macos builds
feat(website): add japanese and simplified chinese docs with i18n, translation issue flow
fix: detect grok build working and blocked states from current ui chrome (#1055)
* fix: detect grok build working and blocked states from current ui chrome
refs #1017
* fix: sync grok detection website manifest
refs #1017
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add public stats page at herdr.dev/stats
ci: accept common environment aliases in issue gate
refactor(nix): replace apple-sdk wrappers with xcbuild (#995)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: retry pi state socket reports
refs #1049
fix: support custom command keybindings on windows
refs #1041
fix: switch prefix ASCII input source on the foreground client (#1016)
* fix: switch prefix ASCII input source on the foreground client
The macOS prefix ASCII-switch ran in the headless server, whose
TISCopyCurrentKeyboardInputSource read is a stale per-process cache
(refreshed only via a main-run-loop notification the server never pumps),
so prefix could leave the terminal on the wrong input source.
Forward it to the foreground client, like clipboard: sync_prefix_input_source
emits AppEvent::PrefixInputSource as an intent; the server forwards it to the
foreground client and the monolithic app applies it in-process via
RealPrefixInputSource, which pumps its main run loop before the stale TIS read.
Key it on Mode::wants_ascii_input so multi-level prefix commands keep ASCII
until returning to the terminal, and restore the IME for rename text entry.
Adds ServerMessage::PrefixInputSource to the already-unreleased protocol 15.
refs #774
* fix: keep prefix input-source switch out of the headless server process
An App-internal drain (the exhaustive drain at the top of
handle_api_request, reachable from prefix-key runtime mutations) can
consume a queued PrefixInputSource intent before the server's
forwarding drain sees it, applying the TIS switch in the headless
server process and stranding the restore state. Gate the in-process
switch on App.local_input_source_switch, disabled by the headless
server alongside the other local side effects, so a swallowed intent
degrades to a skipped switch. Widen the forwarding-bypass maintenance
test to the handle_internal_event_with_prefix_sync wrapper.
refs #774
* docs: clarify prefix input-source comments and flag docs
refs #774
* fix: bump protocol for prefix input source
refs #774
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
test: wait for client frame before crash assertion
test: keep windows smoke cleanup non-fatal
test: wait for windows smoke pane output
fix: wait for server stop socket cleanup
chore: approve contributor TonyxSun
refactor: route headless deferred creates through runtime helpers
refactor: route cli pane placement through runtime adapters
refactor: route cli workspace tab worktree through runtime adapters
refactor: route tui runtime mutations through typed adapters
feat: expose session snapshot through cli
feat: emit layout update events for runtime layout changes
chore: approve contributor ppggff
refactor: route worktree tui actions through runtime wrappers
refactor: route pane layout tui actions through runtime wrappers
fix: allow foreground agent session takeover
refs #943
chore: approve merged contributor DevSrSouza
fix: kitty graphics streams freeze on partial updates and leak host images (#948)
* fix: request a render on kitty graphics writes
pty output containing a kitty graphics sequence only scheduled the
deferred settle render. that render's wake-up notifies the render loop
only when the dirty flag was not already set, so under a continuous
stream of image updates the notify can be dropped and the pane keeps
showing an old frame until something else forces a full render.
request an immediate render like any other output. the dirty flag and
the minimum render interval still coalesce chunked writes, and the
settle render stays as a backstop.
refs #947
* fix: fingerprint kitty images exactly across retransmissions
the image fingerprint hashed only the first, middle, and last 4096
bytes of pixel data. a program that streams updates by retransmitting
one image id keeps the length and dimensions constant, so a frame whose
changed pixels all fall outside those three windows gets the same
fingerprint as the frame before it. the encoder then treats the image
as already uploaded, emits no graphics bytes, and the frame is dropped
as identical to the previous render. the pane stays stuck on the last
uploaded image until a resize resets the graphics surface.
hash the full payload instead. to keep that off the render hot path,
cache the fingerprint per image id and recompute it only when the
image's transmit time changes. libghostty-vt already refreshes the
transmit time on every transmission; vendor patch 0002 exposes it
through a new GHOSTTY_KITTY_IMAGE_DATA_TRANSMIT_TIME_NS accessor. a
static image costs one map lookup per render and a streaming image one
hash per transmitted frame.
refs #947
* fix: delete superseded host kitty images
host image ids derive from image content, so a pane image whose pixels
change maps to a new host id on every update. nothing deleted the host
image it replaced, and a streaming pane left one full-size image behind
in the host terminal per changed frame until the graphics surface was
reset. track which host image backs each pane image and delete the
replaced one once no source references it.
refs #947
* fix: prune stale kitty graphics source entries
a source entry whose pane closed or whose placement disappeared stayed
in the cache forever. through the shared-reference check it could keep
an old host image alive that nothing visible used anymore, and the
entries themselves accumulated without bound. prune sources against
the visible set at the start of every encode pass.
refs #947
* docs: link issue and upstream discussion for vendor patch 0002
the transmit time accessor now has a removal path: the ghostty
discussion proposing it upstream is linked in the patch ledger.
refs…
- Added the missing `Stack` arm to `apply_context_menu_action_via_api`, the dispatcher every production menu activation funnels through, so selecting it now creates a pane instead of silently closing the menu
- Covered that path with a test that fails with one pane when the arm is removed, because the pre-existing test asserted against the `cfg(test)` dispatch mirror and stayed green while the real binary was broken
- Renamed the context menu item from `Split stacked` to `Stack`, since a stack is not a split
- Renamed the navigate bar entry to `stack` and the keybind help entry to `stack pane`
- Surfaced the stack action in the navigate bar, which previously offered only the two splits
- Added a TestBackend assertion that the navigate bar renders all three ways to add a pane, each with a bound key
docs: document stacked panes wherever splitting is documented
- Documented the stack layout node (`panes`, `active`) in socket-api so clients can round-trip a stacked tab through layout.export and layout.apply
- Added stacking to the pane concepts, quick-start and keyboard pages in English, Japanese and Simplified Chinese
- Added the `split_stacked` binding to the keyboard and configuration samples in all three locales
- Corrected the `pane split` and `plugin pane open` usage strings to read `right|down|stacked`, which the parsers already accepted
- Taught the embedded agent skill to reach for `--direction stacked` when another split would leave panes unusably small
- Left `pane move --split` as `right|down` because the server rejects moving a pane into a stack
chore: import fork-local justfile recipes
An optional import keeps local recipes in an ignored directory, so the
tracked justfile carries one line instead of a growing fork-only block
and a rebase has one place to conflict.
fix(input): give stack title rows priority over the split resize handle
A stack's first title row sits on the region's top border, which is the
same row a vertical split above it uses as its resize handle. Border
lookup runs before the pane hit test, so clicking the top member of a
stack below a split started a resize instead of focusing it, leaving that
member unreachable by mouse.
feat(ui): offer a stacked split in the pane menu
The pane menu offered split right and split down, so stacking was
reachable only from the keyboard. The placement enum already had the
variant, so this is wiring rather than new capability.
fix(server): keep hidden stack members out of their own title rows
The retained renderer applied every pane's dirty patch at its inner rect.
A collapsed member's inner rect is its one row title row, and collecting
a patch has no size check, so asking for one row handed back the first
row of that hidden terminal to be painted over the member's own name.
Only the span between the corners was overwritten, which is why the frame
survived while the name did not, and only while that agent was producing
output.
A collapsed member also reports its whole screen dirty for as long as it
stays hidden, because nothing else refreshes a hidden pane's render
state, so one stack was enough to drop a whole tab back to full redraws.
Skipping it fixes both, and matches what pane rendering and kitty
graphics already do.
feat(ui): draw stacked pane titles on the frame
Each member of a stack was named twice: once on the box's top border and
again on a title row of its own directly below it. The first member's
title row is now the region's own top border, so a stack costs one row
less than a box plus a row per member, and the name sits where a pane's
name already sits.
A title row is drawn as a ruled frame line opening its own corner rather
than tee-ing into one continuous box, so a stack reads as a deck of cards
rather than as one pane chopped into strips. The region's top border row
is shared with the pane above and is left to the border pass, which has
already drawn its junctions and its colour; only the title text goes
there.
A collapsed member takes a muted version of the accent instead of the
generic border grey, so a stack reads as one group of related panes.
StackSlot carries the region's borders because only the visible member
holds them, and rescanning the pane list for it would be quadratic inside
a render loop.
docs: document stacked panes and the stacked split keybind
Covers prefix+shift+s and the agent panel row change in the sample
config, the keyboard page and the config reference.
feat(ui): name panes after the agent session
A pane's name is now resolved in one place, TerminalState::display_name:
a title the agent pushed, then an explicit rename, then the agent session
name, then the terminal's own title. Pane chrome, stack title rows and
the agent panel all read it, so they cannot drift. Two of them already
had, which is how a renamed session showed on a stack row but not in the
panel.
An agent renaming its own session arrives as a terminal title, so leaving
that out of the chain made a renamed session look unnamed. The agent
session name reaches the panel through the existing pane token, and the
default second row is now agent then pane name.
pi prefixes its title with a lone glyph the same way claude does, so it
joins the set that is stripped before a title is shown. An unnamed pi
session is nothing but that glyph, which now leaves no name and falls
back to the agent label.
feat(input): add a stacked split action
prefix+shift+s puts a new pane in the focused pane's stack, creating one
if the pane is not stacked yet. It sits alongside split_vertical and
split_horizontal as a third way to place a pane, and stays prefix-first
so herdr does not start swallowing keys from shells and editors.
Moving between members needs no new action: collapsed title rows are
ordinary rects stacked vertically, so prefix+j and prefix+k already walk
a stack.
SplitDirection gains a stacked variant, which the cli accepts as
herdr pane split --direction stacked. It has no split axis, so the
conversion to a layout direction is now fallible, and pane move rejects
it before taking the source pane out of its tab rather than after.
feat(ui): render stacked pane title rows
Every member of a stack gets a title row, the visible one included, and
its terminal starts on the row directly below. Without a row of its own
the last collapsed title sat right above the visible terminal and read as
that terminal's label.
The box is drawn once around the whole region and carried by the visible
member, so the existing border joining code handles it like any other
pane. Collapsed rows carry no chrome. Chrome is decided for the region
rather than per member, otherwise the top, middle and bottom of a stack
get different borders and the visible pane's terminal changes height as
focus moves.
Kitty graphics bypass the cell buffer, so a collapsed member is skipped
when collecting placements too; otherwise a hidden pane draws images over
its own title row. A layout with no stacks costs one scan and no
allocation.
feat(layout): add a stacked pane node
Panes in a stack share one region. One shows its terminal and the rest
collapse to a single title row, so a tab with six agents no longer gives
each of them a sixth of the screen.
Unlike zellij, a collapsed pane keeps a full size terminal behind its
title row. Every member is sized to the region the visible member
occupies, so moving through a stack never resizes a pty, never reflows a
running agent, and leaves the bottom buffer that detection reads intact.
The visible member also keeps a floor of content rows, so adding members
drops title rows rather than shrinking every terminal toward nothing.
Stack membership is a session fact, so it is saved with the layout and
reported by the layout API. Restore drops dead members, keeps the visible
one in range, and turns a stack that is down to one pane back into a
plain pane. A stack holds panes rather than subtrees, and applying a
layout restores the member the caller marked visible, so exporting a
layout and applying it back reproduces the same stack.
fix: speed up alternate-screen history reads (#2426)
refs #2387
fix: keep active sidebar rows visible (#2794)
refs #2792
feat(cli): guide agents to Herdr resources
fix(docs): publish channel-aware documentation indexes
fix(docs): apply llms patch during website builds
feat(docs): publish agent-readable documentation
fix: reject prompts to blocked agents (#2790)
* fix: reject prompts to blocked agents
refs #2788
* docs: clarify agent prompt timing
refs #2788
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: detect all claude half-circle spinner frames (#2762)
refs #2760
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: wait for new pane shell readiness (#2774)
* fix: wait for new pane shell readiness
refs #2773
* refactor: share agent startup bounds
refs #2773
* fix: reconcile agent names after startup timeout
refs #2773
* fix: cover agent cleanup scheduling skew
refs #2773
* fix: bound pane shell readiness retries
refs #2773
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: keep tab and sidebar clicks when the terminal reports a stray drag (#2736)
* fix: keep tab and sidebar clicks when the terminal reports a stray drag
This works around a Ghostty bug that causes herdr tabs to be unclickable
in fullscreen mode.
Ghostty on macOS in native fullscreen emits one motion report after a
fresh press in the strip where the menu bar reveals, with the row
shifted to near the bottom of the grid. The cause is upstream: macOS
delivers one mouse event whose y is nearly a window height away from the
real pointer, and Ghostty reports it as it arrives (iTerm2 and
Terminal.app report the same clicks correctly).
Herdr treated the stray report as a real drag and lost the click two
ways: it opened a tab reorder with no drop target, making the release a
no-op, and it handed the release to the pane under the bogus
coordinates.
Now, a press on the tab bar or sidebar owns the gesture until release,
and a tab drag only starts once the pointer is over a real drop target.
refs #796
* fix: scope chrome mouse gestures to their input source
* fix: preserve chrome drag input source
* fix: preserve concurrent chrome presses
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(graphics): support high-dpi direct file frames (#2680)
fix: preserve logical lines in scrollback editor (#2735)
refs #2733
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: add qwen code detection and restore (#2743)
refs #2730
fix(agent): focus Copilot before prompting (#2734)
* fix(agent): focus Copilot before prompting
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(agent): cover stale focus-reporting state
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: strip claude title spinner frames (#2709)
* fix: source title activity glyphs from manifests
refs #2707
* fix: simplify manifest-driven title stripping
refs #2707
* fix: reconcile handoff title policies
refs #2707
* fix: strip claude title spinner frames
refs #2707
* fix: keep claude detection manifest unchanged
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: use the running binary in agent hooks (#2722)
fix: preserve workspace labels for root repositories (#2727)
refs #2594
chore: update contributor list
perf: avoid repeated Git config reads (#2688)
refs #2643
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: synchronously terminate cancelled status commands
fix: detect claude 2.1.228 half-circle busy spinner
fix: disambiguate shifted punctuation keybinds (#2676)
refs #2674
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(render): compact large terminal redraws (#2675)
refs #2670
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): reduce idle agent detection CPU (#2651)
* fix(windows): reduce idle agent detection CPU
refs #2642
* fix(windows): gate agent process discovery
refs #2642
---------
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
fix: make just build cross-platform (#2647)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: derive repo name for embedded bare layouts (#2660)
refs #2657
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: refresh english documentation
fix: wait for agent prompt readiness (#2537)
* fix: wait for agent prompt readiness
refs #2410
* fix: return pane updates after tab bar command
refs #2410
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: keep the outer terminal window title in sync with the session (#2627)
* feat: keep the outer terminal window title in sync with the session
Herdr emulates the terminals in its panes, so an OSC 0/OSC 2 title
written inside a pane stops at Herdr and never reaches the terminal
Herdr itself runs in. That outer title is what window managers read for
title bars, tab bars, and group bars, so it kept showing whatever the
shell or ssh happened to leave behind.
Add `ui.window_title`, rendered from {hostname}, {workspace}, {tab},
{pane}, and {terminal_title}, and push it to the foreground client
whenever it changes. It renders on the server, so {hostname} names the
machine the panes actually run on rather than the machine a thin remote
client runs on, and it is gated on a pending render so an idle loop
never pays for it.
A title is only remembered as delivered once a foreground client takes
it, so the first client to attach is written to rather than skipped.
`client.window_title.set` still wins over the configured title, and
clearing it now hands the title back to `ui.window_title` instead of
only "herdr".
* fix: deliver the outer window title to a newly attached client
ClientConnected assigns the foreground client directly rather than going
through promote_client_to_foreground, so clearing the sent-title cache
there missed the case that matters most: attaching a second terminal to a
running session. The title was usually unchanged, so the sync returned
early and the new terminal kept whatever its shell or ssh had left.
Key the cache on the client that received the title instead of relying on
every foreground assignment to invalidate it.
* perf: keep hidden pane output off the window title path
Output from a hidden or background pane sets needs_render without setting
needs_full_render, and the retained render plan then skips presentation
for it entirely. Syncing the title on needs_render meant every coalesced
hidden-output tick still formatted, sanitized, and allocated a title that
could not have changed, against the hidden-source early exit AGENTS.md
requires.
Every input to the title is app state, which always requests a full
render, so gate on that instead. The one exception is the focused pane's
own terminal title, which arrives through PTY parsing, so ask for a full
render when that changes and the configured title uses it.
* fix: only cache a window title a client writer received
* fix: carry an api set window title across a live handoff
* fix: make outer window title updates event-driven
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
refactor(website): clean up homepage
fix(input): ignore modified j/k/up/down in session navigator (#2377)
The Char('j')/Char('k')/Down/Up match arms in handle_navigator_key
had no modifier guard, unlike every sibling arm in the same match
block, so Ctrl+K, Alt+J, etc. also moved the navigator selection.
refs #1981
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
ci: remove automatic issue gate
fix(windows): strip elevated terminal title decoration (#2632)
fix(server): prioritize shutdown requests (#2624)
refs #2612
test(windows): serialize media player environment access (#2619)
fix: track opencode tui session selection (#2455)
refs #2450
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(ui): anchor the host cursor to modal name inputs (#2569)
* fix(ui): anchor the host cursor to modal name inputs
IMEs draw their composition preview at the host terminal cursor. The rename
and new-worktree dialogs drew a block glyph instead of setting one, so the
frame carried no cursor and the client kept the position the focused pane
last reported. Japanese composition appeared behind the dialog and only
reached the field on Enter.
Set the cursor to the caret column instead, counting wide characters as two
cells.
refs #1755
* fix(ui): keep the clamped caret cell blank
A name that fills the field left the clamped caret sitting on the last
rendered glyph. A terminal inverts the cell under its cursor and an IME
composes there, so the glyph was hidden and composition overlapped it.
Render the text one column short of the field. The field is still cleared
in full, so the clamped caret always lands on a blank cell.
refs #1755
---------
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: center tab labels for symmetric highlight padding (#2570)
* fix: center tab labels for symmetric highlight padding
* docs: note centered tab labels in the changelog
* fix: center tab labels by display width, not char count
feat: add move tab keybind actions (#2561)
* feat: add move tab keybind actions
Add optional keys.move_tab_previous/move_tab_next actions that reorder
the active tab one position, wrapping at either end. Reuses the
existing tab.move runtime path that mouse drag reordering already
drives.
* fix: exit navigate mode on single-tab move attempts
feat: add configurable tab bar status (#2586)
* feat: show a zoom indicator in the desktop tab bar
Reserve the right edge of the tab row for a ZOOM pill while the
focused pane is zoomed, matching the accent style of the mode bars.
The per-tab Z suffix stays; the pill makes the zoomed state visible
at a glance like tmux's status-right flag.
* feat: optionally show the hostname in the desktop tab bar
Add ui.tab_bar_hostname to display the machine's hostname at the right
edge of the tab row, like tmux's #h in status-right. The value resolves
where the server renders, so remote sessions show the remote host. Off
by default.
* fix: strip control characters from the tab bar hostname
* fix: hide the hostname when it would squeeze out the tab strip
* feat: add configurable tab bar status
* fix: harden tab bar status updates
* fix: terminate tab bar status process trees
* fix: disable status commands on unsupported platforms
* fix: skip unchanged status command renders
* fix: keep tab bar status opt-in by default
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
test: guard pane-scaled render performance
refs #2550
feat: add direct pane resize keybindings (#2558)
fix(client): avoid abort on terminal hangup (#2427)
* fix(client): avoid abort on terminal hangup
refs #2424
* test(client): gate PTY integration on unix
refs #2424
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
perf(ui): avoid full pane mode reads for scrollbars (#2554)
fix(input): preserve alt-prefixed control keys (#2543)
refs #2514
fix(website): improve plugins page readability on dark ground
fix(ui): reclaim scrollbar gutter in alternate screen (#2538)
feat(graphics): add direct pane frame streaming (#2523)
* feat(graphics): add direct pane frame streaming
* feat(graphics): expose pane visibility
* test(graphics): preserve legacy terminal image output
* fix(graphics): harden streaming lifecycle
* fix(input): preserve mouse releases outside panes
feat: make outer pane borders configurable (#2535)
fix: make windows installer swaps atomic (#2530)
refs #2356
feat(input): add per-pane right-click routing (#2504)
chore: approve dhh as contributor
fix: forward pane terminal bells (#2498)
refs #2453
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: support all agent integrations on windows (#2496)
fix(windows): share Git Bash agent candidate scans (#2494)
refs #2459
fix(config): report unknown theme names (#2488)
refs #2452
fix: avoid redundant Windows recent-history snapshots (#2474)
refs #962
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve shift in kitty alternate reports (#2479)
refs #2435
fix(remote): restore blocking bridge streams (#2485)
refs #2478
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat(website): rebuild compare page in new design with runtime positioning
fix: verify stable release checksums
fix: publish stable release checksums
chore: update website
feat(marketplace): track star history for trending and new plugin surfaces
fix(theme): refresh host appearance on focus (#2417)
* fix(theme): refresh host appearance on focus
refs #2416
* fix(input): preserve split appearance replies
refs #2416
* fix(input): retain fragmented appearance reports
refs #2416
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(detect): ignore Cursor Run Everything status (#2220)
* fix(detect): ignore Cursor Run Everything status
refs #1763
* fix(detect): constrain Cursor approval controls
refs #1763
* test(detect): remove cursor manifest behavior fixture
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: add positive idle detection for kiro-cli prompt (#2301)
* fix: add positive idle detection for kiro-cli prompt
refs discussion #982
* fix: remove manifest integration tests per reviewer request
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat(copy-mode): add big-word motions (#2270)
Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(terminal): restore keyboard reporting on detach (#2395)
refs #2393
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize versioned Python agent wrappers (#2188)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: document custom agent integrations
fix(cli): accept --flag=value and reordered options in pane read/wait-output (#2183)
* fix(cli): accept --flag=value and reordered options in pane read/wait-output
* test(cli): trim redundant pane parser coverage
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: keep plugin marketplace counts current
fix: render OSC 4 palette overrides instead of forwarding the index (#2162)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: avoid ctrl-tab escape sequences in legacy panes
refs #2296
fix(ci): repair contributor gate handling
chore: update canonical repository references
ci: restore approved contributor gate
fix(sidebar): highlight active agent in collapsed sidebar (#2382)
The collapsed sidebar renders agent rows with an unconditional
Style::default().fg(p.overlay0), so the active agent is
indistinguishable from the others. The workspace list directly above
it, and render_agent_detail in the expanded sidebar, both mark the
active entry.
Reuse the existing active treatment: resolve the active entry with the
same is_active_pane call the expanded agent panel uses, then paint the
row background with surface_dim and the position number with text, the
same tokens the collapsed workspace rows already use.
Assisted-By: devx/717e5259-915f-4a7b-af07-6abe46da5b90
feat(windows): support remote attach to unix hosts (#2329)
* feat(windows): support remote attach to unix hosts
* fix(remote): preserve unix bridge behavior
fix(website): update author X profile
chore: remove project-local worktree extension
refs #2325
docs: refresh readme and sponsors
feat(theme): add optional sidebar background
fix(config): accept retired agent panel scope (#2295)
refs #2292
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve modifyOtherKeys key releases (#2303)
refs #2302
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): make issue gate structural
fix(terminal): render halfwidth katakana voiced marks (#2257)
Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(layout): return focus to the pane a split was opened from (#2266)
Closing a focused pane handed focus to the next pane in tree order.
For a pane opened beside another one -- a plugin split, a file viewer,
any transient tool pane -- that is rarely where the user was: it lands
on some unrelated neighbour rather than the pane that opened it.
Track the pane focus came from in TileLayout and prefer it when the
focused pane closes, falling back to tree order when there is no
history, when it points at the pane being closed, or when it points at
a pane that has since gone away. The history lives in the layout, so it
can only ever name a pane in the same tab.
A one-slot history is only sound if internal focus excursions never
write it, so the tree edits that used to bounce focus around now go
through target-taking primitives instead. close_pane removes a
background pane directly, so detach_pane and take_pane_for_move stop
focus-close-refocusing. split_pane splits a target without moving
focus: the runtime split path only focuses the new pane once the spawn
succeeds, which makes a failed split a pure rollback, and the targeted
and unfocused workspace split paths stop fabricating history.
insert_pane_near now takes the focus intent, so an unfocused pane move
leaves the target tab's history alone. The layout-level focused-split
helpers become test-only; production splits all flow through the
target-taking path.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ui): search single-tab names in navigator (#2320)
fix(input): parse default mouse reports (#2312)
* fix(input): parse default mouse reports
refs #2309
* fix(input): preserve split default mouse reports
refs #2309
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(cli): resolve pane query --current from caller (#2298)
refs #2297
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): keep pending url clicks across host focus loss (#2291)
Opening a URL raises the browser, which takes focus away from the host
terminal before the mouse release arrives. release_input_source(_headless)
cleared pending_url_click_sources on that focus loss, so the release was
forwarded to the pane and the agent opened the same URL again.
Clear the set in clear_input_source instead, whose only production caller
is remove_client.
refs #2290
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
feat(ui): add distinct status indicators (#2282)
refs #2260
fix: detect claude confirmation prompts
refs #2268
fix(website): copy heading links to clipboard
fix(ui): preserve sidebar scroll across clients (#2280)
refs #2255
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): preserve shift-tab in pane automation (#2259)
refs #1561
fix(docs): allow corrections to published versions
refs #916
feat(plugins): index marketplace manifests
docs: publish preview documentation
fix(ui): keep collapsed workspace status visible (#2239)
refs #2216
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: refine cpu optimization blog post
docs: update website manifest for v0.8.0
release: v0.8.0
docs: finalize 0.8.0 release documentation
feat(website): rebuild marketing pages on new brand chassis
fix: page keys scroll pane scrollback at zsh and REPL prompts (#2191)
* fix: page keys scroll pane scrollback at zsh and REPL prompts
PageUp/PageDown were forwarded to the pane whenever DECCKM (application
cursor) was on, assuming only primary-screen pagers enable it, but zsh's
line editor also enables DECCKM, as do REPLs such as python3. The result
was PageUp scrolling shell history instead of Herdr scrollback.
Bracketed paste discriminates the two: it means the app accepts typed or
pasted text at a prompt, so line editors enable it and pagers do not.
* test: update page key state fixture
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(pi): restrict state reporting to tui sessions (#2159)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: propagate host color scheme to pane apps (#2214)
refs #714
fix(input): preserve hover during extended-button drags
fix(docs): support older git in snapshot checks
fix(docs): publish only released documentation
fix: avoid blocking on foreground cwd checks (#2213)
refs #2206
fix(cli): report non-UTF-8 arguments instead of panicking (#2207)
* fix(cli): report non-UTF-8 arguments instead of panicking
* fix(cli): avoid echoing malformed arguments
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(client): query host cell size when the ioctl reports no pixels (#2160)
fix: preserve claude settings formatting (#2089)
refs #2066
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: stop advertising worktree json flag (#2174)
refs #2171
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize opencode2 as opencode
refs #2169
fix: route vscode remote copies through osc52 (#2173)
refs #2015
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): detect agents across git bash exec boundaries (#2170)
refs #2107
fix(socket_paths): remove dead if-branch in derive_client_socket_from_api_socket (#2157)
fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard (#2165)
* fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard
refs #2164
* fix(input): update control-byte matrix test for 0x1f -> Ctrl+_
feat: add antigravity-cli integration (#2087)
* feat: add antigravity_cli integration harness
Register the `antigravity_cli` target, resolve its configuration
directory to `~/.gemini/antigravity-cli/`, wire target actions,
and add lifecycle hook scripts for Unix and Windows.
* feat: support session resume for antigravity-cli
* fix: correct antigravity-cli hook config path, shape, and agent label
Antigravity CLI reads global customizations from ~/.gemini/config, keys
hooks.json by hook name, and only accepts the matcher/hooks wrapper for
the tool events. The previous install wrote event arrays at the top level
of ~/.gemini/antigravity-cli/hooks.json, which agy never reads and would
reject anyway, so no Herdr hook ever ran.
Session reports were dropped for a third reason: the hooks reported the
agent as antigravity-cli, but the server normalizes that to the canonical
label agy before matching, so is_official_agent_source never matched and
agy --conversation resume was unreachable.
- Resolve the config dir to ~/.gemini/config
- Nest Herdr entries under a Herdr-owned "herdr" block that install
rewrites and uninstall removes, leaving other named hooks untouched
- Emit grouped entries for PreToolUse/PostToolUse and flat handler lists
for PreInvocation/PostInvocation/Stop
- Report the canonical agy label from both hook assets and match it in
agent_resume
- Compile-gate the hook asset constants and stop shadowing $args in the
PowerShell hook
- Document the real directory, that it must already exist, and the
named-block behavior
refs #1011
refs #1571
* fix: make antigravity-cli integration session-only
antigravity cli cannot express lifecycle safely: there is no blocked
event, postinvocation is skipped on interruption, and stop fires at the
end of a turn rather than on process exit, which left stale state and
released authority at the wrong time.
report only the conversation on preinvocation and let screen detection
own agent state. resume via `agy --conversation <id>` is unchanged.
* fix: update antigravity session after conversation switch
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): skip pr gate in forks
feat(ui): make pane scrollbars optional (#2166)
refs #2167
fix: expand copy-mode word-end window past a final wide glyph (#2145)
point_is_final_atom compared an atom's terminating column against a
word-motion target's starting column. The two are equal for narrow
cells but never for wide ones, so the read window stopped expanding
and copy-mode `e` halted at the soft-wrap boundary on CJK text.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: report a clear cli error when no herdr server is running (#1963)
* fix: report a clear cli error when no herdr server is running
socket cli commands surfaced a raw io::Error debug string
(`Error: Os { code: 2, ... }`) when nothing was listening on the
api socket, which read like a bad --cwd path. map dead-socket
connect failures to a `server_not_running` json error carrying the
resolved socket path, printed once at the edge that surfaces the
error; recovering callers (plugin offline registry fallback, agent
start polling) recognize the marker and keep their existing
behavior.
refs #1941
* fix: map dead-socket errors on the unchecked cli request path
refs #1941
* fix: make server-not-running guidance session-aware
refs #1941
fix(windows): preserve semantic escape key taps
fix(input): preserve native key lifecycle across routing (#2142)
refs #2077
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
chore: remove experiments from settings tui
feat: support bottom tab bar placement (#2118)
* feat: support bottom tab bar placement
* fix: preserve mouse cleanup under bottom mode bar
refs #2117
chore: update agentmd for protocol changes
fix: read alternate-screen agent history
fix(sidebar): keep worktree groups packed
fix(client): restore terminal on sighup and sigterm
Enable termination-signal handling so SIGHUP and SIGTERM follow the graceful
quit path and restore terminal state. Log handler registration failures and
add PTY coverage for direct SIGHUP and server EOF restoration
Co-authored-by: Matt Coles <macols@amazon.com>
fix: preserve windows sessions after ssh logout (#2098)
* fix: preserve windows sessions after ssh logout
refs #2008
* chore: document windows wmi safety
refs #2008
fix(omp): support Windows session paths (#2092)
fix: resume agents after headless restore (#2088)
refs #2064
ci: consolidate ai review trigger label
fix: launch argument-free agents on windows (#2075)
refs #2072
fix: add opt-in child-group process detection (#2052)
* fix: add opt-in child-group process detection
refs #1982
* fix: preserve lifecycle probes without foreground groups
refs #1982
fix: preserve kitty associated text (#2051)
refs #2020
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: finish repository organization migration
Update rose pine surface_dim colour to "Overlay" (#2002)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: update repository links after organization transfer
ci: allow repository organization migration
fix: scope agent skill installation
refs #2022
docs: update preview manifest
fix(windows): preserve parent agent ownership
refs #1514
fix: preserve windows path variables during install
refs #1947
test(windows): remove flaky sound timing assertion
refs #1330
fix(windows): restore system notifications and sound playback (#2019)
ci: remove approved contributor bypass
chore: approve merged contributor we11adam
fix: preserve navigate mode after pane focus (#1993)
refs #1850
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: approve merged contributor patrick-xin
docs: add simplified chinese readme (#1990)
* docs: add simplified chinese readme
* fix: publish simplified chinese readme
* fix: require localized readme for releases
* docs: publish simplified chinese readme
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: restore python3 commit hook
fix: select windows python command in commit hook (#1994)
chore: approve merged contributor bioform
fix: count ptmx master fds under devpts layouts (#1984)
live_server_holds_one_pty_master_fd_per_pane counted only /proc/<pid>/fd links
resolving to exactly /dev/ptmx. On devpts setups such as WSL2 and many
containers, a PTY master fd resolves to /dev/pts/ptmx instead, so the test found
zero masters and failed with "had 0 ptmx master fds; expected 1" even though the
server held the pane's master fd. Match both ptmx node paths; pty slaves still
resolve to /dev/pts/<N> and stay uncounted, so the one-master-per-pane invariant
is unchanged.
perf: skip rendering hidden pty updates
fix: preserve linked worktree workspace labels
perf: replace agent spinners with static status marks
fix: ignore nested codex session reports (#1927)
* fix: ignore nested codex session reports
refs #1789
* test: cover matching codex thread id
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: resolve relative plugin commands from plugin root
refs #1949
docs: update sponsor acknowledgements
fix: keep focus on the current workspace when another self-closes (#1912)
handle_pane_died only clamped the stale active/selected indices after
removing a workspace that closed itself, so it never shifted them down
when the removed workspace sat before the focused one. With workspaces
[x, y, z] and focus on y, removing x left active pointing at z, silently
moving the user into a workspace they did not select.
Resolve both indices by workspace id across the removal, as
close_selected_workspace already does, keeping the clamp as the fallback
for when the removed workspace was the focused one. Also scroll the
focused workspace back into view, which the explicit-close path already
did and this one did not.
refs #1621
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: make native windows checks reliable (#1925)
chore: approve merged contributor season179
fix: close workspace when api closes its last tab (#1899)
herdr tab close on a workspace's only tab returned tab_close_failed,
while the TUI close-tab action on the same tab closes the tab and
cascades to closing the workspace. Cascade in the API too, emitting
tab.closed then workspace.closed. When the cascade would close a whole
worktree group, return confirmation_required instead, matching
pane.close and the TUI prompt.
refs #1760
chore: approve merged contributor Pimpmuckl
fix: preserve shift-enter in windows panes (#1909)
refs #1743
fix: delay agent prompt submission
refs #1878
fix: ignore empty clipboard writes
refs #1893
fix: restrict unapproved pull requests to bug fixes
ci: harden pull request workflow execution
chore: approve merged contributor olafkfreund
fix(nix): include SKILL.md in the package fileset (#1890)
refs #1889
fix: repaint after transient terminal resizes
fix: preserve prefix mode for modifier events
refs #1870
feat: print bundled agent skill and hint next cli steps
chore: approve merged contributor yianL
fix: preserve focus when closing a non-focused workspace (#1877)
refs #1328
fix: support non-us shifted keybindings (#1876)
* fix: support non-us shifted keybindings
refs #1870
* docs: require current pull request base
fix: improve sidebar worktree hierarchy and reordering (#1873)
* fix: clarify sidebar worktree hierarchy
refs #1694
* feat: reorder worktree groups as a unit
refs #1694
fix: avoid renders for passive mouse motion (#1872)
refs #1865
perf: avoid full pane renders for spinner animation (#1868)
ci: gate pull request review by scope
fix(nix): add rust-analyzer to development shell
chore: consolidate project skills
docs: define maintainer and agent contribution workflows
feat: switch IME to ASCII in prefix mode on Windows (Korean IME) (#1823)
* feat: switch IME to ASCII in prefix mode on Windows
Extend switch_ascii_input_source_in_prefix to Windows: detect IME state
via WM_IME_CONTROL and toggle to ASCII with SendInput for the Korean IME.
Other IME languages are detected and left unchanged.
refs #1802
* docs: clarify Windows (Korean IME) support for prefix ASCII switching
Follow-up to the Windows prefix ASCII switch, which extended
switch_ascii_input_source_in_prefix to Windows but left the surrounding
text describing macOS only.
- Settings row label: "(macOS)" -> "(macOS/Windows)", plus its test.
- Generalize the Windows behavior wording to "switches the IME to
English (ASCII) input" in the config-reference.json entry and the
model.rs doc comment, and state that Windows support is currently
limited to the Korean IME.
- Add a :::caution aside noting the Korean-IME-only limitation to the
en/ja/zh preview docs, keeping the three translations in sync.
refs #1802
* fix: warn when prefix IME toggle injection is incomplete
SendInput can queue fewer events than requested (for example when blocked
by UIPI), which would otherwise leave the IME silently stuck in ASCII or
native mode. Log a warning with the sent and expected counts so the failure
is diagnosable.
refs #1802
* fix: guard prefix IME restore and correct open-status naming
Address maintainer review on the Windows prefix ASCII switch:
- Restore only when safe: store the foreground window at switch time and,
before toggling back, require that the same window is still focused and
the IME is still in English. This stops restore from toggling another
application or overriding a manual return to Hangul during prefix mode.
- Report injection success from send_vk_tap and only arm restoration when
the initial toggle landed; on a partial injection retry the dropped
key-up so a key is not left logically held down. The injection policy is
split into send_vk_tap_with(inject) so the success, partial, and failure
branches are unit-tested without the real SendInput.
- Correct the WM_IME_CONTROL sub-command naming: 0x0005 is IMC_GETOPENSTATUS
(IME open state), not IMC_GETCONVERSIONMODE. Behavior is unchanged; the
constant, comments, and tests now describe the open-status read.
refs #1802
* fix: bound IME open-status read with a timeout
The prefix IME switch reads IMC_GETOPENSTATUS via WM_IME_CONTROL, which
crosses into the terminal-emulator process. A plain SendMessageW would block
herdr's client thread until that process responds, indefinitely if it hangs.
Read through SendMessageTimeoutW with SMTO_ABORTIFHUNG and a short timeout
instead; on timeout the switch is skipped and restore does nothing, so a hung
host process can no longer freeze prefix-mode entry or exit.
refs #1802
* fix: preserve windows ime restoration after partial injection
refs #1802
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
perf: eliminate repeated workspace git discovery (#1842)
* perf: eliminate repeated workspace git discovery
refs #1838
* fix: keep workspace labels current without extra redraws
refs #1838
* fix: retain discovered workspace git metadata
refs #1838
fix: copy retained mouse selections with keyboard shortcuts
refs #1782
fix: run pi worktree ext on background
chore: approve merged contributor ogulcancelik
fix: bundle modern ConPTY on Windows (#1828)
refs #1533
refs #1644
fix: harden hermes lifecycle detection
feat: filter keybind help (#1832)
* feat: filter keybind help
refs #1825
* fix: recognize shifted slash in keybind help
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add grok cli integration for native session restore (#1807)
* feat: add grok cli integration for native session restore
tl;dr: adds `herdr integration install grok` (session-identity tier: a
SessionStart hook reports the grok session id for native restore; state
stays screen-detected via the bundled manifest).
Grok merges every ~/.grok/hooks/*.json, so install writes a
self-contained hooks/herdr.json registering a SessionStart hook next to
hooks/herdr-agent-state.sh, and never touches other hook files. The hook
prefers $GROK_SESSION_ID (injected into every grok hook process) and
reports through the socket API; herdr:grok is a reserved-native-state
source so screen detection stays authoritative. Restore uses
`grok --resume <id>`. Additive JSON API change; no protocol bump; the
schema artifact is regenerated.
refs #1800
* fix: honor GROK_HOME and validate grok hook config in status
Review follow-ups: grok_dir now resolves GROK_CONFIG_DIR (herdr test
seam) before GROK_HOME (the grok CLI's own config-home override) before
~/.grok, so hook installs land where grok actually looks. Integration
status now also validates the herdr-owned hooks/herdr.json next to the
hook script — missing, corrupt, or no-longer-referencing configs report
the install as outdated instead of masking a hook grok never invokes.
refs #1800
* fix: validate the exact grok session hook command in status
The config validator matched on a filename substring, so a SessionStart
command like `echo herdr-agent-state.sh`, or one invoking the script
without the `session` action, still reported the integration as current
while grok never delivered a session id. Status now compares against the
exact command the installer writes, via a shared builder, and the
degradation tests cover both nonfunctional shapes.
refs #1800
* fix: require a command-type grok session hook in status validation
A config entry carrying the exact generated command under a non-command
hook type (e.g. "http") is never executed by grok, so it must not report
the integration as current. The validator now also requires
type = "command", with a degradation test for the mismatched-type shape.
refs #1800
* fix: validate the complete grok hook config
refs #1800
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor corrius
chore: approve contributor adamkrellenstein
fix: report truncated pane reads
refs #1717
fix: make known-agent exit process-owned
refs #1792
refs #1648
fix: answer XTWINOPS size queries in panes
refs #835
chore: approve contributor joonhwan
fix: prefer branded homepage search image
fix: consume handled url click gestures
refs #1761
fix: preserve kitty graphics during host repaints
refs #1628
fix: inherit host palette in pane queries (#1759)
refs #1752
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor carlesso
chore: approve contributor badlogic
fix: preserve kitty printable key releases
refs #1746
fix: preserve physical escape on windows
refs #1736
fix: respect OMP config directory override
refs #1696
chore: relicense herdr under apache-2.0
refactor: centralize new terminal cwd selection
replaces contributions from Pitchfork-and-Torch
refactor: name darwin nix toolchain inputs
replaces contributions from DeevsDeevs
refactor: simplify macos input source ownership
replaces contributions from sf-jin-ku
refactor: clarify opencode event state mapping
replaces contributions from soar
refactor: simplify cursor session reporting
replaces contributions from udirom
refactor: simplify kimi lifecycle reporting
replaces contributions from wbxl2000
refactor: simplify qoder session reporting
replaces contributions from wayneleelwc
refactor: replace pane mouse and clipboard internals
replaces contributions from othavi0
feat(docs): publish versioned release documentation
fix: keep reading while pty input is blocked
refs #1295
fix: fall back to sh for remote path discovery
refs #1201
docs: add alternate-screen output fallback
docs: update preview manifest
fix(website): add agent automation to docs sidebar
docs: update website manifest for v0.7.5
release: v0.7.5
docs: finalize release docs and refresh agent skill
docs: document alternate-screen automation limits
fix: link plugins without a running server
refs #1670
fix: reject oversized text pastes safely (#1676)
refs #1665
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: bound linux sound player lifetime (#1677)
refs #1622
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: discover canonical mise remote installs
refs #1201
fix: use pi settled lifecycle event
docs: explain Windows cursor and IME trade-off
refs #1637
fix: make plugin state global across sessions
refs #1174
fix: show agent targets before options in help
fix: bound stalled agent prompt waits
fix: report kimi questions as blocked
fix: avoid rechecking cached pane cwd (#1616)
refs #1603
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: add plugin-driven agent views and startup hooks
feat: make agent automation a first-class cli primitive
fix: preserve plugin command arguments (#1613)
fix: show current workspace name in close confirmation
refs #1364
feat: connected tree glyphs, workspace grouping, and search auto-select in navigator
refs #1611
perf: cache windows foreground process snapshots
refs #1158
fix: preserve terminal live follow through resize
fix: support javascript integrations on windows
refs #1531
fix: serialize opencode lifecycle reports
refs #1519
fix: detect codex working with static titles (#1574)
* fix: detect codex working with static titles
refs #1563
* fix: ignore interrupted codex footer
refs #1563
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: report unknown config keys (#1575)
* fix: report unknown config keys
refs #1573
* fix: preserve mixed config warning context
refs #1573
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: batch contiguous terminal diff writes
refs #283
fix: preserve lone escape input boundaries
refs #541
feat: add optional workspace name prompt
fix: update windows conpty smoke for pane-first agents
feat: harden named agent cli workflows
refs #1525
docs: update preview manifest
test(windows): support headless console runners
fix(windows): prevent remaining subprocess console flashes
refs #1468
perf: adopt libghostty integration improvements
refs #276
ci: gate Greptile reviews by contributor approval
fix: detect grok background work from pinned status
fix: detect grok state from terminal signals
chore: update vendored libghostty-vt
refs #276
fix: follow foreground process group leader cwd
refs #1472
refactor: extract active tab surface rendering
fix: preserve selection when auto-copy is disabled (#1496)
refs #1471
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): suppress noninteractive process windows
refs #1468
docs: update preview manifest
fix(windows): hide agent manifest curl windows
refs #1468
fix: stop agent wait when pane closes (#1488)
chore: enable zed lsp
feat: configure collapsed sidebar startup state
refs #1463
feat: add configurable sidebar token styles
feat(macos): support agent environment hints
refs https://github.com/ogulcancelik/herdr/discussions/679
fix: preserve plugins during live handoff
refs #893
fix: handle pane graphics stream disconnect race
fix: guard cli requests against protocol mismatches (#1453)
refs #1435
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
test: wait for multi-client resize propagation
docs: update preview manifest
docs: update website manifest for v0.7.4
release: v0.7.4
docs: finalize next release documentation
docs: add popup pane usage examples
refs #1125
test: shorten pane graphics socket fixture paths
feat: add floating popup panes
refs #1125
feat: add isolated pane graphics streaming
fix: preserve escape before sgr mouse reports
refs #1334
feat(website): homepage plugin showcase, live star count, faithful claude code mock
fix(linux): scope foreground process discovery to panes
refs #1399
fix: reassemble split sgr mouse input
refs #1382
fix: preserve associated emoji input (#1410)
refs #1404
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
test: shorten macos api socket fixture path
ci: restore fast reliable checks
fix: flush live handoff responses before exit
feat: configure sidebar entry gaps
fix: stop copy mode line-end at text (#1411)
fix: forward horizontal wheel events to panes (#1402)
refs #1349
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: retry dropped omp lifecycle reports
refs #1310
fix(website): scope docs search by locale and channel
fix: forward outer focus events to panes (#1388)
* fix: forward outer focus events to panes
refs #1337
* fix: preserve ordered focus forwarding
refs #1337
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: show renamed single tabs in agents sidebar
refs #1369
fix: reap detached custom command children (#1384)
* fix: reap detached custom command children
refs #1360
* test: harden child cleanup and sidebar metrics
refs #1360
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: explain modified-arrow shell bindings
refs #1370
fix: keep Claude working during /btw
refs #1366
docs: streamline configuration guide
fix: allow slow server shutdowns
fix: detect reordered codex title spinners
refs #1281
feat: add configurable sidebar metadata tokens
docs: add versioned config reference
refactor: centralize agent identity lookup
docs: add troubleshooting guide
refs #1116
fix: number collapsed agent rows by list position
refs #1344
fix: keep windows api connections open
refs #1279
fix: match homepage mock pane chrome and sidebar to tui rendering
fix: clarify config fallback diagnostics
fix: detach windows server from host terminal
refs #1329
chore: remove unmerged approved contributors
feat: add copy-on-select setting
feat: add maki agent support (#1302)
* feat: add maki detection support
Maki always draws a one-line status bar at the bottom of the screen, so the manifest reads just that row: a braille spinner before the `[BUILD]`/`[PLAN]`/`[BASH]` mode label means working, the bare label means idle.
Blocked states come from the panels that replace the input box, the `Permission Required` dialog with its `y Allow`/`n Deny` hint rows and the `Plan complete` form. Maki emits no OSC title or progress, so these screen rules are the only evidence.
Also wires `maki` through process-name identification, per-agent sound overrides, and the website manifest catalog.
* docs: stage maki detection docs
chore: approve contributor tontinton
docs: refresh herdr agent skill
refs #1297
fix: improve config diagnostic delivery
fix: stop windows installer from rewriting config
refs #1162
fix: follow foreground cwd for new terminals
refs #1245
feat: add copy mode search and tmux word motions
refs #1230
docs: document windows config path
ci: pin rust toolchain to 1.96.1
fix: preserve explicit session sockets during live handoff
refs #1180
reported-by: dvic
based-on: https://github.com/dvic/herdr/pull/3
fix: use drawn cursor by default in wsl
refs #930
fix: reanchor pi status after session replacement (#1189)
* fix: reanchor pi status after session replacement
refs #943
* fix: guard active pi sessions from nested startup
refs #943
* fix: serialize pi session replacement reports
refs #943
fix: detect active amp turns
refs #1208
chore: approve merged contributor kovalov
fix: refresh tab bar after plugin-driven tab rename (#1179)
refs #1111
Co-authored-by: Vlad Kovalov <kovalov@users.noreply.github.com>
fix: make remote helper installs shell-portable
refs #1203
fix: match shifted indexed number keybinds
refs #1184
fix: align collapsed sidebar agent rows (#1182)
refs #1168
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: link plugin marketplace from readme
docs: lean readme, add terminal trove gold sponsor
docs: enforce localized release doc parity
refs #1151
docs: update website manifest for v0.7.3
release: v0.7.3
docs: stage 0.7.3 release notes
fix: restore workspace picker keyboard navigation
refs #1149
fix: avoid render-time plain url scans
docs: change sponsorships tiers and add lead sponsor
docs: update preview manifest
ci: ignore microsoft apt repos in artifact builds
ci: clear zig cache before windows checks
fix: keep cursor hide inside sync output
refs #967
fix: guard windows process tree cycles
refs #1083
fix: clear done status on repeated pane focus
fix: preserve navigator search commands (#1140)
Navigator search treated Escape as either modal close or query reset,
which left no way to return to command mode while keeping the filtered
row set. `/` also rebuilt search mode by clearing the query, so a user
could not resume editing the same filter after backing out.
Make Escape leave search focus only, reserve command-mode Escape for
closing the picker, and let `/` refocus the existing query. The footer
now lists the shortcuts for the active mode so command keys are not
advertised while text input owns them.
refs #1115
docs: update website manifest for v0.7.2
release: v0.7.2
docs: finalize release docs
fix: send shifted punctuation as text in kitty mode
refs #1105
fix: preserve alt-shift letters (#1102)
refs #1088
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: move session autosaves off main loop
fix: stop windows server over named pipes
refs #1113
fix: support esc
interrupt for github copilot (#1120)
* fix: support esc interrupt for github copilot
Github Copilot CLI version v1.0.69-2 introduces the "esc interrupt" prompt.
Update the Github Copilot agent detection manifest to match this prompt and correctly report the agent as working.
Add test cases in tests.rs to verify state detection.
Synchronize the website's copy of the manifest.
refs #1119
* test: clean up github copilot detection rules and tests
Clean up formatting and comments for the github copilot detection rule and tests.
refs #1119
* test: remove copilot manifest literal test
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor liby
docs: remove star history embed
fix: honor prefix in copy mode
refs #681
Based on PR #1092 by @reobin.
Co-authored-by: Robin Gagnon <me@reobin.dev>
fix: preserve wrapped pane links (#1099)
refs #1098
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: expose pane scroll state
docs: update sponsors
fix: bridge remote image file drops (#1085)
refs #828
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: add community video section
test: synchronize multi-client resize assertion
fix: clarify remote ssh auth failures (#1084)
refs #1034
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: preserve shifted punctuation for alt legacy input (#1076)
refs #1066
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: expose stats page in website nav
fix: write pane copies to native windows clipboard (#1082)
refs #1067
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: approve merged contributor akbash-bot
fix: focus parent after worktree removal (#1075)
refs #1004
Co-authored-by: akbash-bot <akbash-bot@users.noreply.github.com>
docs: update preview manifest
ci: use homebrew zig for preview macos builds
feat(website): add japanese and simplified chinese docs with i18n, translation issue flow
fix: detect grok build working and blocked states from current ui chrome (#1055)
* fix: detect grok build working and blocked states from current ui chrome
refs #1017
* fix: sync grok detection website manifest
refs #1017
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add public stats page at herdr.dev/stats
ci: accept common environment aliases in issue gate
refactor(nix): replace apple-sdk wrappers with xcbuild (#995)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: retry pi state socket reports
refs #1049
fix: support custom command keybindings on windows
refs #1041
fix: switch prefix ASCII input source on the foreground client (#1016)
* fix: switch prefix ASCII input source on the foreground client
The macOS prefix ASCII-switch ran in the headless server, whose
TISCopyCurrentKeyboardInputSource read is a stale per-process cache
(refreshed only via a main-run-loop notification the server never pumps),
so prefix could leave the terminal on the wrong input source.
Forward it to the foreground client, like clipboard: sync_prefix_input_source
emits AppEvent::PrefixInputSource as an intent; the server forwards it to the
foreground client and the monolithic app applies it in-process via
RealPrefixInputSource, which pumps its main run loop before the stale TIS read.
Key it on Mode::wants_ascii_input so multi-level prefix commands keep ASCII
until returning to the terminal, and restore the IME for rename text entry.
Adds ServerMessage::PrefixInputSource to the already-unreleased protocol 15.
refs #774
* fix: keep prefix input-source switch out of the headless server process
An App-internal drain (the exhaustive drain at the top of
handle_api_request, reachable from prefix-key runtime mutations) can
consume a queued PrefixInputSource intent before the server's
forwarding drain sees it, applying the TIS switch in the headless
server process and stranding the restore state. Gate the in-process
switch on App.local_input_source_switch, disabled by the headless
server alongside the other local side effects, so a swallowed intent
degrades to a skipped switch. Widen the forwarding-bypass maintenance
test to the handle_internal_event_with_prefix_sync wrapper.
refs #774
* docs: clarify prefix input-source comments and flag docs
refs #774
* fix: bump protocol for prefix input source
refs #774
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
test: wait for client frame before crash assertion
test: keep windows smoke cleanup non-fatal
test: wait for windows smoke pane output
fix: wait for server stop socket cleanup
chore: approve contributor TonyxSun
refactor: route headless deferred creates through runtime helpers
refactor: route cli pane placement through runtime adapters
refactor: route cli workspace tab worktree through runtime adapters
refactor: route tui runtime mutations through typed adapters
feat: expose session snapshot through cli
feat: emit layout update events for runtime layout changes
chore: approve contributor ppggff
refactor: route worktree tui actions through runtime wrappers
refactor: route pane layout tui actions through runtime wrappers
fix: allow foreground agent session takeover
refs #943
chore: approve merged contributor DevSrSouza
fix: kitty graphics streams freeze on partial updates and leak host images (#948)
* fix: request a render on kitty graphics writes
pty output containing a kitty graphics sequence only scheduled the
deferred settle render. that render's wake-up notifies the render loop
only when the dirty flag was not already set, so under a continuous
stream of image updates the notify can be dropped and the pane keeps
showing an old frame until something else forces a full render.
request an immediate render like any other output. the dirty flag and
the minimum render interval still coalesce chunked writes, and the
settle render stays as a backstop.
refs #947
* fix: fingerprint kitty images exactly across retransmissions
the image fingerprint hashed only the first, middle, and last 4096
bytes of pixel data. a program that streams updates by retransmitting
one image id keeps the length and dimensions constant, so a frame whose
changed pixels all fall outside those three windows gets the same
fingerprint as the frame before it. the encoder then treats the image
as already uploaded, emits no graphics bytes, and the frame is dropped
as identical to the previous render. the pane stays stuck on the last
uploaded image until a resize resets the graphics surface.
hash the full payload instead. to keep that off the render hot path,
cache the fingerprint per image id and recompute it only when the
image's transmit time changes. libghostty-vt already refreshes the
transmit time on every transmission; vendor patch 0002 exposes it
through a new GHOSTTY_KITTY_IMAGE_DATA_TRANSMIT_TIME_NS accessor. a
static image costs one map lookup per render and a streaming image one
hash per transmitted frame.
refs #947
* fix: delete superseded host kitty images
host image ids derive from image content, so a pane image whose pixels
change maps to a new host id on every u…
- Removed `apply_context_menu_action` and `handle_context_menu_key`, test-only duplicates of menu dispatch that let the stack item ship green while it was dead in the real binary
- Pointed every test that used them at `apply_context_menu_action_via_api` and `handle_context_menu_key_via_api`, the dispatchers production actually runs
- Dropped the close-pane test that duplicated its stronger `api_` twin on the real path
- Moved two menu tests from mouse.rs to modal.rs onto the shared workspace fixture, because their hand-spawned PTY cannot survive the API path's opening `drain_all_internal_events`
- Removed the `Direction` import the mirror was the last user of, and the stray `cfg(test)` attribute it left behind on the `Rect` import
fix: make the pane menu's stack action work, and stop calling it a split
- Added the missing `Stack` arm to `apply_context_menu_action_via_api`, the dispatcher every production menu activation funnels through, so selecting it now creates a pane instead of silently closing the menu
- Covered that path with a test that fails with one pane when the arm is removed, because the pre-existing test asserted against the `cfg(test)` dispatch mirror and stayed green while the real binary was broken
- Renamed the context menu item from `Split stacked` to `Stack`, since a stack is not a split
- Renamed the navigate bar entry to `stack` and the keybind help entry to `stack pane`
- Surfaced the stack action in the navigate bar, which previously offered only the two splits
- Added a TestBackend assertion that the navigate bar renders all three ways to add a pane, each with a bound key
docs: document stacked panes wherever splitting is documented
- Documented the stack layout node (`panes`, `active`) in socket-api so clients can round-trip a stacked tab through layout.export and layout.apply
- Added stacking to the pane concepts, quick-start and keyboard pages in English, Japanese and Simplified Chinese
- Added the `split_stacked` binding to the keyboard and configuration samples in all three locales
- Corrected the `pane split` and `plugin pane open` usage strings to read `right|down|stacked`, which the parsers already accepted
- Taught the embedded agent skill to reach for `--direction stacked` when another split would leave panes unusably small
- Left `pane move --split` as `right|down` because the server rejects moving a pane into a stack
chore: import fork-local justfile recipes
An optional import keeps local recipes in an ignored directory, so the
tracked justfile carries one line instead of a growing fork-only block
and a rebase has one place to conflict.
fix(input): give stack title rows priority over the split resize handle
A stack's first title row sits on the region's top border, which is the
same row a vertical split above it uses as its resize handle. Border
lookup runs before the pane hit test, so clicking the top member of a
stack below a split started a resize instead of focusing it, leaving that
member unreachable by mouse.
feat(ui): offer a stacked split in the pane menu
The pane menu offered split right and split down, so stacking was
reachable only from the keyboard. The placement enum already had the
variant, so this is wiring rather than new capability.
fix(server): keep hidden stack members out of their own title rows
The retained renderer applied every pane's dirty patch at its inner rect.
A collapsed member's inner rect is its one row title row, and collecting
a patch has no size check, so asking for one row handed back the first
row of that hidden terminal to be painted over the member's own name.
Only the span between the corners was overwritten, which is why the frame
survived while the name did not, and only while that agent was producing
output.
A collapsed member also reports its whole screen dirty for as long as it
stays hidden, because nothing else refreshes a hidden pane's render
state, so one stack was enough to drop a whole tab back to full redraws.
Skipping it fixes both, and matches what pane rendering and kitty
graphics already do.
feat(ui): draw stacked pane titles on the frame
Each member of a stack was named twice: once on the box's top border and
again on a title row of its own directly below it. The first member's
title row is now the region's own top border, so a stack costs one row
less than a box plus a row per member, and the name sits where a pane's
name already sits.
A title row is drawn as a ruled frame line opening its own corner rather
than tee-ing into one continuous box, so a stack reads as a deck of cards
rather than as one pane chopped into strips. The region's top border row
is shared with the pane above and is left to the border pass, which has
already drawn its junctions and its colour; only the title text goes
there.
A collapsed member takes a muted version of the accent instead of the
generic border grey, so a stack reads as one group of related panes.
StackSlot carries the region's borders because only the visible member
holds them, and rescanning the pane list for it would be quadratic inside
a render loop.
docs: document stacked panes and the stacked split keybind
Covers prefix+shift+s and the agent panel row change in the sample
config, the keyboard page and the config reference.
feat(ui): name panes after the agent session
A pane's name is now resolved in one place, TerminalState::display_name:
a title the agent pushed, then an explicit rename, then the agent session
name, then the terminal's own title. Pane chrome, stack title rows and
the agent panel all read it, so they cannot drift. Two of them already
had, which is how a renamed session showed on a stack row but not in the
panel.
An agent renaming its own session arrives as a terminal title, so leaving
that out of the chain made a renamed session look unnamed. The agent
session name reaches the panel through the existing pane token, and the
default second row is now agent then pane name.
pi prefixes its title with a lone glyph the same way claude does, so it
joins the set that is stripped before a title is shown. An unnamed pi
session is nothing but that glyph, which now leaves no name and falls
back to the agent label.
feat(input): add a stacked split action
prefix+shift+s puts a new pane in the focused pane's stack, creating one
if the pane is not stacked yet. It sits alongside split_vertical and
split_horizontal as a third way to place a pane, and stays prefix-first
so herdr does not start swallowing keys from shells and editors.
Moving between members needs no new action: collapsed title rows are
ordinary rects stacked vertically, so prefix+j and prefix+k already walk
a stack.
SplitDirection gains a stacked variant, which the cli accepts as
herdr pane split --direction stacked. It has no split axis, so the
conversion to a layout direction is now fallible, and pane move rejects
it before taking the source pane out of its tab rather than after.
feat(ui): render stacked pane title rows
Every member of a stack gets a title row, the visible one included, and
its terminal starts on the row directly below. Without a row of its own
the last collapsed title sat right above the visible terminal and read as
that terminal's label.
The box is drawn once around the whole region and carried by the visible
member, so the existing border joining code handles it like any other
pane. Collapsed rows carry no chrome. Chrome is decided for the region
rather than per member, otherwise the top, middle and bottom of a stack
get different borders and the visible pane's terminal changes height as
focus moves.
Kitty graphics bypass the cell buffer, so a collapsed member is skipped
when collecting placements too; otherwise a hidden pane draws images over
its own title row. A layout with no stacks costs one scan and no
allocation.
feat(layout): add a stacked pane node
Panes in a stack share one region. One shows its terminal and the rest
collapse to a single title row, so a tab with six agents no longer gives
each of them a sixth of the screen.
Unlike zellij, a collapsed pane keeps a full size terminal behind its
title row. Every member is sized to the region the visible member
occupies, so moving through a stack never resizes a pty, never reflows a
running agent, and leaves the bottom buffer that detection reads intact.
The visible member also keeps a floor of content rows, so adding members
drops title rows rather than shrinking every terminal toward nothing.
Stack membership is a session fact, so it is saved with the layout and
reported by the layout API. Restore drops dead members, keeps the visible
one in range, and turns a stack that is down to one pane back into a
plain pane. A stack holds panes rather than subtrees, and applying a
layout restores the member the caller marked visible, so exporting a
layout and applying it back reproduces the same stack.
fix: speed up alternate-screen history reads (#2426)
refs #2387
fix: keep active sidebar rows visible (#2794)
refs #2792
feat(cli): guide agents to Herdr resources
fix(docs): publish channel-aware documentation indexes
fix(docs): apply llms patch during website builds
feat(docs): publish agent-readable documentation
fix: reject prompts to blocked agents (#2790)
* fix: reject prompts to blocked agents
refs #2788
* docs: clarify agent prompt timing
refs #2788
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: detect all claude half-circle spinner frames (#2762)
refs #2760
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: wait for new pane shell readiness (#2774)
* fix: wait for new pane shell readiness
refs #2773
* refactor: share agent startup bounds
refs #2773
* fix: reconcile agent names after startup timeout
refs #2773
* fix: cover agent cleanup scheduling skew
refs #2773
* fix: bound pane shell readiness retries
refs #2773
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: keep tab and sidebar clicks when the terminal reports a stray drag (#2736)
* fix: keep tab and sidebar clicks when the terminal reports a stray drag
This works around a Ghostty bug that causes herdr tabs to be unclickable
in fullscreen mode.
Ghostty on macOS in native fullscreen emits one motion report after a
fresh press in the strip where the menu bar reveals, with the row
shifted to near the bottom of the grid. The cause is upstream: macOS
delivers one mouse event whose y is nearly a window height away from the
real pointer, and Ghostty reports it as it arrives (iTerm2 and
Terminal.app report the same clicks correctly).
Herdr treated the stray report as a real drag and lost the click two
ways: it opened a tab reorder with no drop target, making the release a
no-op, and it handed the release to the pane under the bogus
coordinates.
Now, a press on the tab bar or sidebar owns the gesture until release,
and a tab drag only starts once the pointer is over a real drop target.
refs #796
* fix: scope chrome mouse gestures to their input source
* fix: preserve chrome drag input source
* fix: preserve concurrent chrome presses
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(graphics): support high-dpi direct file frames (#2680)
fix: preserve logical lines in scrollback editor (#2735)
refs #2733
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: add qwen code detection and restore (#2743)
refs #2730
fix(agent): focus Copilot before prompting (#2734)
* fix(agent): focus Copilot before prompting
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(agent): cover stale focus-reporting state
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: strip claude title spinner frames (#2709)
* fix: source title activity glyphs from manifests
refs #2707
* fix: simplify manifest-driven title stripping
refs #2707
* fix: reconcile handoff title policies
refs #2707
* fix: strip claude title spinner frames
refs #2707
* fix: keep claude detection manifest unchanged
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: use the running binary in agent hooks (#2722)
fix: preserve workspace labels for root repositories (#2727)
refs #2594
chore: update contributor list
perf: avoid repeated Git config reads (#2688)
refs #2643
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: synchronously terminate cancelled status commands
fix: detect claude 2.1.228 half-circle busy spinner
fix: disambiguate shifted punctuation keybinds (#2676)
refs #2674
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(render): compact large terminal redraws (#2675)
refs #2670
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): reduce idle agent detection CPU (#2651)
* fix(windows): reduce idle agent detection CPU
refs #2642
* fix(windows): gate agent process discovery
refs #2642
---------
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
fix: make just build cross-platform (#2647)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: derive repo name for embedded bare layouts (#2660)
refs #2657
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: refresh english documentation
fix: wait for agent prompt readiness (#2537)
* fix: wait for agent prompt readiness
refs #2410
* fix: return pane updates after tab bar command
refs #2410
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: keep the outer terminal window title in sync with the session (#2627)
* feat: keep the outer terminal window title in sync with the session
Herdr emulates the terminals in its panes, so an OSC 0/OSC 2 title
written inside a pane stops at Herdr and never reaches the terminal
Herdr itself runs in. That outer title is what window managers read for
title bars, tab bars, and group bars, so it kept showing whatever the
shell or ssh happened to leave behind.
Add `ui.window_title`, rendered from {hostname}, {workspace}, {tab},
{pane}, and {terminal_title}, and push it to the foreground client
whenever it changes. It renders on the server, so {hostname} names the
machine the panes actually run on rather than the machine a thin remote
client runs on, and it is gated on a pending render so an idle loop
never pays for it.
A title is only remembered as delivered once a foreground client takes
it, so the first client to attach is written to rather than skipped.
`client.window_title.set` still wins over the configured title, and
clearing it now hands the title back to `ui.window_title` instead of
only "herdr".
* fix: deliver the outer window title to a newly attached client
ClientConnected assigns the foreground client directly rather than going
through promote_client_to_foreground, so clearing the sent-title cache
there missed the case that matters most: attaching a second terminal to a
running session. The title was usually unchanged, so the sync returned
early and the new terminal kept whatever its shell or ssh had left.
Key the cache on the client that received the title instead of relying on
every foreground assignment to invalidate it.
* perf: keep hidden pane output off the window title path
Output from a hidden or background pane sets needs_render without setting
needs_full_render, and the retained render plan then skips presentation
for it entirely. Syncing the title on needs_render meant every coalesced
hidden-output tick still formatted, sanitized, and allocated a title that
could not have changed, against the hidden-source early exit AGENTS.md
requires.
Every input to the title is app state, which always requests a full
render, so gate on that instead. The one exception is the focused pane's
own terminal title, which arrives through PTY parsing, so ask for a full
render when that changes and the configured title uses it.
* fix: only cache a window title a client writer received
* fix: carry an api set window title across a live handoff
* fix: make outer window title updates event-driven
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
refactor(website): clean up homepage
fix(input): ignore modified j/k/up/down in session navigator (#2377)
The Char('j')/Char('k')/Down/Up match arms in handle_navigator_key
had no modifier guard, unlike every sibling arm in the same match
block, so Ctrl+K, Alt+J, etc. also moved the navigator selection.
refs #1981
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
ci: remove automatic issue gate
fix(windows): strip elevated terminal title decoration (#2632)
fix(server): prioritize shutdown requests (#2624)
refs #2612
test(windows): serialize media player environment access (#2619)
fix: track opencode tui session selection (#2455)
refs #2450
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(ui): anchor the host cursor to modal name inputs (#2569)
* fix(ui): anchor the host cursor to modal name inputs
IMEs draw their composition preview at the host terminal cursor. The rename
and new-worktree dialogs drew a block glyph instead of setting one, so the
frame carried no cursor and the client kept the position the focused pane
last reported. Japanese composition appeared behind the dialog and only
reached the field on Enter.
Set the cursor to the caret column instead, counting wide characters as two
cells.
refs #1755
* fix(ui): keep the clamped caret cell blank
A name that fills the field left the clamped caret sitting on the last
rendered glyph. A terminal inverts the cell under its cursor and an IME
composes there, so the glyph was hidden and composition overlapped it.
Render the text one column short of the field. The field is still cleared
in full, so the clamped caret always lands on a blank cell.
refs #1755
---------
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: center tab labels for symmetric highlight padding (#2570)
* fix: center tab labels for symmetric highlight padding
* docs: note centered tab labels in the changelog
* fix: center tab labels by display width, not char count
feat: add move tab keybind actions (#2561)
* feat: add move tab keybind actions
Add optional keys.move_tab_previous/move_tab_next actions that reorder
the active tab one position, wrapping at either end. Reuses the
existing tab.move runtime path that mouse drag reordering already
drives.
* fix: exit navigate mode on single-tab move attempts
feat: add configurable tab bar status (#2586)
* feat: show a zoom indicator in the desktop tab bar
Reserve the right edge of the tab row for a ZOOM pill while the
focused pane is zoomed, matching the accent style of the mode bars.
The per-tab Z suffix stays; the pill makes the zoomed state visible
at a glance like tmux's status-right flag.
* feat: optionally show the hostname in the desktop tab bar
Add ui.tab_bar_hostname to display the machine's hostname at the right
edge of the tab row, like tmux's #h in status-right. The value resolves
where the server renders, so remote sessions show the remote host. Off
by default.
* fix: strip control characters from the tab bar hostname
* fix: hide the hostname when it would squeeze out the tab strip
* feat: add configurable tab bar status
* fix: harden tab bar status updates
* fix: terminate tab bar status process trees
* fix: disable status commands on unsupported platforms
* fix: skip unchanged status command renders
* fix: keep tab bar status opt-in by default
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
test: guard pane-scaled render performance
refs #2550
feat: add direct pane resize keybindings (#2558)
fix(client): avoid abort on terminal hangup (#2427)
* fix(client): avoid abort on terminal hangup
refs #2424
* test(client): gate PTY integration on unix
refs #2424
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
perf(ui): avoid full pane mode reads for scrollbars (#2554)
fix(input): preserve alt-prefixed control keys (#2543)
refs #2514
fix(website): improve plugins page readability on dark ground
fix(ui): reclaim scrollbar gutter in alternate screen (#2538)
feat(graphics): add direct pane frame streaming (#2523)
* feat(graphics): add direct pane frame streaming
* feat(graphics): expose pane visibility
* test(graphics): preserve legacy terminal image output
* fix(graphics): harden streaming lifecycle
* fix(input): preserve mouse releases outside panes
feat: make outer pane borders configurable (#2535)
fix: make windows installer swaps atomic (#2530)
refs #2356
feat(input): add per-pane right-click routing (#2504)
chore: approve dhh as contributor
fix: forward pane terminal bells (#2498)
refs #2453
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: support all agent integrations on windows (#2496)
fix(windows): share Git Bash agent candidate scans (#2494)
refs #2459
fix(config): report unknown theme names (#2488)
refs #2452
fix: avoid redundant Windows recent-history snapshots (#2474)
refs #962
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve shift in kitty alternate reports (#2479)
refs #2435
fix(remote): restore blocking bridge streams (#2485)
refs #2478
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat(website): rebuild compare page in new design with runtime positioning
fix: verify stable release checksums
fix: publish stable release checksums
chore: update website
feat(marketplace): track star history for trending and new plugin surfaces
fix(theme): refresh host appearance on focus (#2417)
* fix(theme): refresh host appearance on focus
refs #2416
* fix(input): preserve split appearance replies
refs #2416
* fix(input): retain fragmented appearance reports
refs #2416
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(detect): ignore Cursor Run Everything status (#2220)
* fix(detect): ignore Cursor Run Everything status
refs #1763
* fix(detect): constrain Cursor approval controls
refs #1763
* test(detect): remove cursor manifest behavior fixture
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: add positive idle detection for kiro-cli prompt (#2301)
* fix: add positive idle detection for kiro-cli prompt
refs discussion #982
* fix: remove manifest integration tests per reviewer request
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat(copy-mode): add big-word motions (#2270)
Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(terminal): restore keyboard reporting on detach (#2395)
refs #2393
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize versioned Python agent wrappers (#2188)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: document custom agent integrations
fix(cli): accept --flag=value and reordered options in pane read/wait-output (#2183)
* fix(cli): accept --flag=value and reordered options in pane read/wait-output
* test(cli): trim redundant pane parser coverage
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: keep plugin marketplace counts current
fix: render OSC 4 palette overrides instead of forwarding the index (#2162)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: avoid ctrl-tab escape sequences in legacy panes
refs #2296
fix(ci): repair contributor gate handling
chore: update canonical repository references
ci: restore approved contributor gate
fix(sidebar): highlight active agent in collapsed sidebar (#2382)
The collapsed sidebar renders agent rows with an unconditional
Style::default().fg(p.overlay0), so the active agent is
indistinguishable from the others. The workspace list directly above
it, and render_agent_detail in the expanded sidebar, both mark the
active entry.
Reuse the existing active treatment: resolve the active entry with the
same is_active_pane call the expanded agent panel uses, then paint the
row background with surface_dim and the position number with text, the
same tokens the collapsed workspace rows already use.
Assisted-By: devx/717e5259-915f-4a7b-af07-6abe46da5b90
feat(windows): support remote attach to unix hosts (#2329)
* feat(windows): support remote attach to unix hosts
* fix(remote): preserve unix bridge behavior
fix(website): update author X profile
chore: remove project-local worktree extension
refs #2325
docs: refresh readme and sponsors
feat(theme): add optional sidebar background
fix(config): accept retired agent panel scope (#2295)
refs #2292
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve modifyOtherKeys key releases (#2303)
refs #2302
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): make issue gate structural
fix(terminal): render halfwidth katakana voiced marks (#2257)
Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(layout): return focus to the pane a split was opened from (#2266)
Closing a focused pane handed focus to the next pane in tree order.
For a pane opened beside another one -- a plugin split, a file viewer,
any transient tool pane -- that is rarely where the user was: it lands
on some unrelated neighbour rather than the pane that opened it.
Track the pane focus came from in TileLayout and prefer it when the
focused pane closes, falling back to tree order when there is no
history, when it points at the pane being closed, or when it points at
a pane that has since gone away. The history lives in the layout, so it
can only ever name a pane in the same tab.
A one-slot history is only sound if internal focus excursions never
write it, so the tree edits that used to bounce focus around now go
through target-taking primitives instead. close_pane removes a
background pane directly, so detach_pane and take_pane_for_move stop
focus-close-refocusing. split_pane splits a target without moving
focus: the runtime split path only focuses the new pane once the spawn
succeeds, which makes a failed split a pure rollback, and the targeted
and unfocused workspace split paths stop fabricating history.
insert_pane_near now takes the focus intent, so an unfocused pane move
leaves the target tab's history alone. The layout-level focused-split
helpers become test-only; production splits all flow through the
target-taking path.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ui): search single-tab names in navigator (#2320)
fix(input): parse default mouse reports (#2312)
* fix(input): parse default mouse reports
refs #2309
* fix(input): preserve split default mouse reports
refs #2309
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(cli): resolve pane query --current from caller (#2298)
refs #2297
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): keep pending url clicks across host focus loss (#2291)
Opening a URL raises the browser, which takes focus away from the host
terminal before the mouse release arrives. release_input_source(_headless)
cleared pending_url_click_sources on that focus loss, so the release was
forwarded to the pane and the agent opened the same URL again.
Clear the set in clear_input_source instead, whose only production caller
is remove_client.
refs #2290
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
feat(ui): add distinct status indicators (#2282)
refs #2260
fix: detect claude confirmation prompts
refs #2268
fix(website): copy heading links to clipboard
fix(ui): preserve sidebar scroll across clients (#2280)
refs #2255
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): preserve shift-tab in pane automation (#2259)
refs #1561
fix(docs): allow corrections to published versions
refs #916
feat(plugins): index marketplace manifests
docs: publish preview documentation
fix(ui): keep collapsed workspace status visible (#2239)
refs #2216
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: refine cpu optimization blog post
docs: update website manifest for v0.8.0
release: v0.8.0
docs: finalize 0.8.0 release documentation
feat(website): rebuild marketing pages on new brand chassis
fix: page keys scroll pane scrollback at zsh and REPL prompts (#2191)
* fix: page keys scroll pane scrollback at zsh and REPL prompts
PageUp/PageDown were forwarded to the pane whenever DECCKM (application
cursor) was on, assuming only primary-screen pagers enable it, but zsh's
line editor also enables DECCKM, as do REPLs such as python3. The result
was PageUp scrolling shell history instead of Herdr scrollback.
Bracketed paste discriminates the two: it means the app accepts typed or
pasted text at a prompt, so line editors enable it and pagers do not.
* test: update page key state fixture
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(pi): restrict state reporting to tui sessions (#2159)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: propagate host color scheme to pane apps (#2214)
refs #714
fix(input): preserve hover during extended-button drags
fix(docs): support older git in snapshot checks
fix(docs): publish only released documentation
fix: avoid blocking on foreground cwd checks (#2213)
refs #2206
fix(cli): report non-UTF-8 arguments instead of panicking (#2207)
* fix(cli): report non-UTF-8 arguments instead of panicking
* fix(cli): avoid echoing malformed arguments
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(client): query host cell size when the ioctl reports no pixels (#2160)
fix: preserve claude settings formatting (#2089)
refs #2066
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: stop advertising worktree json flag (#2174)
refs #2171
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize opencode2 as opencode
refs #2169
fix: route vscode remote copies through osc52 (#2173)
refs #2015
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): detect agents across git bash exec boundaries (#2170)
refs #2107
fix(socket_paths): remove dead if-branch in derive_client_socket_from_api_socket (#2157)
fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard (#2165)
* fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard
refs #2164
* fix(input): update control-byte matrix test for 0x1f -> Ctrl+_
feat: add antigravity-cli integration (#2087)
* feat: add antigravity_cli integration harness
Register the `antigravity_cli` target, resolve its configuration
directory to `~/.gemini/antigravity-cli/`, wire target actions,
and add lifecycle hook scripts for Unix and Windows.
* feat: support session resume for antigravity-cli
* fix: correct antigravity-cli hook config path, shape, and agent label
Antigravity CLI reads global customizations from ~/.gemini/config, keys
hooks.json by hook name, and only accepts the matcher/hooks wrapper for
the tool events. The previous install wrote event arrays at the top level
of ~/.gemini/antigravity-cli/hooks.json, which agy never reads and would
reject anyway, so no Herdr hook ever ran.
Session reports were dropped for a third reason: the hooks reported the
agent as antigravity-cli, but the server normalizes that to the canonical
label agy before matching, so is_official_agent_source never matched and
agy --conversation resume was unreachable.
- Resolve the config dir to ~/.gemini/config
- Nest Herdr entries under a Herdr-owned "herdr" block that install
rewrites and uninstall removes, leaving other named hooks untouched
- Emit grouped entries for PreToolUse/PostToolUse and flat handler lists
for PreInvocation/PostInvocation/Stop
- Report the canonical agy label from both hook assets and match it in
agent_resume
- Compile-gate the hook asset constants and stop shadowing $args in the
PowerShell hook
- Document the real directory, that it must already exist, and the
named-block behavior
refs #1011
refs #1571
* fix: make antigravity-cli integration session-only
antigravity cli cannot express lifecycle safely: there is no blocked
event, postinvocation is skipped on interruption, and stop fires at the
end of a turn rather than on process exit, which left stale state and
released authority at the wrong time.
report only the conversation on preinvocation and let screen detection
own agent state. resume via `agy --conversation <id>` is unchanged.
* fix: update antigravity session after conversation switch
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): skip pr gate in forks
feat(ui): make pane scrollbars optional (#2166)
refs #2167
fix: expand copy-mode word-end window past a final wide glyph (#2145)
point_is_final_atom compared an atom's terminating column against a
word-motion target's starting column. The two are equal for narrow
cells but never for wide ones, so the read window stopped expanding
and copy-mode `e` halted at the soft-wrap boundary on CJK text.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: report a clear cli error when no herdr server is running (#1963)
* fix: report a clear cli error when no herdr server is running
socket cli commands surfaced a raw io::Error debug string
(`Error: Os { code: 2, ... }`) when nothing was listening on the
api socket, which read like a bad --cwd path. map dead-socket
connect failures to a `server_not_running` json error carrying the
resolved socket path, printed once at the edge that surfaces the
error; recovering callers (plugin offline registry fallback, agent
start polling) recognize the marker and keep their existing
behavior.
refs #1941
* fix: map dead-socket errors on the unchecked cli request path
refs #1941
* fix: make server-not-running guidance session-aware
refs #1941
fix(windows): preserve semantic escape key taps
fix(input): preserve native key lifecycle across routing (#2142)
refs #2077
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
chore: remove experiments from settings tui
feat: support bottom tab bar placement (#2118)
* feat: support bottom tab bar placement
* fix: preserve mouse cleanup under bottom mode bar
refs #2117
chore: update agentmd for protocol changes
fix: read alternate-screen agent history
fix(sidebar): keep worktree groups packed
fix(client): restore terminal on sighup and sigterm
Enable termination-signal handling so SIGHUP and SIGTERM follow the graceful
quit path and restore terminal state. Log handler registration failures and
add PTY coverage for direct SIGHUP and server EOF restoration
Co-authored-by: Matt Coles <macols@amazon.com>
fix: preserve windows sessions after ssh logout (#2098)
* fix: preserve windows sessions after ssh logout
refs #2008
* chore: document windows wmi safety
refs #2008
fix(omp): support Windows session paths (#2092)
fix: resume agents after headless restore (#2088)
refs #2064
ci: consolidate ai review trigger label
fix: launch argument-free agents on windows (#2075)
refs #2072
fix: add opt-in child-group process detection (#2052)
* fix: add opt-in child-group process detection
refs #1982
* fix: preserve lifecycle probes without foreground groups
refs #1982
fix: preserve kitty associated text (#2051)
refs #2020
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: finish repository organization migration
Update rose pine surface_dim colour to "Overlay" (#2002)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: update repository links after organization transfer
ci: allow repository organization migration
fix: scope agent skill installation
refs #2022
docs: update preview manifest
fix(windows): preserve parent agent ownership
refs #1514
fix: preserve windows path variables during install
refs #1947
test(windows): remove flaky sound timing assertion
refs #1330
fix(windows): restore system notifications and sound playback (#2019)
ci: remove approved contributor bypass
chore: approve merged contributor we11adam
fix: preserve navigate mode after pane focus (#1993)
refs #1850
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: approve merged contributor patrick-xin
docs: add simplified chinese readme (#1990)
* docs: add simplified chinese readme
* fix: publish simplified chinese readme
* fix: require localized readme for releases
* docs: publish simplified chinese readme
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: restore python3 commit hook
fix: select windows python command in commit hook (#1994)
chore: approve merged contributor bioform
fix: count ptmx master fds under devpts layouts (#1984)
live_server_holds_one_pty_master_fd_per_pane counted only /proc/<pid>/fd links
resolving to exactly /dev/ptmx. On devpts setups such as WSL2 and many
containers, a PTY master fd resolves to /dev/pts/ptmx instead, so the test found
zero masters and failed with "had 0 ptmx master fds; expected 1" even though the
server held the pane's master fd. Match both ptmx node paths; pty slaves still
resolve to /dev/pts/<N> and stay uncounted, so the one-master-per-pane invariant
is unchanged.
perf: skip rendering hidden pty updates
fix: preserve linked worktree workspace labels
perf: replace agent spinners with static status marks
fix: ignore nested codex session reports (#1927)
* fix: ignore nested codex session reports
refs #1789
* test: cover matching codex thread id
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: resolve relative plugin commands from plugin root
refs #1949
docs: update sponsor acknowledgements
fix: keep focus on the current workspace when another self-closes (#1912)
handle_pane_died only clamped the stale active/selected indices after
removing a workspace that closed itself, so it never shifted them down
when the removed workspace sat before the focused one. With workspaces
[x, y, z] and focus on y, removing x left active pointing at z, silently
moving the user into a workspace they did not select.
Resolve both indices by workspace id across the removal, as
close_selected_workspace already does, keeping the clamp as the fallback
for when the removed workspace was the focused one. Also scroll the
focused workspace back into view, which the explicit-close path already
did and this one did not.
refs #1621
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: make native windows checks reliable (#1925)
chore: approve merged contributor season179
fix: close workspace when api closes its last tab (#1899)
herdr tab close on a workspace's only tab returned tab_close_failed,
while the TUI close-tab action on the same tab closes the tab and
cascades to closing the workspace. Cascade in the API too, emitting
tab.closed then workspace.closed. When the cascade would close a whole
worktree group, return confirmation_required instead, matching
pane.close and the TUI prompt.
refs #1760
chore: approve merged contributor Pimpmuckl
fix: preserve shift-enter in windows panes (#1909)
refs #1743
fix: delay agent prompt submission
refs #1878
fix: ignore empty clipboard writes
refs #1893
fix: restrict unapproved pull requests to bug fixes
ci: harden pull request workflow execution
chore: approve merged contributor olafkfreund
fix(nix): include SKILL.md in the package fileset (#1890)
refs #1889
fix: repaint after transient terminal resizes
fix: preserve prefix mode for modifier events
refs #1870
feat: print bundled agent skill and hint next cli steps
chore: approve merged contributor yianL
fix: preserve focus when closing a non-focused workspace (#1877)
refs #1328
fix: support non-us shifted keybindings (#1876)
* fix: support non-us shifted keybindings
refs #1870
* docs: require current pull request base
fix: improve sidebar worktree hierarchy and reordering (#1873)
* fix: clarify sidebar worktree hierarchy
refs #1694
* feat: reorder worktree groups as a unit
refs #1694
fix: avoid renders for passive mouse motion (#1872)
refs #1865
perf: avoid full pane renders for spinner animation (#1868)
ci: gate pull request review by scope
fix(nix): add rust-analyzer to development shell
chore: consolidate project skills
docs: define maintainer and agent contribution workflows
feat: switch IME to ASCII in prefix mode on Windows (Korean IME) (#1823)
* feat: switch IME to ASCII in prefix mode on Windows
Extend switch_ascii_input_source_in_prefix to Windows: detect IME state
via WM_IME_CONTROL and toggle to ASCII with SendInput for the Korean IME.
Other IME languages are detected and left unchanged.
refs #1802
* docs: clarify Windows (Korean IME) support for prefix ASCII switching
Follow-up to the Windows prefix ASCII switch, which extended
switch_ascii_input_source_in_prefix to Windows but left the surrounding
text describing macOS only.
- Settings row label: "(macOS)" -> "(macOS/Windows)", plus its test.
- Generalize the Windows behavior wording to "switches the IME to
English (ASCII) input" in the config-reference.json entry and the
model.rs doc comment, and state that Windows support is currently
limited to the Korean IME.
- Add a :::caution aside noting the Korean-IME-only limitation to the
en/ja/zh preview docs, keeping the three translations in sync.
refs #1802
* fix: warn when prefix IME toggle injection is incomplete
SendInput can queue fewer events than requested (for example when blocked
by UIPI), which would otherwise leave the IME silently stuck in ASCII or
native mode. Log a warning with the sent and expected counts so the failure
is diagnosable.
refs #1802
* fix: guard prefix IME restore and correct open-status naming
Address maintainer review on the Windows prefix ASCII switch:
- Restore only when safe: store the foreground window at switch time and,
before toggling back, require that the same window is still focused and
the IME is still in English. This stops restore from toggling another
application or overriding a manual return to Hangul during prefix mode.
- Report injection success from send_vk_tap and only arm restoration when
the initial toggle landed; on a partial injection retry the dropped
key-up so a key is not left logically held down. The injection policy is
split into send_vk_tap_with(inject) so the success, partial, and failure
branches are unit-tested without the real SendInput.
- Correct the WM_IME_CONTROL sub-command naming: 0x0005 is IMC_GETOPENSTATUS
(IME open state), not IMC_GETCONVERSIONMODE. Behavior is unchanged; the
constant, comments, and tests now describe the open-status read.
refs #1802
* fix: bound IME open-status read with a timeout
The prefix IME switch reads IMC_GETOPENSTATUS via WM_IME_CONTROL, which
crosses into the terminal-emulator process. A plain SendMessageW would block
herdr's client thread until that process responds, indefinitely if it hangs.
Read through SendMessageTimeoutW with SMTO_ABORTIFHUNG and a short timeout
instead; on timeout the switch is skipped and restore does nothing, so a hung
host process can no longer freeze prefix-mode entry or exit.
refs #1802
* fix: preserve windows ime restoration after partial injection
refs #1802
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
perf: eliminate repeated workspace git discovery (#1842)
* perf: eliminate repeated workspace git discovery
refs #1838
* fix: keep workspace labels current without extra redraws
refs #1838
* fix: retain discovered workspace git metadata
refs #1838
fix: copy retained mouse selections with keyboard shortcuts
refs #1782
fix: run pi worktree ext on background
chore: approve merged contributor ogulcancelik
fix: bundle modern ConPTY on Windows (#1828)
refs #1533
refs #1644
fix: harden hermes lifecycle detection
feat: filter keybind help (#1832)
* feat: filter keybind help
refs #1825
* fix: recognize shifted slash in keybind help
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add grok cli integration for native session restore (#1807)
* feat: add grok cli integration for native session restore
tl;dr: adds `herdr integration install grok` (session-identity tier: a
SessionStart hook reports the grok session id for native restore; state
stays screen-detected via the bundled manifest).
Grok merges every ~/.grok/hooks/*.json, so install writes a
self-contained hooks/herdr.json registering a SessionStart hook next to
hooks/herdr-agent-state.sh, and never touches other hook files. The hook
prefers $GROK_SESSION_ID (injected into every grok hook process) and
reports through the socket API; herdr:grok is a reserved-native-state
source so screen detection stays authoritative. Restore uses
`grok --resume <id>`. Additive JSON API change; no protocol bump; the
schema artifact is regenerated.
refs #1800
* fix: honor GROK_HOME and validate grok hook config in status
Review follow-ups: grok_dir now resolves GROK_CONFIG_DIR (herdr test
seam) before GROK_HOME (the grok CLI's own config-home override) before
~/.grok, so hook installs land where grok actually looks. Integration
status now also validates the herdr-owned hooks/herdr.json next to the
hook script — missing, corrupt, or no-longer-referencing configs report
the install as outdated instead of masking a hook grok never invokes.
refs #1800
* fix: validate the exact grok session hook command in status
The config validator matched on a filename substring, so a SessionStart
command like `echo herdr-agent-state.sh`, or one invoking the script
without the `session` action, still reported the integration as current
while grok never delivered a session id. Status now compares against the
exact command the installer writes, via a shared builder, and the
degradation tests cover both nonfunctional shapes.
refs #1800
* fix: require a command-type grok session hook in status validation
A config entry carrying the exact generated command under a non-command
hook type (e.g. "http") is never executed by grok, so it must not report
the integration as current. The validator now also requires
type = "command", with a degradation test for the mismatched-type shape.
refs #1800
* fix: validate the complete grok hook config
refs #1800
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor corrius
chore: approve contributor adamkrellenstein
fix: report truncated pane reads
refs #1717
fix: make known-agent exit process-owned
refs #1792
refs #1648
fix: answer XTWINOPS size queries in panes
refs #835
chore: approve contributor joonhwan
fix: prefer branded homepage search image
fix: consume handled url click gestures
refs #1761
fix: preserve kitty graphics during host repaints
refs #1628
fix: inherit host palette in pane queries (#1759)
refs #1752
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor carlesso
chore: approve contributor badlogic
fix: preserve kitty printable key releases
refs #1746
fix: preserve physical escape on windows
refs #1736
fix: respect OMP config directory override
refs #1696
chore: relicense herdr under apache-2.0
refactor: centralize new terminal cwd selection
replaces contributions from Pitchfork-and-Torch
refactor: name darwin nix toolchain inputs
replaces contributions from DeevsDeevs
refactor: simplify macos input source ownership
replaces contributions from sf-jin-ku
refactor: clarify opencode event state mapping
replaces contributions from soar
refactor: simplify cursor session reporting
replaces contributions from udirom
refactor: simplify kimi lifecycle reporting
replaces contributions from wbxl2000
refactor: simplify qoder session reporting
replaces contributions from wayneleelwc
refactor: replace pane mouse and clipboard internals
replaces contributions from othavi0
feat(docs): publish versioned release documentation
fix: keep reading while pty input is blocked
refs #1295
fix: fall back to sh for remote path discovery
refs #1201
docs: add alternate-screen output fallback
docs: update preview manifest
fix(website): add agent automation to docs sidebar
docs: update website manifest for v0.7.5
release: v0.7.5
docs: finalize release docs and refresh agent skill
docs: document alternate-screen automation limits
fix: link plugins without a running server
refs #1670
fix: reject oversized text pastes safely (#1676)
refs #1665
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: bound linux sound player lifetime (#1677)
refs #1622
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: discover canonical mise remote installs
refs #1201
fix: use pi settled lifecycle event
docs: explain Windows cursor and IME trade-off
refs #1637
fix: make plugin state global across sessions
refs #1174
fix: show agent targets before options in help
fix: bound stalled agent prompt waits
fix: report kimi questions as blocked
fix: avoid rechecking cached pane cwd (#1616)
refs #1603
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: add plugin-driven agent views and startup hooks
feat: make agent automation a first-class cli primitive
fix: preserve plugin command arguments (#1613)
fix: show current workspace name in close confirmation
refs #1364
feat: connected tree glyphs, workspace grouping, and search auto-select in navigator
refs #1611
perf: cache windows foreground process snapshots
refs #1158
fix: preserve terminal live follow through resize
fix: support javascript integrations on windows
refs #1531
fix: serialize opencode lifecycle reports
refs #1519
fix: detect codex working with static titles (#1574)
* fix: detect codex working with static titles
refs #1563
* fix: ignore interrupted codex footer
refs #1563
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: report unknown config keys (#1575)
* fix: report unknown config keys
refs #1573
* fix: preserve mixed config warning context
refs #1573
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: batch contiguous terminal diff writes
refs #283
fix: preserve lone escape input boundaries
refs #541
feat: add optional workspace name prompt
fix: update windows conpty smoke for pane-first agents
feat: harden named agent cli workflows
refs #1525
docs: update preview manifest
test(windows): support headless console runners
fix(windows): prevent remaining subprocess console flashes
refs #1468
perf: adopt libghostty integration improvements
refs #276
ci: gate Greptile reviews by contributor approval
fix: detect grok background work from pinned status
fix: detect grok state from terminal signals
chore: update vendored libghostty-vt
refs #276
fix: follow foreground process group leader cwd
refs #1472
refactor: extract active tab surface rendering
fix: preserve selection when auto-copy is disabled (#1496)
refs #1471
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): suppress noninteractive process windows
refs #1468
docs: update preview manifest
fix(windows): hide agent manifest curl windows
refs #1468
fix: stop agent wait when pane closes (#1488)
chore: enable zed lsp
feat: configure collapsed sidebar startup state
refs #1463
feat: add configurable sidebar token styles
feat(macos): support agent environment hints
refs https://github.com/ogulcancelik/herdr/discussions/679
fix: preserve plugins during live handoff
refs #893
fix: handle pane graphics stream disconnect race
fix: guard cli requests against protocol mismatches (#1453)
refs #1435
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
test: wait for multi-client resize propagation
docs: update preview manifest
docs: update website manifest for v0.7.4
release: v0.7.4
docs: finalize next release documentation
docs: add popup pane usage examples
refs #1125
test: shorten pane graphics socket fixture paths
feat: add floating popup panes
refs #1125
feat: add isolated pane graphics streaming
fix: preserve escape before sgr mouse reports
refs #1334
feat(website): homepage plugin showcase, live star count, faithful claude code mock
fix(linux): scope foreground process discovery to panes
refs #1399
fix: reassemble split sgr mouse input
refs #1382
fix: preserve associated emoji input (#1410)
refs #1404
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
test: shorten macos api socket fixture path
ci: restore fast reliable checks
fix: flush live handoff responses before exit
feat: configure sidebar entry gaps
fix: stop copy mode line-end at text (#1411)
fix: forward horizontal wheel events to panes (#1402)
refs #1349
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: retry dropped omp lifecycle reports
refs #1310
fix(website): scope docs search by locale and channel
fix: forward outer focus events to panes (#1388)
* fix: forward outer focus events to panes
refs #1337
* fix: preserve ordered focus forwarding
refs #1337
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: show renamed single tabs in agents sidebar
refs #1369
fix: reap detached custom command children (#1384)
* fix: reap detached custom command children
refs #1360
* test: harden child cleanup and sidebar metrics
refs #1360
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: explain modified-arrow shell bindings
refs #1370
fix: keep Claude working during /btw
refs #1366
docs: streamline configuration guide
fix: allow slow server shutdowns
fix: detect reordered codex title spinners
refs #1281
feat: add configurable sidebar metadata tokens
docs: add versioned config reference
refactor: centralize agent identity lookup
docs: add troubleshooting guide
refs #1116
fix: number collapsed agent rows by list position
refs #1344
fix: keep windows api connections open
refs #1279
fix: match homepage mock pane chrome and sidebar to tui rendering
fix: clarify config fallback diagnostics
fix: detach windows server from host terminal
refs #1329
chore: remove unmerged approved contributors
feat: add copy-on-select setting
feat: add maki agent support (#1302)
* feat: add maki detection support
Maki always draws a one-line status bar at the bottom of the screen, so the manifest reads just that row: a braille spinner before the `[BUILD]`/`[PLAN]`/`[BASH]` mode label means working, the bare label means idle.
Blocked states come from the panels that replace the input box, the `Permission Required` dialog with its `y Allow`/`n Deny` hint rows and the `Plan complete` form. Maki emits no OSC title or progress, so these screen rules are the only evidence.
Also wires `maki` through process-name identification, per-agent sound overrides, and the website manifest catalog.
* docs: stage maki detection docs
chore: approve contributor tontinton
docs: refresh herdr agent skill
refs #1297
fix: improve config diagnostic delivery
fix: stop windows installer from rewriting config
refs #1162
fix: follow foreground cwd for new terminals
refs #1245
feat: add copy mode search and tmux word motions
refs #1230
docs: document windows config path
ci: pin rust toolchain to 1.96.1
fix: preserve explicit session sockets during live handoff
refs #1180
reported-by: dvic
based-on: https://github.com/dvic/herdr/pull/3
fix: use drawn cursor by default in wsl
refs #930
fix: reanchor pi status after session replacement (#1189)
* fix: reanchor pi status after session replacement
refs #943
* fix: guard active pi sessions from nested startup
refs #943
* fix: serialize pi session replacement reports
refs #943
fix: detect active amp turns
refs #1208
chore: approve merged contributor kovalov
fix: refresh tab bar after plugin-driven tab rename (#1179)
refs #1111
Co-authored-by: Vlad Kovalov <kovalov@users.noreply.github.com>
fix: make remote helper installs shell-portable
refs #1203
fix: match shifted indexed number keybinds
refs #1184
fix: align collapsed sidebar agent rows (#1182)
refs #1168
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: link plugin marketplace from readme
docs: lean readme, add terminal trove gold sponsor
docs: enforce localized release doc parity
refs #1151
docs: update website manifest for v0.7.3
release: v0.7.3
docs: stage 0.7.3 release notes
fix: restore workspace picker keyboard navigation
refs #1149
fix: avoid render-time plain url scans
docs: change sponsorships tiers and add lead sponsor
docs: update preview manifest
ci: ignore microsoft apt repos in artifact builds
ci: clear zig cache before windows checks
fix: keep cursor hide inside sync output
refs #967
fix: guard windows process tree cycles
refs #1083
fix: clear done status on repeated pane focus
fix: preserve navigator search commands (#1140)
Navigator search treated Escape as either modal close or query reset,
which left no way to return to command mode while keeping the filtered
row set. `/` also rebuilt search mode by clearing the query, so a user
could not resume editing the same filter after backing out.
Make Escape leave search focus only, reserve command-mode Escape for
closing the picker, and let `/` refocus the existing query. The footer
now lists the shortcuts for the active mode so command keys are not
advertised while text input owns them.
refs #1115
docs: update website manifest for v0.7.2
release: v0.7.2
docs: finalize release docs
fix: send shifted punctuation as text in kitty mode
refs #1105
fix: preserve alt-shift letters (#1102)
refs #1088
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: move session autosaves off main loop
fix: stop windows server over named pipes
refs #1113
fix: support esc
interrupt for github copilot (#1120)
* fix: support esc interrupt for github copilot
Github Copilot CLI version v1.0.69-2 introduces the "esc interrupt" prompt.
Update the Github Copilot agent detection manifest to match this prompt and correctly report the agent as working.
Add test cases in tests.rs to verify state detection.
Synchronize the website's copy of the manifest.
refs #1119
* test: clean up github copilot detection rules and tests
Clean up formatting and comments for the github copilot detection rule and tests.
refs #1119
* test: remove copilot manifest literal test
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor liby
docs: remove star history embed
fix: honor prefix in copy mode
refs #681
Based on PR #1092 by @reobin.
Co-authored-by: Robin Gagnon <me@reobin.dev>
fix: preserve wrapped pane links (#1099)
refs #1098
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: expose pane scroll state
docs: update sponsors
fix: bridge remote image file drops (#1085)
refs #828
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: add community video section
test: synchronize multi-client resize assertion
fix: clarify remote ssh auth failures (#1084)
refs #1034
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: preserve shifted punctuation for alt legacy input (#1076)
refs #1066
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: expose stats page in website nav
fix: write pane copies to native windows clipboard (#1082)
refs #1067
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: approve merged contributor akbash-bot
fix: focus parent after worktree removal (#1075)
refs #1004
Co-authored-by: akbash-bot <akbash-bot@users.noreply.github.com>
docs: update preview manifest
ci: use homebrew zig for preview macos builds
feat(website): add japanese and simplified chinese docs with i18n, translation issue flow
fix: detect grok build working and blocked states from current ui chrome (#1055)
* fix: detect grok build working and blocked states from current ui chrome
refs #1017
* fix: sync grok detection website manifest
refs #1017
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add public stats page at herdr.dev/stats
ci: accept common environment aliases in issue gate
refactor(nix): replace apple-sdk wrappers with xcbuild (#995)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: retry pi state socket reports
refs #1049
fix: support custom command keybindings on windows
refs #1041
fix: switch prefix ASCII input source on the foreground client (#1016)
* fix: switch prefix ASCII input source on the foreground client
The macOS prefix ASCII-switch ran in the headless server, whose
TISCopyCurrentKeyboardInputSource read is a stale per-process cache
(refreshed only via a main-run-loop notification the server never pumps),
so prefix could leave the terminal on the wrong input source.
Forward it to the foreground client, like clipboard: sync_prefix_input_source
emits AppEvent::PrefixInputSource as an intent; the server forwards it to the
foreground client and the monolithic app applies it in-process via
RealPrefixInputSource, which pumps its main run loop before the stale TIS read.
Key it on Mode::wants_ascii_input so multi-level prefix commands keep ASCII
until returning to the terminal, and restore the IME for rename text entry.
Adds ServerMessage::PrefixInputSource to the already-unreleased protocol 15.
refs #774
* fix: keep prefix input-source switch out of the headless server process
An App-internal drain (the exhaustive drain at the top of
handle_api_request, reachable from prefix-key runtime mutations) can
consume a queued PrefixInputSource intent before the server's
forwarding drain sees it, applying the TIS switch in the headless
server process and stranding the restore state. Gate the in-process
switch on App.local_input_source_switch, disabled by the headless
server alongside the other local side effects, so a swallowed intent
degrades to a skipped switch. Widen the forwarding-bypass maintenance
test to the handle_internal_event_with_prefix_sync wrapper.
refs #774
* docs: clarify prefix input-source comments and flag docs
refs #774
* fix: bump protocol for prefix input source
refs #774
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
test: wait for client frame before crash assertion
test: keep windows smoke cleanup non-fatal
test: wait for windows smoke pane output
fix: wait for server stop socket cleanup
chore: approve contributor TonyxSun
refactor: route headless deferred creates through runtime helpers
refactor: route cli pane placement through runtime adapters
refactor: route cli workspace tab worktree through runtime adapters
refactor: route tui runtime mutations through typed adapters
feat: expose session snapshot through cli
feat: emit layout update events for runtime layout changes
chore: approve contributor ppggff
refactor: route worktree tui actions through runtime wrappers
refactor: route pane layout tui actions through runtime wrappers
fix: allow foreground agent session takeover
refs #943
chore: approve merged contributor DevSrSouza
fix: kitty graphics streams freeze on partial updates and leak host images (#948)
* fix: request a render on kitty graphics writes
pty output containing a kitty graphics sequence only scheduled the
deferred settle render. that render's wake-up notifies the render loop
only when the dirty flag was not already set, so under a continuous
stream of image updates the notify can be dropped and the pane keeps
showing an old frame until something else forces a full render.
request an immediate render like any other output. the dirty flag and
the minimum render interval still coalesce chunked writes, and the
settle render stays as a backstop.
refs #947
* fix: fingerprint kitty images exactly across retransmissions
the image fingerprint hashed only the first, middle, and last 4096
bytes of pixel data. a program that streams updates by retransmitting
one image id keeps the length and dimensions constant, so a frame whose
changed pixels all fall outside those three windows gets the same
fingerprint as the frame before it. the encoder then treats the image…
- Renamed the binding to `keys.stack_pane`, since stacking a pane is not a kind of split and the old name said it was
- Kept `split_stacked` as a serde alias so existing configs keep their binding instead of silently losing it
- Covered the alias with a test that fails when the alias is dropped from the overlay struct, which is the one config parsing actually goes through
- Renamed `NavigateAction::SplitStacked` to `StackPane` to match
- Updated the default config comment, the keyboard and configuration samples in all three locales, and the generated config reference
refactor: delete the cfg(test) context menu dispatch mirror
- Removed `apply_context_menu_action` and `handle_context_menu_key`, test-only duplicates of menu dispatch that let the stack item ship green while it was dead in the real binary
- Pointed every test that used them at `apply_context_menu_action_via_api` and `handle_context_menu_key_via_api`, the dispatchers production actually runs
- Dropped the close-pane test that duplicated its stronger `api_` twin on the real path
- Moved two menu tests from mouse.rs to modal.rs onto the shared workspace fixture, because their hand-spawned PTY cannot survive the API path's opening `drain_all_internal_events`
- Removed the `Direction` import the mirror was the last user of, and the stray `cfg(test)` attribute it left behind on the `Rect` import
fix: make the pane menu's stack action work, and stop calling it a split
- Added the missing `Stack` arm to `apply_context_menu_action_via_api`, the dispatcher every production menu activation funnels through, so selecting it now creates a pane instead of silently closing the menu
- Covered that path with a test that fails with one pane when the arm is removed, because the pre-existing test asserted against the `cfg(test)` dispatch mirror and stayed green while the real binary was broken
- Renamed the context menu item from `Split stacked` to `Stack`, since a stack is not a split
- Renamed the navigate bar entry to `stack` and the keybind help entry to `stack pane`
- Surfaced the stack action in the navigate bar, which previously offered only the two splits
- Added a TestBackend assertion that the navigate bar renders all three ways to add a pane, each with a bound key
docs: document stacked panes wherever splitting is documented
- Documented the stack layout node (`panes`, `active`) in socket-api so clients can round-trip a stacked tab through layout.export and layout.apply
- Added stacking to the pane concepts, quick-start and keyboard pages in English, Japanese and Simplified Chinese
- Added the `split_stacked` binding to the keyboard and configuration samples in all three locales
- Corrected the `pane split` and `plugin pane open` usage strings to read `right|down|stacked`, which the parsers already accepted
- Taught the embedded agent skill to reach for `--direction stacked` when another split would leave panes unusably small
- Left `pane move --split` as `right|down` because the server rejects moving a pane into a stack
chore: import fork-local justfile recipes
An optional import keeps local recipes in an ignored directory, so the
tracked justfile carries one line instead of a growing fork-only block
and a rebase has one place to conflict.
fix(input): give stack title rows priority over the split resize handle
A stack's first title row sits on the region's top border, which is the
same row a vertical split above it uses as its resize handle. Border
lookup runs before the pane hit test, so clicking the top member of a
stack below a split started a resize instead of focusing it, leaving that
member unreachable by mouse.
feat(ui): offer a stacked split in the pane menu
The pane menu offered split right and split down, so stacking was
reachable only from the keyboard. The placement enum already had the
variant, so this is wiring rather than new capability.
fix(server): keep hidden stack members out of their own title rows
The retained renderer applied every pane's dirty patch at its inner rect.
A collapsed member's inner rect is its one row title row, and collecting
a patch has no size check, so asking for one row handed back the first
row of that hidden terminal to be painted over the member's own name.
Only the span between the corners was overwritten, which is why the frame
survived while the name did not, and only while that agent was producing
output.
A collapsed member also reports its whole screen dirty for as long as it
stays hidden, because nothing else refreshes a hidden pane's render
state, so one stack was enough to drop a whole tab back to full redraws.
Skipping it fixes both, and matches what pane rendering and kitty
graphics already do.
feat(ui): draw stacked pane titles on the frame
Each member of a stack was named twice: once on the box's top border and
again on a title row of its own directly below it. The first member's
title row is now the region's own top border, so a stack costs one row
less than a box plus a row per member, and the name sits where a pane's
name already sits.
A title row is drawn as a ruled frame line opening its own corner rather
than tee-ing into one continuous box, so a stack reads as a deck of cards
rather than as one pane chopped into strips. The region's top border row
is shared with the pane above and is left to the border pass, which has
already drawn its junctions and its colour; only the title text goes
there.
A collapsed member takes a muted version of the accent instead of the
generic border grey, so a stack reads as one group of related panes.
StackSlot carries the region's borders because only the visible member
holds them, and rescanning the pane list for it would be quadratic inside
a render loop.
docs: document stacked panes and the stacked split keybind
Covers prefix+shift+s and the agent panel row change in the sample
config, the keyboard page and the config reference.
feat(ui): name panes after the agent session
A pane's name is now resolved in one place, TerminalState::display_name:
a title the agent pushed, then an explicit rename, then the agent session
name, then the terminal's own title. Pane chrome, stack title rows and
the agent panel all read it, so they cannot drift. Two of them already
had, which is how a renamed session showed on a stack row but not in the
panel.
An agent renaming its own session arrives as a terminal title, so leaving
that out of the chain made a renamed session look unnamed. The agent
session name reaches the panel through the existing pane token, and the
default second row is now agent then pane name.
pi prefixes its title with a lone glyph the same way claude does, so it
joins the set that is stripped before a title is shown. An unnamed pi
session is nothing but that glyph, which now leaves no name and falls
back to the agent label.
feat(input): add a stacked split action
prefix+shift+s puts a new pane in the focused pane's stack, creating one
if the pane is not stacked yet. It sits alongside split_vertical and
split_horizontal as a third way to place a pane, and stays prefix-first
so herdr does not start swallowing keys from shells and editors.
Moving between members needs no new action: collapsed title rows are
ordinary rects stacked vertically, so prefix+j and prefix+k already walk
a stack.
SplitDirection gains a stacked variant, which the cli accepts as
herdr pane split --direction stacked. It has no split axis, so the
conversion to a layout direction is now fallible, and pane move rejects
it before taking the source pane out of its tab rather than after.
feat(ui): render stacked pane title rows
Every member of a stack gets a title row, the visible one included, and
its terminal starts on the row directly below. Without a row of its own
the last collapsed title sat right above the visible terminal and read as
that terminal's label.
The box is drawn once around the whole region and carried by the visible
member, so the existing border joining code handles it like any other
pane. Collapsed rows carry no chrome. Chrome is decided for the region
rather than per member, otherwise the top, middle and bottom of a stack
get different borders and the visible pane's terminal changes height as
focus moves.
Kitty graphics bypass the cell buffer, so a collapsed member is skipped
when collecting placements too; otherwise a hidden pane draws images over
its own title row. A layout with no stacks costs one scan and no
allocation.
feat(layout): add a stacked pane node
Panes in a stack share one region. One shows its terminal and the rest
collapse to a single title row, so a tab with six agents no longer gives
each of them a sixth of the screen.
Unlike zellij, a collapsed pane keeps a full size terminal behind its
title row. Every member is sized to the region the visible member
occupies, so moving through a stack never resizes a pty, never reflows a
running agent, and leaves the bottom buffer that detection reads intact.
The visible member also keeps a floor of content rows, so adding members
drops title rows rather than shrinking every terminal toward nothing.
Stack membership is a session fact, so it is saved with the layout and
reported by the layout API. Restore drops dead members, keeps the visible
one in range, and turns a stack that is down to one pane back into a
plain pane. A stack holds panes rather than subtrees, and applying a
layout restores the member the caller marked visible, so exporting a
layout and applying it back reproduces the same stack.
fix: speed up alternate-screen history reads (#2426)
refs #2387
fix: keep active sidebar rows visible (#2794)
refs #2792
feat(cli): guide agents to Herdr resources
fix(docs): publish channel-aware documentation indexes
fix(docs): apply llms patch during website builds
feat(docs): publish agent-readable documentation
fix: reject prompts to blocked agents (#2790)
* fix: reject prompts to blocked agents
refs #2788
* docs: clarify agent prompt timing
refs #2788
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: detect all claude half-circle spinner frames (#2762)
refs #2760
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: wait for new pane shell readiness (#2774)
* fix: wait for new pane shell readiness
refs #2773
* refactor: share agent startup bounds
refs #2773
* fix: reconcile agent names after startup timeout
refs #2773
* fix: cover agent cleanup scheduling skew
refs #2773
* fix: bound pane shell readiness retries
refs #2773
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: keep tab and sidebar clicks when the terminal reports a stray drag (#2736)
* fix: keep tab and sidebar clicks when the terminal reports a stray drag
This works around a Ghostty bug that causes herdr tabs to be unclickable
in fullscreen mode.
Ghostty on macOS in native fullscreen emits one motion report after a
fresh press in the strip where the menu bar reveals, with the row
shifted to near the bottom of the grid. The cause is upstream: macOS
delivers one mouse event whose y is nearly a window height away from the
real pointer, and Ghostty reports it as it arrives (iTerm2 and
Terminal.app report the same clicks correctly).
Herdr treated the stray report as a real drag and lost the click two
ways: it opened a tab reorder with no drop target, making the release a
no-op, and it handed the release to the pane under the bogus
coordinates.
Now, a press on the tab bar or sidebar owns the gesture until release,
and a tab drag only starts once the pointer is over a real drop target.
refs #796
* fix: scope chrome mouse gestures to their input source
* fix: preserve chrome drag input source
* fix: preserve concurrent chrome presses
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(graphics): support high-dpi direct file frames (#2680)
fix: preserve logical lines in scrollback editor (#2735)
refs #2733
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: add qwen code detection and restore (#2743)
refs #2730
fix(agent): focus Copilot before prompting (#2734)
* fix(agent): focus Copilot before prompting
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(agent): cover stale focus-reporting state
refs #1698
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: strip claude title spinner frames (#2709)
* fix: source title activity glyphs from manifests
refs #2707
* fix: simplify manifest-driven title stripping
refs #2707
* fix: reconcile handoff title policies
refs #2707
* fix: strip claude title spinner frames
refs #2707
* fix: keep claude detection manifest unchanged
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: use the running binary in agent hooks (#2722)
fix: preserve workspace labels for root repositories (#2727)
refs #2594
chore: update contributor list
perf: avoid repeated Git config reads (#2688)
refs #2643
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: synchronously terminate cancelled status commands
fix: detect claude 2.1.228 half-circle busy spinner
fix: disambiguate shifted punctuation keybinds (#2676)
refs #2674
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(render): compact large terminal redraws (#2675)
refs #2670
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): reduce idle agent detection CPU (#2651)
* fix(windows): reduce idle agent detection CPU
refs #2642
* fix(windows): gate agent process discovery
refs #2642
---------
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
fix: make just build cross-platform (#2647)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: derive repo name for embedded bare layouts (#2660)
refs #2657
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: refresh english documentation
fix: wait for agent prompt readiness (#2537)
* fix: wait for agent prompt readiness
refs #2410
* fix: return pane updates after tab bar command
refs #2410
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: keep the outer terminal window title in sync with the session (#2627)
* feat: keep the outer terminal window title in sync with the session
Herdr emulates the terminals in its panes, so an OSC 0/OSC 2 title
written inside a pane stops at Herdr and never reaches the terminal
Herdr itself runs in. That outer title is what window managers read for
title bars, tab bars, and group bars, so it kept showing whatever the
shell or ssh happened to leave behind.
Add `ui.window_title`, rendered from {hostname}, {workspace}, {tab},
{pane}, and {terminal_title}, and push it to the foreground client
whenever it changes. It renders on the server, so {hostname} names the
machine the panes actually run on rather than the machine a thin remote
client runs on, and it is gated on a pending render so an idle loop
never pays for it.
A title is only remembered as delivered once a foreground client takes
it, so the first client to attach is written to rather than skipped.
`client.window_title.set` still wins over the configured title, and
clearing it now hands the title back to `ui.window_title` instead of
only "herdr".
* fix: deliver the outer window title to a newly attached client
ClientConnected assigns the foreground client directly rather than going
through promote_client_to_foreground, so clearing the sent-title cache
there missed the case that matters most: attaching a second terminal to a
running session. The title was usually unchanged, so the sync returned
early and the new terminal kept whatever its shell or ssh had left.
Key the cache on the client that received the title instead of relying on
every foreground assignment to invalidate it.
* perf: keep hidden pane output off the window title path
Output from a hidden or background pane sets needs_render without setting
needs_full_render, and the retained render plan then skips presentation
for it entirely. Syncing the title on needs_render meant every coalesced
hidden-output tick still formatted, sanitized, and allocated a title that
could not have changed, against the hidden-source early exit AGENTS.md
requires.
Every input to the title is app state, which always requests a full
render, so gate on that instead. The one exception is the focused pane's
own terminal title, which arrives through PTY parsing, so ask for a full
render when that changes and the configured title uses it.
* fix: only cache a window title a client writer received
* fix: carry an api set window title across a live handoff
* fix: make outer window title updates event-driven
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
refactor(website): clean up homepage
fix(input): ignore modified j/k/up/down in session navigator (#2377)
The Char('j')/Char('k')/Down/Up match arms in handle_navigator_key
had no modifier guard, unlike every sibling arm in the same match
block, so Ctrl+K, Alt+J, etc. also moved the navigator selection.
refs #1981
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
ci: remove automatic issue gate
fix(windows): strip elevated terminal title decoration (#2632)
fix(server): prioritize shutdown requests (#2624)
refs #2612
test(windows): serialize media player environment access (#2619)
fix: track opencode tui session selection (#2455)
refs #2450
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(ui): anchor the host cursor to modal name inputs (#2569)
* fix(ui): anchor the host cursor to modal name inputs
IMEs draw their composition preview at the host terminal cursor. The rename
and new-worktree dialogs drew a block glyph instead of setting one, so the
frame carried no cursor and the client kept the position the focused pane
last reported. Japanese composition appeared behind the dialog and only
reached the field on Enter.
Set the cursor to the caret column instead, counting wide characters as two
cells.
refs #1755
* fix(ui): keep the clamped caret cell blank
A name that fills the field left the clamped caret sitting on the last
rendered glyph. A terminal inverts the cell under its cursor and an IME
composes there, so the glyph was hidden and composition overlapped it.
Render the text one column short of the field. The field is still cleared
in full, so the clamped caret always lands on a blank cell.
refs #1755
---------
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: center tab labels for symmetric highlight padding (#2570)
* fix: center tab labels for symmetric highlight padding
* docs: note centered tab labels in the changelog
* fix: center tab labels by display width, not char count
feat: add move tab keybind actions (#2561)
* feat: add move tab keybind actions
Add optional keys.move_tab_previous/move_tab_next actions that reorder
the active tab one position, wrapping at either end. Reuses the
existing tab.move runtime path that mouse drag reordering already
drives.
* fix: exit navigate mode on single-tab move attempts
feat: add configurable tab bar status (#2586)
* feat: show a zoom indicator in the desktop tab bar
Reserve the right edge of the tab row for a ZOOM pill while the
focused pane is zoomed, matching the accent style of the mode bars.
The per-tab Z suffix stays; the pill makes the zoomed state visible
at a glance like tmux's status-right flag.
* feat: optionally show the hostname in the desktop tab bar
Add ui.tab_bar_hostname to display the machine's hostname at the right
edge of the tab row, like tmux's #h in status-right. The value resolves
where the server renders, so remote sessions show the remote host. Off
by default.
* fix: strip control characters from the tab bar hostname
* fix: hide the hostname when it would squeeze out the tab strip
* feat: add configurable tab bar status
* fix: harden tab bar status updates
* fix: terminate tab bar status process trees
* fix: disable status commands on unsupported platforms
* fix: skip unchanged status command renders
* fix: keep tab bar status opt-in by default
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
test: guard pane-scaled render performance
refs #2550
feat: add direct pane resize keybindings (#2558)
fix(client): avoid abort on terminal hangup (#2427)
* fix(client): avoid abort on terminal hangup
refs #2424
* test(client): gate PTY integration on unix
refs #2424
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
perf(ui): avoid full pane mode reads for scrollbars (#2554)
fix(input): preserve alt-prefixed control keys (#2543)
refs #2514
fix(website): improve plugins page readability on dark ground
fix(ui): reclaim scrollbar gutter in alternate screen (#2538)
feat(graphics): add direct pane frame streaming (#2523)
* feat(graphics): add direct pane frame streaming
* feat(graphics): expose pane visibility
* test(graphics): preserve legacy terminal image output
* fix(graphics): harden streaming lifecycle
* fix(input): preserve mouse releases outside panes
feat: make outer pane borders configurable (#2535)
fix: make windows installer swaps atomic (#2530)
refs #2356
feat(input): add per-pane right-click routing (#2504)
chore: approve dhh as contributor
fix: forward pane terminal bells (#2498)
refs #2453
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: support all agent integrations on windows (#2496)
fix(windows): share Git Bash agent candidate scans (#2494)
refs #2459
fix(config): report unknown theme names (#2488)
refs #2452
fix: avoid redundant Windows recent-history snapshots (#2474)
refs #962
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve shift in kitty alternate reports (#2479)
refs #2435
fix(remote): restore blocking bridge streams (#2485)
refs #2478
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat(website): rebuild compare page in new design with runtime positioning
fix: verify stable release checksums
fix: publish stable release checksums
chore: update website
feat(marketplace): track star history for trending and new plugin surfaces
fix(theme): refresh host appearance on focus (#2417)
* fix(theme): refresh host appearance on focus
refs #2416
* fix(input): preserve split appearance replies
refs #2416
* fix(input): retain fragmented appearance reports
refs #2416
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(detect): ignore Cursor Run Everything status (#2220)
* fix(detect): ignore Cursor Run Everything status
refs #1763
* fix(detect): constrain Cursor approval controls
refs #1763
* test(detect): remove cursor manifest behavior fixture
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: add positive idle detection for kiro-cli prompt (#2301)
* fix: add positive idle detection for kiro-cli prompt
refs discussion #982
* fix: remove manifest integration tests per reviewer request
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat(copy-mode): add big-word motions (#2270)
Co-authored-by: Ubuntu <ubuntu@ip-172-31-252-234.ca-west-1.compute.internal>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(terminal): restore keyboard reporting on detach (#2395)
refs #2393
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize versioned Python agent wrappers (#2188)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: document custom agent integrations
fix(cli): accept --flag=value and reordered options in pane read/wait-output (#2183)
* fix(cli): accept --flag=value and reordered options in pane read/wait-output
* test(cli): trim redundant pane parser coverage
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: keep plugin marketplace counts current
fix: render OSC 4 palette overrides instead of forwarding the index (#2162)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: avoid ctrl-tab escape sequences in legacy panes
refs #2296
fix(ci): repair contributor gate handling
chore: update canonical repository references
ci: restore approved contributor gate
fix(sidebar): highlight active agent in collapsed sidebar (#2382)
The collapsed sidebar renders agent rows with an unconditional
Style::default().fg(p.overlay0), so the active agent is
indistinguishable from the others. The workspace list directly above
it, and render_agent_detail in the expanded sidebar, both mark the
active entry.
Reuse the existing active treatment: resolve the active entry with the
same is_active_pane call the expanded agent panel uses, then paint the
row background with surface_dim and the position number with text, the
same tokens the collapsed workspace rows already use.
Assisted-By: devx/717e5259-915f-4a7b-af07-6abe46da5b90
feat(windows): support remote attach to unix hosts (#2329)
* feat(windows): support remote attach to unix hosts
* fix(remote): preserve unix bridge behavior
fix(website): update author X profile
chore: remove project-local worktree extension
refs #2325
docs: refresh readme and sponsors
feat(theme): add optional sidebar background
fix(config): accept retired agent panel scope (#2295)
refs #2292
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(input): preserve modifyOtherKeys key releases (#2303)
refs #2302
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): make issue gate structural
fix(terminal): render halfwidth katakana voiced marks (#2257)
Co-authored-by: oyoguhito <oyoguhito@kamatanoMacBook-Pro.local>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(layout): return focus to the pane a split was opened from (#2266)
Closing a focused pane handed focus to the next pane in tree order.
For a pane opened beside another one -- a plugin split, a file viewer,
any transient tool pane -- that is rarely where the user was: it lands
on some unrelated neighbour rather than the pane that opened it.
Track the pane focus came from in TileLayout and prefer it when the
focused pane closes, falling back to tree order when there is no
history, when it points at the pane being closed, or when it points at
a pane that has since gone away. The history lives in the layout, so it
can only ever name a pane in the same tab.
A one-slot history is only sound if internal focus excursions never
write it, so the tree edits that used to bounce focus around now go
through target-taking primitives instead. close_pane removes a
background pane directly, so detach_pane and take_pane_for_move stop
focus-close-refocusing. split_pane splits a target without moving
focus: the runtime split path only focuses the new pane once the spawn
succeeds, which makes a failed split a pure rollback, and the targeted
and unfocused workspace split paths stop fabricating history.
insert_pane_near now takes the focus intent, so an unfocused pane move
leaves the target tab's history alone. The layout-level focused-split
helpers become test-only; production splits all flow through the
target-taking path.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ui): search single-tab names in navigator (#2320)
fix(input): parse default mouse reports (#2312)
* fix(input): parse default mouse reports
refs #2309
* fix(input): preserve split default mouse reports
refs #2309
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(cli): resolve pane query --current from caller (#2298)
refs #2297
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): keep pending url clicks across host focus loss (#2291)
Opening a URL raises the browser, which takes focus away from the host
terminal before the mouse release arrives. release_input_source(_headless)
cleared pending_url_click_sources on that focus loss, so the release was
forwarded to the pane and the agent opened the same URL again.
Clear the set in clear_input_source instead, whose only production caller
is remove_client.
refs #2290
Co-authored-by: kataokatsuki <kataokatsuki@users.noreply.github.com>
feat(ui): add distinct status indicators (#2282)
refs #2260
fix: detect claude confirmation prompts
refs #2268
fix(website): copy heading links to clipboard
fix(ui): preserve sidebar scroll across clients (#2280)
refs #2255
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(input): preserve shift-tab in pane automation (#2259)
refs #1561
fix(docs): allow corrections to published versions
refs #916
feat(plugins): index marketplace manifests
docs: publish preview documentation
fix(ui): keep collapsed workspace status visible (#2239)
refs #2216
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
docs: refine cpu optimization blog post
docs: update website manifest for v0.8.0
release: v0.8.0
docs: finalize 0.8.0 release documentation
feat(website): rebuild marketing pages on new brand chassis
fix: page keys scroll pane scrollback at zsh and REPL prompts (#2191)
* fix: page keys scroll pane scrollback at zsh and REPL prompts
PageUp/PageDown were forwarded to the pane whenever DECCKM (application
cursor) was on, assuming only primary-screen pagers enable it, but zsh's
line editor also enables DECCKM, as do REPLs such as python3. The result
was PageUp scrolling shell history instead of Herdr scrollback.
Bracketed paste discriminates the two: it means the app accepts typed or
pasted text at a prompt, so line editors enable it and pagers do not.
* test: update page key state fixture
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(pi): restrict state reporting to tui sessions (#2159)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: propagate host color scheme to pane apps (#2214)
refs #714
fix(input): preserve hover during extended-button drags
fix(docs): support older git in snapshot checks
fix(docs): publish only released documentation
fix: avoid blocking on foreground cwd checks (#2213)
refs #2206
fix(cli): report non-UTF-8 arguments instead of panicking (#2207)
* fix(cli): report non-UTF-8 arguments instead of panicking
* fix(cli): avoid echoing malformed arguments
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix(client): query host cell size when the ioctl reports no pixels (#2160)
fix: preserve claude settings formatting (#2089)
refs #2066
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: stop advertising worktree json flag (#2174)
refs #2171
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(detect): recognize opencode2 as opencode
refs #2169
fix: route vscode remote copies through osc52 (#2173)
refs #2015
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): detect agents across git bash exec boundaries (#2170)
refs #2107
fix(socket_paths): remove dead if-branch in derive_client_socket_from_api_socket (#2157)
fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard (#2165)
* fix(input): decode 0x1f as Ctrl+_ not Ctrl+- per ASCII standard
refs #2164
* fix(input): update control-byte matrix test for 0x1f -> Ctrl+_
feat: add antigravity-cli integration (#2087)
* feat: add antigravity_cli integration harness
Register the `antigravity_cli` target, resolve its configuration
directory to `~/.gemini/antigravity-cli/`, wire target actions,
and add lifecycle hook scripts for Unix and Windows.
* feat: support session resume for antigravity-cli
* fix: correct antigravity-cli hook config path, shape, and agent label
Antigravity CLI reads global customizations from ~/.gemini/config, keys
hooks.json by hook name, and only accepts the matcher/hooks wrapper for
the tool events. The previous install wrote event arrays at the top level
of ~/.gemini/antigravity-cli/hooks.json, which agy never reads and would
reject anyway, so no Herdr hook ever ran.
Session reports were dropped for a third reason: the hooks reported the
agent as antigravity-cli, but the server normalizes that to the canonical
label agy before matching, so is_official_agent_source never matched and
agy --conversation resume was unreachable.
- Resolve the config dir to ~/.gemini/config
- Nest Herdr entries under a Herdr-owned "herdr" block that install
rewrites and uninstall removes, leaving other named hooks untouched
- Emit grouped entries for PreToolUse/PostToolUse and flat handler lists
for PreInvocation/PostInvocation/Stop
- Report the canonical agy label from both hook assets and match it in
agent_resume
- Compile-gate the hook asset constants and stop shadowing $args in the
PowerShell hook
- Document the real directory, that it must already exist, and the
named-block behavior
refs #1011
refs #1571
* fix: make antigravity-cli integration session-only
antigravity cli cannot express lifecycle safely: there is no blocked
event, postinvocation is skipped on interruption, and stop fires at the
end of a turn rather than on process exit, which left stale state and
released authority at the wrong time.
report only the conversation on preinvocation and let screen detection
own agent state. resume via `agy --conversation <id>` is unchanged.
* fix: update antigravity session after conversation switch
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix(ci): skip pr gate in forks
feat(ui): make pane scrollbars optional (#2166)
refs #2167
fix: expand copy-mode word-end window past a final wide glyph (#2145)
point_is_final_atom compared an atom's terminating column against a
word-motion target's starting column. The two are equal for narrow
cells but never for wide ones, so the read window stopped expanding
and copy-mode `e` halted at the soft-wrap boundary on CJK text.
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: report a clear cli error when no herdr server is running (#1963)
* fix: report a clear cli error when no herdr server is running
socket cli commands surfaced a raw io::Error debug string
(`Error: Os { code: 2, ... }`) when nothing was listening on the
api socket, which read like a bad --cwd path. map dead-socket
connect failures to a `server_not_running` json error carrying the
resolved socket path, printed once at the edge that surfaces the
error; recovering callers (plugin offline registry fallback, agent
start polling) recognize the marker and keep their existing
behavior.
refs #1941
* fix: map dead-socket errors on the unchecked cli request path
refs #1941
* fix: make server-not-running guidance session-aware
refs #1941
fix(windows): preserve semantic escape key taps
fix(input): preserve native key lifecycle across routing (#2142)
refs #2077
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
chore: remove experiments from settings tui
feat: support bottom tab bar placement (#2118)
* feat: support bottom tab bar placement
* fix: preserve mouse cleanup under bottom mode bar
refs #2117
chore: update agentmd for protocol changes
fix: read alternate-screen agent history
fix(sidebar): keep worktree groups packed
fix(client): restore terminal on sighup and sigterm
Enable termination-signal handling so SIGHUP and SIGTERM follow the graceful
quit path and restore terminal state. Log handler registration failures and
add PTY coverage for direct SIGHUP and server EOF restoration
Co-authored-by: Matt Coles <macols@amazon.com>
fix: preserve windows sessions after ssh logout (#2098)
* fix: preserve windows sessions after ssh logout
refs #2008
* chore: document windows wmi safety
refs #2008
fix(omp): support Windows session paths (#2092)
fix: resume agents after headless restore (#2088)
refs #2064
ci: consolidate ai review trigger label
fix: launch argument-free agents on windows (#2075)
refs #2072
fix: add opt-in child-group process detection (#2052)
* fix: add opt-in child-group process detection
refs #1982
* fix: preserve lifecycle probes without foreground groups
refs #1982
fix: preserve kitty associated text (#2051)
refs #2020
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: finish repository organization migration
Update rose pine surface_dim colour to "Overlay" (#2002)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: update repository links after organization transfer
ci: allow repository organization migration
fix: scope agent skill installation
refs #2022
docs: update preview manifest
fix(windows): preserve parent agent ownership
refs #1514
fix: preserve windows path variables during install
refs #1947
test(windows): remove flaky sound timing assertion
refs #1330
fix(windows): restore system notifications and sound playback (#2019)
ci: remove approved contributor bypass
chore: approve merged contributor we11adam
fix: preserve navigate mode after pane focus (#1993)
refs #1850
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
chore: approve merged contributor patrick-xin
docs: add simplified chinese readme (#1990)
* docs: add simplified chinese readme
* fix: publish simplified chinese readme
* fix: require localized readme for releases
* docs: publish simplified chinese readme
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: restore python3 commit hook
fix: select windows python command in commit hook (#1994)
chore: approve merged contributor bioform
fix: count ptmx master fds under devpts layouts (#1984)
live_server_holds_one_pty_master_fd_per_pane counted only /proc/<pid>/fd links
resolving to exactly /dev/ptmx. On devpts setups such as WSL2 and many
containers, a PTY master fd resolves to /dev/pts/ptmx instead, so the test found
zero masters and failed with "had 0 ptmx master fds; expected 1" even though the
server held the pane's master fd. Match both ptmx node paths; pty slaves still
resolve to /dev/pts/<N> and stay uncounted, so the one-master-per-pane invariant
is unchanged.
perf: skip rendering hidden pty updates
fix: preserve linked worktree workspace labels
perf: replace agent spinners with static status marks
fix: ignore nested codex session reports (#1927)
* fix: ignore nested codex session reports
refs #1789
* test: cover matching codex thread id
---------
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: resolve relative plugin commands from plugin root
refs #1949
docs: update sponsor acknowledgements
fix: keep focus on the current workspace when another self-closes (#1912)
handle_pane_died only clamped the stale active/selected indices after
removing a workspace that closed itself, so it never shifted them down
when the removed workspace sat before the focused one. With workspaces
[x, y, z] and focus on y, removing x left active pointing at z, silently
moving the user into a workspace they did not select.
Resolve both indices by workspace id across the removal, as
close_selected_workspace already does, keeping the clamp as the fallback
for when the removed workspace was the focused one. Also scroll the
focused workspace back into view, which the explicit-close path already
did and this one did not.
refs #1621
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: make native windows checks reliable (#1925)
chore: approve merged contributor season179
fix: close workspace when api closes its last tab (#1899)
herdr tab close on a workspace's only tab returned tab_close_failed,
while the TUI close-tab action on the same tab closes the tab and
cascades to closing the workspace. Cascade in the API too, emitting
tab.closed then workspace.closed. When the cascade would close a whole
worktree group, return confirmation_required instead, matching
pane.close and the TUI prompt.
refs #1760
chore: approve merged contributor Pimpmuckl
fix: preserve shift-enter in windows panes (#1909)
refs #1743
fix: delay agent prompt submission
refs #1878
fix: ignore empty clipboard writes
refs #1893
fix: restrict unapproved pull requests to bug fixes
ci: harden pull request workflow execution
chore: approve merged contributor olafkfreund
fix(nix): include SKILL.md in the package fileset (#1890)
refs #1889
fix: repaint after transient terminal resizes
fix: preserve prefix mode for modifier events
refs #1870
feat: print bundled agent skill and hint next cli steps
chore: approve merged contributor yianL
fix: preserve focus when closing a non-focused workspace (#1877)
refs #1328
fix: support non-us shifted keybindings (#1876)
* fix: support non-us shifted keybindings
refs #1870
* docs: require current pull request base
fix: improve sidebar worktree hierarchy and reordering (#1873)
* fix: clarify sidebar worktree hierarchy
refs #1694
* feat: reorder worktree groups as a unit
refs #1694
fix: avoid renders for passive mouse motion (#1872)
refs #1865
perf: avoid full pane renders for spinner animation (#1868)
ci: gate pull request review by scope
fix(nix): add rust-analyzer to development shell
chore: consolidate project skills
docs: define maintainer and agent contribution workflows
feat: switch IME to ASCII in prefix mode on Windows (Korean IME) (#1823)
* feat: switch IME to ASCII in prefix mode on Windows
Extend switch_ascii_input_source_in_prefix to Windows: detect IME state
via WM_IME_CONTROL and toggle to ASCII with SendInput for the Korean IME.
Other IME languages are detected and left unchanged.
refs #1802
* docs: clarify Windows (Korean IME) support for prefix ASCII switching
Follow-up to the Windows prefix ASCII switch, which extended
switch_ascii_input_source_in_prefix to Windows but left the surrounding
text describing macOS only.
- Settings row label: "(macOS)" -> "(macOS/Windows)", plus its test.
- Generalize the Windows behavior wording to "switches the IME to
English (ASCII) input" in the config-reference.json entry and the
model.rs doc comment, and state that Windows support is currently
limited to the Korean IME.
- Add a :::caution aside noting the Korean-IME-only limitation to the
en/ja/zh preview docs, keeping the three translations in sync.
refs #1802
* fix: warn when prefix IME toggle injection is incomplete
SendInput can queue fewer events than requested (for example when blocked
by UIPI), which would otherwise leave the IME silently stuck in ASCII or
native mode. Log a warning with the sent and expected counts so the failure
is diagnosable.
refs #1802
* fix: guard prefix IME restore and correct open-status naming
Address maintainer review on the Windows prefix ASCII switch:
- Restore only when safe: store the foreground window at switch time and,
before toggling back, require that the same window is still focused and
the IME is still in English. This stops restore from toggling another
application or overriding a manual return to Hangul during prefix mode.
- Report injection success from send_vk_tap and only arm restoration when
the initial toggle landed; on a partial injection retry the dropped
key-up so a key is not left logically held down. The injection policy is
split into send_vk_tap_with(inject) so the success, partial, and failure
branches are unit-tested without the real SendInput.
- Correct the WM_IME_CONTROL sub-command naming: 0x0005 is IMC_GETOPENSTATUS
(IME open state), not IMC_GETCONVERSIONMODE. Behavior is unchanged; the
constant, comments, and tests now describe the open-status read.
refs #1802
* fix: bound IME open-status read with a timeout
The prefix IME switch reads IMC_GETOPENSTATUS via WM_IME_CONTROL, which
crosses into the terminal-emulator process. A plain SendMessageW would block
herdr's client thread until that process responds, indefinitely if it hangs.
Read through SendMessageTimeoutW with SMTO_ABORTIFHUNG and a short timeout
instead; on timeout the switch is skipped and restore does nothing, so a hung
host process can no longer freeze prefix-mode entry or exit.
refs #1802
* fix: preserve windows ime restoration after partial injection
refs #1802
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
perf: eliminate repeated workspace git discovery (#1842)
* perf: eliminate repeated workspace git discovery
refs #1838
* fix: keep workspace labels current without extra redraws
refs #1838
* fix: retain discovered workspace git metadata
refs #1838
fix: copy retained mouse selections with keyboard shortcuts
refs #1782
fix: run pi worktree ext on background
chore: approve merged contributor ogulcancelik
fix: bundle modern ConPTY on Windows (#1828)
refs #1533
refs #1644
fix: harden hermes lifecycle detection
feat: filter keybind help (#1832)
* feat: filter keybind help
refs #1825
* fix: recognize shifted slash in keybind help
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add grok cli integration for native session restore (#1807)
* feat: add grok cli integration for native session restore
tl;dr: adds `herdr integration install grok` (session-identity tier: a
SessionStart hook reports the grok session id for native restore; state
stays screen-detected via the bundled manifest).
Grok merges every ~/.grok/hooks/*.json, so install writes a
self-contained hooks/herdr.json registering a SessionStart hook next to
hooks/herdr-agent-state.sh, and never touches other hook files. The hook
prefers $GROK_SESSION_ID (injected into every grok hook process) and
reports through the socket API; herdr:grok is a reserved-native-state
source so screen detection stays authoritative. Restore uses
`grok --resume <id>`. Additive JSON API change; no protocol bump; the
schema artifact is regenerated.
refs #1800
* fix: honor GROK_HOME and validate grok hook config in status
Review follow-ups: grok_dir now resolves GROK_CONFIG_DIR (herdr test
seam) before GROK_HOME (the grok CLI's own config-home override) before
~/.grok, so hook installs land where grok actually looks. Integration
status now also validates the herdr-owned hooks/herdr.json next to the
hook script — missing, corrupt, or no-longer-referencing configs report
the install as outdated instead of masking a hook grok never invokes.
refs #1800
* fix: validate the exact grok session hook command in status
The config validator matched on a filename substring, so a SessionStart
command like `echo herdr-agent-state.sh`, or one invoking the script
without the `session` action, still reported the integration as current
while grok never delivered a session id. Status now compares against the
exact command the installer writes, via a shared builder, and the
degradation tests cover both nonfunctional shapes.
refs #1800
* fix: require a command-type grok session hook in status validation
A config entry carrying the exact generated command under a non-command
hook type (e.g. "http") is never executed by grok, so it must not report
the integration as current. The validator now also requires
type = "command", with a degradation test for the mismatched-type shape.
refs #1800
* fix: validate the complete grok hook config
refs #1800
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor corrius
chore: approve contributor adamkrellenstein
fix: report truncated pane reads
refs #1717
fix: make known-agent exit process-owned
refs #1792
refs #1648
fix: answer XTWINOPS size queries in panes
refs #835
chore: approve contributor joonhwan
fix: prefer branded homepage search image
fix: consume handled url click gestures
refs #1761
fix: preserve kitty graphics during host repaints
refs #1628
fix: inherit host palette in pane queries (#1759)
refs #1752
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor carlesso
chore: approve contributor badlogic
fix: preserve kitty printable key releases
refs #1746
fix: preserve physical escape on windows
refs #1736
fix: respect OMP config directory override
refs #1696
chore: relicense herdr under apache-2.0
refactor: centralize new terminal cwd selection
replaces contributions from Pitchfork-and-Torch
refactor: name darwin nix toolchain inputs
replaces contributions from DeevsDeevs
refactor: simplify macos input source ownership
replaces contributions from sf-jin-ku
refactor: clarify opencode event state mapping
replaces contributions from soar
refactor: simplify cursor session reporting
replaces contributions from udirom
refactor: simplify kimi lifecycle reporting
replaces contributions from wbxl2000
refactor: simplify qoder session reporting
replaces contributions from wayneleelwc
refactor: replace pane mouse and clipboard internals
replaces contributions from othavi0
feat(docs): publish versioned release documentation
fix: keep reading while pty input is blocked
refs #1295
fix: fall back to sh for remote path discovery
refs #1201
docs: add alternate-screen output fallback
docs: update preview manifest
fix(website): add agent automation to docs sidebar
docs: update website manifest for v0.7.5
release: v0.7.5
docs: finalize release docs and refresh agent skill
docs: document alternate-screen automation limits
fix: link plugins without a running server
refs #1670
fix: reject oversized text pastes safely (#1676)
refs #1665
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: bound linux sound player lifetime (#1677)
refs #1622
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: discover canonical mise remote installs
refs #1201
fix: use pi settled lifecycle event
docs: explain Windows cursor and IME trade-off
refs #1637
fix: make plugin state global across sessions
refs #1174
fix: show agent targets before options in help
fix: bound stalled agent prompt waits
fix: report kimi questions as blocked
fix: avoid rechecking cached pane cwd (#1616)
refs #1603
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
feat: add plugin-driven agent views and startup hooks
feat: make agent automation a first-class cli primitive
fix: preserve plugin command arguments (#1613)
fix: show current workspace name in close confirmation
refs #1364
feat: connected tree glyphs, workspace grouping, and search auto-select in navigator
refs #1611
perf: cache windows foreground process snapshots
refs #1158
fix: preserve terminal live follow through resize
fix: support javascript integrations on windows
refs #1531
fix: serialize opencode lifecycle reports
refs #1519
fix: detect codex working with static titles (#1574)
* fix: detect codex working with static titles
refs #1563
* fix: ignore interrupted codex footer
refs #1563
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: report unknown config keys (#1575)
* fix: report unknown config keys
refs #1573
* fix: preserve mixed config warning context
refs #1573
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: batch contiguous terminal diff writes
refs #283
fix: preserve lone escape input boundaries
refs #541
feat: add optional workspace name prompt
fix: update windows conpty smoke for pane-first agents
feat: harden named agent cli workflows
refs #1525
docs: update preview manifest
test(windows): support headless console runners
fix(windows): prevent remaining subprocess console flashes
refs #1468
perf: adopt libghostty integration improvements
refs #276
ci: gate Greptile reviews by contributor approval
fix: detect grok background work from pinned status
fix: detect grok state from terminal signals
chore: update vendored libghostty-vt
refs #276
fix: follow foreground process group leader cwd
refs #1472
refactor: extract active tab surface rendering
fix: preserve selection when auto-copy is disabled (#1496)
refs #1471
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix(windows): suppress noninteractive process windows
refs #1468
docs: update preview manifest
fix(windows): hide agent manifest curl windows
refs #1468
fix: stop agent wait when pane closes (#1488)
chore: enable zed lsp
feat: configure collapsed sidebar startup state
refs #1463
feat: add configurable sidebar token styles
feat(macos): support agent environment hints
refs https://github.com/ogulcancelik/herdr/discussions/679
fix: preserve plugins during live handoff
refs #893
fix: handle pane graphics stream disconnect race
fix: guard cli requests against protocol mismatches (#1453)
refs #1435
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
test: wait for multi-client resize propagation
docs: update preview manifest
docs: update website manifest for v0.7.4
release: v0.7.4
docs: finalize next release documentation
docs: add popup pane usage examples
refs #1125
test: shorten pane graphics socket fixture paths
feat: add floating popup panes
refs #1125
feat: add isolated pane graphics streaming
fix: preserve escape before sgr mouse reports
refs #1334
feat(website): homepage plugin showcase, live star count, faithful claude code mock
fix(linux): scope foreground process discovery to panes
refs #1399
fix: reassemble split sgr mouse input
refs #1382
fix: preserve associated emoji input (#1410)
refs #1404
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
test: shorten macos api socket fixture path
ci: restore fast reliable checks
fix: flush live handoff responses before exit
feat: configure sidebar entry gaps
fix: stop copy mode line-end at text (#1411)
fix: forward horizontal wheel events to panes (#1402)
refs #1349
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: retry dropped omp lifecycle reports
refs #1310
fix(website): scope docs search by locale and channel
fix: forward outer focus events to panes (#1388)
* fix: forward outer focus events to panes
refs #1337
* fix: preserve ordered focus forwarding
refs #1337
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
fix: show renamed single tabs in agents sidebar
refs #1369
fix: reap detached custom command children (#1384)
* fix: reap detached custom command children
refs #1360
* test: harden child cleanup and sidebar metrics
refs #1360
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: explain modified-arrow shell bindings
refs #1370
fix: keep Claude working during /btw
refs #1366
docs: streamline configuration guide
fix: allow slow server shutdowns
fix: detect reordered codex title spinners
refs #1281
feat: add configurable sidebar metadata tokens
docs: add versioned config reference
refactor: centralize agent identity lookup
docs: add troubleshooting guide
refs #1116
fix: number collapsed agent rows by list position
refs #1344
fix: keep windows api connections open
refs #1279
fix: match homepage mock pane chrome and sidebar to tui rendering
fix: clarify config fallback diagnostics
fix: detach windows server from host terminal
refs #1329
chore: remove unmerged approved contributors
feat: add copy-on-select setting
feat: add maki agent support (#1302)
* feat: add maki detection support
Maki always draws a one-line status bar at the bottom of the screen, so the manifest reads just that row: a braille spinner before the `[BUILD]`/`[PLAN]`/`[BASH]` mode label means working, the bare label means idle.
Blocked states come from the panels that replace the input box, the `Permission Required` dialog with its `y Allow`/`n Deny` hint rows and the `Plan complete` form. Maki emits no OSC title or progress, so these screen rules are the only evidence.
Also wires `maki` through process-name identification, per-agent sound overrides, and the website manifest catalog.
* docs: stage maki detection docs
chore: approve contributor tontinton
docs: refresh herdr agent skill
refs #1297
fix: improve config diagnostic delivery
fix: stop windows installer from rewriting config
refs #1162
fix: follow foreground cwd for new terminals
refs #1245
feat: add copy mode search and tmux word motions
refs #1230
docs: document windows config path
ci: pin rust toolchain to 1.96.1
fix: preserve explicit session sockets during live handoff
refs #1180
reported-by: dvic
based-on: https://github.com/dvic/herdr/pull/3
fix: use drawn cursor by default in wsl
refs #930
fix: reanchor pi status after session replacement (#1189)
* fix: reanchor pi status after session replacement
refs #943
* fix: guard active pi sessions from nested startup
refs #943
* fix: serialize pi session replacement reports
refs #943
fix: detect active amp turns
refs #1208
chore: approve merged contributor kovalov
fix: refresh tab bar after plugin-driven tab rename (#1179)
refs #1111
Co-authored-by: Vlad Kovalov <kovalov@users.noreply.github.com>
fix: make remote helper installs shell-portable
refs #1203
fix: match shifted indexed number keybinds
refs #1184
fix: align collapsed sidebar agent rows (#1182)
refs #1168
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: link plugin marketplace from readme
docs: lean readme, add terminal trove gold sponsor
docs: enforce localized release doc parity
refs #1151
docs: update website manifest for v0.7.3
release: v0.7.3
docs: stage 0.7.3 release notes
fix: restore workspace picker keyboard navigation
refs #1149
fix: avoid render-time plain url scans
docs: change sponsorships tiers and add lead sponsor
docs: update preview manifest
ci: ignore microsoft apt repos in artifact builds
ci: clear zig cache before windows checks
fix: keep cursor hide inside sync output
refs #967
fix: guard windows process tree cycles
refs #1083
fix: clear done status on repeated pane focus
fix: preserve navigator search commands (#1140)
Navigator search treated Escape as either modal close or query reset,
which left no way to return to command mode while keeping the filtered
row set. `/` also rebuilt search mode by clearing the query, so a user
could not resume editing the same filter after backing out.
Make Escape leave search focus only, reserve command-mode Escape for
closing the picker, and let `/` refocus the existing query. The footer
now lists the shortcuts for the active mode so command keys are not
advertised while text input owns them.
refs #1115
docs: update website manifest for v0.7.2
release: v0.7.2
docs: finalize release docs
fix: send shifted punctuation as text in kitty mode
refs #1105
fix: preserve alt-shift letters (#1102)
refs #1088
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
perf: move session autosaves off main loop
fix: stop windows server over named pipes
refs #1113
fix: support esc
interrupt for github copilot (#1120)
* fix: support esc interrupt for github copilot
Github Copilot CLI version v1.0.69-2 introduces the "esc interrupt" prompt.
Update the Github Copilot agent detection manifest to match this prompt and correctly report the agent as working.
Add test cases in tests.rs to verify state detection.
Synchronize the website's copy of the manifest.
refs #1119
* test: clean up github copilot detection rules and tests
Clean up formatting and comments for the github copilot detection rule and tests.
refs #1119
* test: remove copilot manifest literal test
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
chore: approve contributor liby
docs: remove star history embed
fix: honor prefix in copy mode
refs #681
Based on PR #1092 by @reobin.
Co-authored-by: Robin Gagnon <me@reobin.dev>
fix: preserve wrapped pane links (#1099)
refs #1098
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
feat: expose pane scroll state
docs: update sponsors
fix: bridge remote image file drops (#1085)
refs #828
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: add community video section
test: synchronize multi-client resize assertion
fix: clarify remote ssh auth failures (#1084)
refs #1034
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
fix: preserve shifted punctuation for alt legacy input (#1076)
refs #1066
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
docs: expose stats page in website nav
fix: write pane copies to native windows clipboard (#1082)
refs #1067
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
chore: approve merged contributor akbash-bot
fix: focus parent after worktree removal (#1075)
refs #1004
Co-authored-by: akbash-bot <akbash-bot@users.noreply.github.com>
docs: update preview manifest
ci: use homebrew zig for preview macos builds
feat(website): add japanese and simplified chinese docs with i18n, translation issue flow
fix: detect grok build working and blocked states from current ui chrome (#1055)
* fix: detect grok build working and blocked states from current ui chrome
refs #1017
* fix: sync grok detection website manifest
refs #1017
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
feat: add public stats page at herdr.dev/stats
ci: accept common environment aliases in issue gate
refactor(nix): replace apple-sdk wrappers with xcbuild (#995)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
fix: retry pi state socket reports
refs #1049
fix: support custom command keybindings on windows
refs #1041
fix: switch prefix ASCII input source on the foreground client (#1016)
* fix: switch prefix ASCII input source on the foreground client
The macOS prefix ASCII-switch ran in the headless server, whose
TISCopyCurrentKeyboardInputSource read is a stale per-process cache
(refreshed only via a main-run-loop notification the server never pumps),
so prefix could leave the terminal on the wrong input source.
Forward it to the foreground client, like clipboard: sync_prefix_input_source
emits AppEvent::PrefixInputSource as an intent; the server forwards it to the
foreground client and the monolithic app applies it in-process via
RealPrefixInputSource, which pumps its main run loop before the stale TIS read.
Key it on Mode::wants_ascii_input so multi-level prefix commands keep ASCII
until returning to the terminal, and restore the IME for rename text entry.
Adds ServerMessage::PrefixInputSource to the already-unreleased protocol 15.
refs #774
* fix: keep prefix input-source switch out of the headless server process
An App-internal drain (the exhaustive drain at the top of
handle_api_request, reachable from prefix-key runtime mutations) can
consume a queued PrefixInputSource intent before the server's
forwarding drain sees it, applying the TIS switch in the headless
server process and stranding the restore state. Gate the in-process
switch on App.local_input_source_switch, disabled by the headless
server alongside the other local side effects, so a swallowed intent
degrades to a skipped switch. Widen the forwarding-bypass maintenance
test to the handle_internal_event_with_prefix_sync wrapper.
refs #774
* docs: clarify prefix input-source comments and flag docs
refs #774
* fix: bump protocol for prefix input source
refs #774
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
test: wait for client frame before crash assertion
test: keep windows smoke cleanup non-fatal
test: wait for windows smoke pane output
fix: wait for server stop socket cleanup
chore: approve contributor TonyxSun
refactor: route headless deferred creates through runtime helpers
refactor: route cli pane placement through runtime adapters
refactor: route cli workspace tab worktree through runtime adapters
refactor: route tui runtime mutations through typed adapters
feat: expose session snapshot through cli
feat: emit layout update events for runtime layout changes
chore: approve contributor ppggff
refactor: route worktree tui actions through runtime wrappers
refactor: route pane layout tui actions through runtime wrappers
fix: allow foreground agent session takeover
refs #943
chore: approve merged contributor DevSrSouza
fix: kitty graphics streams freeze on partial updates and leak host images (#948)
* fix: request a render on kitty graphics writes
pty output containing a kitty graphics sequence only scheduled the
deferred settle render. that render's wake-up notifies the render loop
only when the dirty flag was not already set, so under a continuous
stream of image updates the notify can be dropped and the pane keeps
showing an old frame until som…
Summary
Testing
just checkjust bench-render-scale(50 active panes: 1.40x median versus one pane)