Skip to content

fix(graphics): support high-dpi direct file frames - #2680

Merged
ogulcancelik merged 2 commits into
masterfrom
shared-pane-terminal-browser
Aug 13, 2026
Merged

fix(graphics): support high-dpi direct file frames#2680
ogulcancelik merged 2 commits into
masterfrom
shared-pane-terminal-browser

Conversation

@ogulcancelik

@ogulcancelik ogulcancelik commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • advertise a separate 400 MiB limit for primary-layer direct RGBA file frames
  • keep inline, BGRA, named-layer, and fallback frames capped at 16 MiB
  • upload oversized frames without placement while a pane is hidden or a redraw is in flight, then replay placement after terminal acknowledgement
  • preserve small-frame inline fallback and close oversized streams without producer acknowledgement on terminal rejection
  • update the socket API schema/docs and add high-DPI and tab-switch regression coverage

Testing

  • just check
  • just bench-render-scale (50 active panes: 1.40x median versus one pane)
  • linked Ghostty test for file upload followed by placement
  • independent regression and test review: no remaining findings

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e515034-e5f5-4590-b811-d4b141f37e1c

📥 Commits

Reviewing files that changed from the base of the PR and between 82807f4 and 06d0fd5.

📒 Files selected for processing (1)
  • docs/next/api/herdr-api.schema.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/next/api/herdr-api.schema.json

📝 Walkthrough

Walkthrough

Pane 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.

Changes

Pane graphics direct-transfer flow

Layer / File(s) Summary
API limits and response contract
src/api/schema/..., docs/next/api/herdr-api.schema.json, src/app/api/pane_graphics.rs
The response exposes file_frame_direct_max_bytes. The direct-file limit is 400 MiB.
Frame limit selection and leasing
src/app/api/pane_graphics.rs
Eligible primary-layer RGBA frames use the direct-file limit. Other frames use the standard stream limit. Tests cover advertised limits and fullscreen retina files.
Kitty control validation and file preparation
src/client/direct_graphics.rs, src/client/mod.rs, src/kitty_graphics.rs, src/ghostty/mod.rs
Validation checks control keys, action profiles, dimensions, RGBA length, and placement rules. Direct-file preparation supports upload-only commands and deferred placement.
Fallback and cache state handling
src/server/headless/pane_graphics.rs
Inline fallback rejects oversized leases. Failed direct transfers clear cached pane layers before fallback.
Transfer-path integration coverage
src/server/headless/tests/pane_graphics.rs, docs/next/website/src/content/docs/socket-api.mdx
Tests and documentation cover hidden uploads, placement replay, redraw uploads, fallback limits, and oversized terminal errors.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: ⚪ Minimal · up to 06d0f

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
Loading

Possibly related PRs

  • herdrdev/herdr#2523: Introduced the direct pane-frame streaming path extended by this change.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the graphics fix and directly reflects the PR’s primary change for high-DPI direct file frames.
Description check ✅ Passed The description accurately summarizes the direct-frame limits, fallback behavior, API updates, and regression coverage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch shared-pane-terminal-browser

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kangal-bot kangal-bot added the ai-review Trigger automated AI reviews for pull requests admitted by the PR gate label Aug 11, 2026
@ogulcancelik
ogulcancelik force-pushed the shared-pane-terminal-browser branch from 1c5a16e to 34bb27e Compare August 11, 2026 20:04
@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown

Greptile Summary

The PR extends direct Kitty file transport to support high-DPI primary-layer RGBA frames while retaining the existing inline fallback limit.

  • Advertises separate 16 MiB fallback and 400 MiB direct-file limits through the API.
  • Adds upload-only transfers when placement must wait for pane visibility or redraw completion.
  • Tightens client-side validation of direct graphics controls and dimensions.
  • Adds regression coverage for delayed placement, rejection, redraw, and tab-switch behavior.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the eligible follow-up review scope.

No blocking failure remains.

Important Files Changed

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
Loading

Reviews (5): Last reviewed commit: "Merge branch 'master' into shared-pane-t..." | Re-trigger Greptile

@ogulcancelik
ogulcancelik force-pushed the shared-pane-terminal-browser branch from 34bb27e to 4851fc9 Compare August 11, 2026 20:13
@ogulcancelik
ogulcancelik force-pushed the shared-pane-terminal-browser branch from bd9f8d0 to 82807f4 Compare August 12, 2026 01:58
@ogulcancelik
ogulcancelik merged commit b7dca4b into master Aug 13, 2026
8 checks passed
@kangal-bot kangal-bot removed the ai-review Trigger automated AI reviews for pull requests admitted by the PR gate label Aug 13, 2026
yjuyjuy added a commit to yjuyjuy/herdr that referenced this pull request Aug 13, 2026
* 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>
bdhrs added a commit to bdhrs/herdr that referenced this pull request Aug 14, 2026
- 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…
bdhrs added a commit to bdhrs/herdr that referenced this pull request Aug 14, 2026
- 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…
bdhrs added a commit to bdhrs/herdr that referenced this pull request Aug 14, 2026
- 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…
bdhrs added a commit to bdhrs/herdr that referenced this pull request Aug 14, 2026
- 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…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants