Skip to content

Herdr support - #30

Merged
RobPruzan merged 4 commits into
mainfrom
herdr-support
Aug 11, 2026
Merged

Herdr support#30
RobPruzan merged 4 commits into
mainfrom
herdr-support

Conversation

@RobPruzan

@RobPruzan RobPruzan commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Adds the ability to render terminal-browser inside herdr using a recently released api - herdrdev/herdr#2523, along with a herdr plugin config/initial actions (WIP)

CleanShot.2026-08-10.at.23.28.27.mp4

Herdr added an api that allows our program to draw graphics to the terminal (internally herdr is proxying the kitty graphics protocol file transport medium). Internally instead of writing to the PTY kitty graphics instructions, we instruct herdr directly to draw pixels located inside a file via their socket api.

Architecturally this is fairly simple, at the point of drawing pixels we run our herdr implementation instead of kitty implementation.

We also create a WIP herdr plugin in this PR that exposes actions that wrap the terminal-browser cli. This is useful because users can set shortcuts for these actions via herdrs shortcut system.


Open in Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

*/
export const TERMINALS: Detect[] = [tmux, tty7, wezterm, kitty, cmux, supacode, ghostty, vscode];
export const TERMINALS: Detect[] = [
herdr,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Browser drawn over the whole outer pane when a terminal multiplexer runs inside herdr

herdr is checked before the multiplexer when deciding which terminal we are in (TERMINALS at terminals/src/terminals/index.ts:16), so a session started inside a multiplexer that itself runs in a herdr pane is treated as plain herdr and its picture is placed over the entire outer pane instead of the inner one.

Impact: Users running the browser inside tmux inside herdr get the page drawn in the wrong place and lose the passthrough handling tmux needs.

Why the ordering and the environment-variable inheritance cause this

HERDR_PANE_ID is inherited by the tmux server (and therefore every tmux pane) started from a herdr pane, so herdr in terminals/src/terminals/herdr.ts:39 matches first and tmux (which supplies wrapper: "tmux", see terminals/src/terminals/tmux.ts:31-32) never runs. The previous list put tmux first precisely because "ordering does matter". The same happens on the render side: crate::herdr::Herdr::open() at engine/crates/pixel-core/src/terminal.rs:372 only looks at HERDR_PANE_ID/HERDR_SOCKET_PATH and ignores self.wrapper.relayed(), so frames are pushed straight at the herdr pane while the size and cursor geometry come from the inner tmux pane.

Prompt for agents
Detection order in terminals/src/terminals/index.ts now puts herdr ahead of tmux. HERDR_PANE_ID is inherited into a tmux server started inside a herdr pane, so a browser launched inside tmux-inside-herdr is detected as herdr, losing the tmux wrapper and drawing over the whole outer pane. Consider either keeping tmux (and other multiplexers) ahead of herdr, or having the herdr detector bail out when a multiplexer variable such as TMUX is present. The same guard is needed on the Rust side: Herdr::open() in engine/crates/pixel-core/src/herdr.rs is called unconditionally from Terminal::with_handle even when the wrapper is relayed (tmux).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread terminals/src/terminals/herdr.ts
frames.get_mut(),
&format!(
r#"{{"id":"stream","method":"pane.graphics.stream","params":{{"pane_id":{},"layer_id":"primary","z_index":0}}}}"#,
// checkme: how does pane get here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Leftover question-to-self comment in the new rendering code

A leftover note asking how a value arrives is committed in the middle of the connection request (// checkme: how does pane get here? at engine/crates/pixel-core/src/herdr.rs:60), which the repository rules disallow.

Impact: Readers are left with an unanswered question in shipped code.

Rule reference

AGENTS.md: "Do not proactively write comments in code. We prefer code to be self explanatory ... Comments should be understandable to someone who was just dropped into the codebase for the first time." The checkme note is a personal reminder rather than an explanation.

Suggested change
// checkme: how does pane get here?
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread engine/crates/pixel-core/src/herdr.rs
Comment thread terminals/src/terminals/herdr.ts
this is okay because the new graphics api lands at the same time so the fallback case is useless

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@RobPruzan
RobPruzan merged commit 6b5850f into main Aug 11, 2026
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.

1 participant