aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-26 22:51:28 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-26 22:51:28 +0300
commiteac2314e6ccb4ba91b7272523e68110035167279 (patch)
treecfa813cec6164a75366dfeeaa88d97ab9fa6e0fa
parent427c2606d8f62558e3949d2f44173175e96bed49 (diff)
fix: handle package-manager remote updates
-rw-r--r--docs/next/CHANGELOG.md2
-rw-r--r--docs/next/README.md2
-rw-r--r--docs/next/website/src/content/docs/persistence-remote.mdx2
-rw-r--r--scripts/changelog.py93
-rw-r--r--scripts/test_changelog.py106
-rw-r--r--src/remote.rs245
-rw-r--r--src/update.rs175
-rw-r--r--website/latest.json315
8 files changed, 840 insertions, 100 deletions
diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md
index 09741137..702561d8 100644
--- a/docs/next/CHANGELOG.md
+++ b/docs/next/CHANGELOG.md
@@ -12,6 +12,8 @@
- Added Ctrl-click URL opening inside panes for OSC 8 hyperlinks and visible `http://` or `https://` URLs when the host terminal sends the modified click to Herdr.
### Fixed
+- Remote bootstrap now downloads exact-version release assets for Homebrew and Nix clients instead of copying package-manager-managed local binaries into `~/.local/bin/herdr`.
+- `website/latest.json` now stores asset URLs for archived releases under `releases[version].assets`, so remote bootstrap can fetch the current client version even when Homebrew and the top-level latest release are temporarily out of sync.
- Linux sound alerts no longer fall back to `aplay` for mp3 files, preventing static noise on systems without `paplay`. Herdr now tries mp3-capable players such as `pw-play`, `ffplay`, `mpg123`, and `mpv` instead. (#290)
## [0.6.2] - 2026-05-23
diff --git a/docs/next/README.md b/docs/next/README.md
index 69af1eeb..322f351a 100644
--- a/docs/next/README.md
+++ b/docs/next/README.md
@@ -102,7 +102,7 @@ ssh you@yourserver
herdr
```
-or attach from your local terminal through ssh without opening a shell first. your local herdr acts as a thin client, connects over ssh, starts or attaches to the remote herdr server, and streams the ui back to your terminal. remote attach uses your local keybindings by default; pass `--remote-keybindings server` to use the remote server config instead. pass `--handoff` to opt into live handoff if remote attach needs to replace a supported running remote server.
+or attach from your local terminal through ssh without opening a shell first. your local herdr acts as a thin client, connects over ssh, starts or attaches to the remote herdr server, and streams the ui back to your terminal. remote attach uses your local keybindings by default; pass `--remote-keybindings server` to use the remote server config instead. pass `--handoff` to opt into live handoff if remote attach needs to replace a supported running remote server. Homebrew and Nix clients bootstrap remote hosts from the matching release asset instead of copying the package-manager-managed local binary.
```bash
herdr --remote workbox
diff --git a/docs/next/website/src/content/docs/persistence-remote.mdx b/docs/next/website/src/content/docs/persistence-remote.mdx
index e8ab0902..f83da309 100644
--- a/docs/next/website/src/content/docs/persistence-remote.mdx
+++ b/docs/next/website/src/content/docs/persistence-remote.mdx
@@ -100,7 +100,7 @@ herdr --remote workbox --handoff
If you SSH into the server first and run `herdr` there, Herdr runs entirely on the server. That mode is useful and simple, but it cannot access your local desktop clipboard beyond normal terminal text paste.
-When your local and remote platforms match, Herdr can copy the current local binary. Otherwise it downloads the matching release asset from `https://herdr.dev/latest.json`.
+When your local and remote platforms match, Herdr can copy the current local binary for direct installs. For Homebrew and Nix installs, or when the platforms differ, it downloads the matching release asset for the current client version from `https://herdr.dev/latest.json`.
For local builds or custom binaries, set `HERDR_REMOTE_BINARY` to a local file path before running remote attach.
diff --git a/scripts/changelog.py b/scripts/changelog.py
index 1e7d2738..188bc29e 100644
--- a/scripts/changelog.py
+++ b/scripts/changelog.py
@@ -162,11 +162,35 @@ def normalize_announcement(value: Any, label: str) -> dict[str, str] | None:
return announcement
-def normalize_release_metadata(value: Any, label: str) -> dict[str, Any]:
+def infer_protocol_from_notes(notes: str) -> int | None:
+ match = re.search(r"protocol(?: is now)? version (\d+)", notes, flags=re.IGNORECASE)
+ if match is None:
+ return None
+ return int(match.group(1))
+
+
+def normalize_assets(value: Any, label: str) -> dict[str, str]:
if not isinstance(value, dict):
raise ChangelogError(f"{label} must be an object")
- allowed_keys = {"notes", "announcement"}
+ missing_targets = [target for target in ASSET_TARGETS if target not in value]
+ if missing_targets:
+ raise ChangelogError(f"{label} is missing asset URL for {', '.join(missing_targets)}")
+
+ normalized_assets: dict[str, str] = {}
+ for target in ASSET_TARGETS:
+ url = value.get(target)
+ if not isinstance(url, str) or not url.strip():
+ raise ChangelogError(f"{label} is missing asset URL for {target}")
+ normalized_assets[target] = url.strip()
+ return normalized_assets
+
+
+def normalize_release_metadata(value: Any, label: str, version: str) -> dict[str, Any]:
+ if not isinstance(value, dict):
+ raise ChangelogError(f"{label} must be an object")
+
+ allowed_keys = {"notes", "announcement", "assets", "protocol"}
extra_keys = sorted(set(value) - allowed_keys)
if extra_keys:
raise ChangelogError(f"{label} has unsupported field(s): {', '.join(extra_keys)}")
@@ -176,6 +200,19 @@ def normalize_release_metadata(value: Any, label: str) -> dict[str, Any]:
raise ChangelogError(f"{label} is missing non-empty release notes")
metadata: dict[str, Any] = {"notes": notes.strip()}
+ protocol = value.get("protocol")
+ if protocol is not None:
+ if not isinstance(protocol, int):
+ raise ChangelogError(f"{label}.protocol must be an integer")
+ metadata["protocol"] = protocol
+ else:
+ inferred_protocol = infer_protocol_from_notes(notes)
+ if inferred_protocol is not None:
+ metadata["protocol"] = inferred_protocol
+ if "assets" in value:
+ metadata["assets"] = normalize_assets(value.get("assets"), f"{label}.assets")
+ else:
+ metadata["assets"] = default_release_assets(version)
announcement = normalize_announcement(value.get("announcement"), label)
if announcement is not None:
metadata["announcement"] = announcement
@@ -194,7 +231,7 @@ def normalize_releases(value: Any) -> dict[str, dict[str, Any]]:
raise ChangelogError("releases contains an empty version key")
version = normalize_version(raw_version)
parse_version(version)
- releases[version] = normalize_release_metadata(raw_metadata, f"releases.{version}")
+ releases[version] = normalize_release_metadata(raw_metadata, f"releases.{version}", version)
return {
version: releases[version]
@@ -218,14 +255,14 @@ def build_latest_json(
if protocol is None:
protocol = read_protocol_version()
- missing_targets = [target for target in ASSET_TARGETS if target not in assets]
- if missing_targets:
- raise ChangelogError(f"missing asset targets: {', '.join(missing_targets)}")
-
- ordered_assets = {target: assets[target] for target in ASSET_TARGETS}
+ ordered_assets = normalize_assets(assets, "assets")
normalized_announcement = normalize_announcement(announcement, "root")
archived_releases = normalize_releases(releases)
- current_metadata: dict[str, Any] = {"notes": normalized_notes}
+ current_metadata: dict[str, Any] = {
+ "notes": normalized_notes,
+ "protocol": protocol,
+ "assets": ordered_assets,
+ }
if normalized_announcement is not None:
current_metadata["announcement"] = normalized_announcement
archived_releases[normalized_version] = current_metadata
@@ -320,12 +357,7 @@ def canonicalize_manifest(manifest: dict[str, Any], label: str) -> dict[str, Any
if not isinstance(assets, dict):
raise ChangelogError(f"{label} is missing an assets object")
- normalized_assets: dict[str, str] = {}
- for target in ASSET_TARGETS:
- url = assets.get(target)
- if not isinstance(url, str) or not url.strip():
- raise ChangelogError(f"{label} is missing asset URL for {target}")
- normalized_assets[target] = url.strip()
+ normalized_assets = normalize_assets(assets, f"{label} assets")
return {
"version": normalize_version(version),
@@ -349,6 +381,18 @@ def ensure_manifest_matches_expected(
return canonical_manifest
+def ensure_current_release_assets_are_mirrored(manifest: dict[str, Any], label: str) -> None:
+ canonical = canonicalize_manifest(manifest, label)
+ releases = normalize_releases(manifest.get("releases"))
+ metadata = releases.get(canonical["version"])
+ if metadata is None:
+ raise ChangelogError(f"{label} is missing releases.{canonical['version']}")
+ if metadata.get("assets") != canonical["assets"]:
+ raise ChangelogError(
+ f"{label} releases.{canonical['version']}.assets must match top-level assets"
+ )
+
+
def load_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8")
@@ -377,11 +421,20 @@ def archived_releases_from_current_manifest(manifest: dict[str, Any]) -> dict[st
version = manifest.get("version")
notes = manifest.get("notes")
if isinstance(version, str) and version.strip() and isinstance(notes, str) and notes.strip():
+ normalized_version = normalize_version(version)
metadata: dict[str, Any] = {"notes": notes.strip()}
+ protocol = manifest.get("protocol")
+ if isinstance(protocol, int):
+ metadata["protocol"] = protocol
+ assets = manifest.get("assets")
+ if isinstance(assets, dict):
+ metadata["assets"] = normalize_assets(assets, "current root assets")
+ else:
+ metadata["assets"] = default_release_assets(normalized_version)
announcement = normalize_announcement(manifest.get("announcement"), "current root")
if announcement is not None:
metadata["announcement"] = announcement
- releases[normalize_version(version)] = metadata
+ releases[normalized_version] = metadata
return {
release_version: releases[release_version]
@@ -583,19 +636,23 @@ def cmd_verify_release_state(args: argparse.Namespace) -> int:
release_payload = fetch_release_payload(version, args.repo)
expected_manifest = manifest_from_release_payload(release_payload, version, args.protocol)
+ local_raw_manifest = load_json(Path(args.output))
local_manifest = ensure_manifest_matches_expected(
- load_json(Path(args.output)),
+ local_raw_manifest,
expected_manifest,
str(args.output),
)
+ ensure_current_release_assets_are_mirrored(local_raw_manifest, str(args.output))
print(f"GitHub release v{version}: OK")
print(f"local manifest ({args.output}): OK")
+ live_raw_manifest = fetch_remote_json(args.live_url, args.live_url)
live_manifest = ensure_manifest_matches_expected(
- fetch_remote_json(args.live_url, args.live_url),
+ live_raw_manifest,
expected_manifest,
args.live_url,
)
+ ensure_current_release_assets_are_mirrored(live_raw_manifest, args.live_url)
print(f"live manifest ({args.live_url}): OK")
verify_asset_urls_resolve(dict(expected_manifest["assets"]), "release")
diff --git a/scripts/test_changelog.py b/scripts/test_changelog.py
index 1d46179a..a1bce002 100644
--- a/scripts/test_changelog.py
+++ b/scripts/test_changelog.py
@@ -12,9 +12,11 @@ from scripts.changelog import (
canonicalize_manifest,
DEFAULT_PRODUCT_ANNOUNCEMENT_PATH,
default_release_assets,
+ ensure_current_release_assets_are_mirrored,
ensure_manifest_is_outdated,
ensure_manifest_matches_expected,
extract_section_body,
+ infer_protocol_from_notes,
load_product_announcement,
manifest_from_release_payload,
prepare_release,
@@ -80,6 +82,7 @@ class ChangelogScriptTests(unittest.TestCase):
"macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.1/herdr-macos-aarch64",
},
)
+ self.assertEqual(manifest["releases"]["0.1.1"]["assets"], manifest["assets"])
def test_build_latest_json_embeds_product_announcement(self) -> None:
manifest = json.loads(
@@ -111,22 +114,58 @@ class ChangelogScriptTests(unittest.TestCase):
)
self.assertEqual(list(manifest["releases"]), ["0.1.2", "0.1.1"])
- self.assertEqual(manifest["releases"]["0.1.2"], {"notes": "### Fixed\n- Two"})
- self.assertEqual(manifest["releases"]["0.1.1"], {"notes": "### Fixed\n- One"})
+ self.assertEqual(manifest["releases"]["0.1.2"]["notes"], "### Fixed\n- Two")
+ self.assertEqual(manifest["releases"]["0.1.2"]["protocol"], read_protocol_version())
+ self.assertEqual(manifest["releases"]["0.1.2"]["assets"], default_release_assets("0.1.2"))
+ self.assertEqual(manifest["releases"]["0.1.1"]["notes"], "### Fixed\n- One")
+ self.assertEqual(manifest["releases"]["0.1.1"]["assets"], default_release_assets("0.1.1"))
+
+ def test_build_latest_json_accepts_release_metadata_assets(self) -> None:
+ assets = default_release_assets("0.1.1")
+ manifest = json.loads(
+ build_latest_json(
+ "0.1.2",
+ "### Fixed\n- Two",
+ default_release_assets("0.1.2"),
+ releases={"0.1.1": {"notes": "### Fixed\n- One", "assets": assets}},
+ )
+ )
+
+ self.assertEqual(manifest["releases"]["0.1.1"]["assets"], assets)
+
+ def test_build_latest_json_preserves_release_metadata_protocol(self) -> None:
+ manifest = json.loads(
+ build_latest_json(
+ "0.1.2",
+ "### Fixed\n- Two",
+ default_release_assets("0.1.2"),
+ releases={"0.1.1": {"notes": "### Fixed\n- One", "protocol": 7}},
+ )
+ )
+
+ self.assertEqual(manifest["releases"]["0.1.1"]["protocol"], 7)
- def test_build_latest_json_rejects_release_metadata_assets(self) -> None:
- with self.assertRaisesRegex(ChangelogError, "unsupported"):
+ def test_build_latest_json_infers_release_metadata_protocol_from_notes(self) -> None:
+ manifest = json.loads(
build_latest_json(
"0.1.2",
"### Fixed\n- Two",
default_release_assets("0.1.2"),
- releases={"0.1.1": {"notes": "### Fixed\n- One", "assets": {}}},
+ releases={
+ "0.1.1": {
+ "notes": "### Breaking Changes\n- The client/server protocol is now version 7."
+ }
+ },
)
+ )
+
+ self.assertEqual(manifest["releases"]["0.1.1"]["protocol"], 7)
def test_archived_releases_from_current_manifest_seeds_legacy_root(self) -> None:
releases = archived_releases_from_current_manifest(
{
"version": "0.1.1",
+ "protocol": 3,
"notes": "### Fixed\n- One",
"announcement": {
"id": "one",
@@ -141,6 +180,8 @@ class ChangelogScriptTests(unittest.TestCase):
{
"0.1.1": {
"notes": "### Fixed\n- One",
+ "protocol": 3,
+ "assets": default_release_assets("0.1.1"),
"announcement": {
"id": "one",
"title": "One",
@@ -154,6 +195,7 @@ class ChangelogScriptTests(unittest.TestCase):
releases = archived_releases_from_current_manifest(
{
"version": "0.1.2",
+ "protocol": read_protocol_version(),
"notes": "### Fixed\n- Root",
"releases": {
"0.1.2": {"notes": "### Fixed\n- Stale"},
@@ -162,8 +204,22 @@ class ChangelogScriptTests(unittest.TestCase):
}
)
- self.assertEqual(releases["0.1.2"], {"notes": "### Fixed\n- Root"})
- self.assertEqual(releases["0.1.1"], {"notes": "### Fixed\n- One"})
+ self.assertEqual(releases["0.1.2"]["notes"], "### Fixed\n- Root")
+ self.assertEqual(releases["0.1.1"]["notes"], "### Fixed\n- One")
+ self.assertEqual(releases["0.1.2"]["protocol"], read_protocol_version())
+ self.assertEqual(releases["0.1.2"]["assets"], default_release_assets("0.1.2"))
+ self.assertEqual(releases["0.1.1"]["assets"], default_release_assets("0.1.1"))
+
+ def test_infer_protocol_from_notes(self) -> None:
+ self.assertEqual(
+ infer_protocol_from_notes("The client/server protocol is now version 10."),
+ 10,
+ )
+ self.assertEqual(
+ infer_protocol_from_notes("The client/server protocol version 9."),
+ 9,
+ )
+ self.assertIsNone(infer_protocol_from_notes("No wire changes."))
def write_temp_json(self, content: str) -> Path:
tmp = tempfile.NamedTemporaryFile("w", delete=False, encoding="utf-8")
@@ -346,6 +402,42 @@ class ChangelogScriptTests(unittest.TestCase):
canonical = ensure_manifest_matches_expected(actual, expected, "test manifest")
self.assertEqual(canonical, expected)
+ def test_current_release_assets_must_be_mirrored(self) -> None:
+ assets = default_release_assets("0.1.1")
+ ensure_current_release_assets_are_mirrored(
+ {
+ "version": "0.1.1",
+ "protocol": read_protocol_version(),
+ "notes": "### Fixed\n- One",
+ "assets": assets,
+ "releases": {
+ "0.1.1": {
+ "notes": "### Fixed\n- One",
+ "assets": assets,
+ }
+ },
+ },
+ "test manifest",
+ )
+
+ def test_current_release_assets_must_match_top_level_assets(self) -> None:
+ with self.assertRaisesRegex(ChangelogError, "assets must match top-level assets"):
+ ensure_current_release_assets_are_mirrored(
+ {
+ "version": "0.1.1",
+ "protocol": read_protocol_version(),
+ "notes": "### Fixed\n- One",
+ "assets": default_release_assets("0.1.1"),
+ "releases": {
+ "0.1.1": {
+ "notes": "### Fixed\n- One",
+ "assets": default_release_assets("0.1.0"),
+ }
+ },
+ },
+ "test manifest",
+ )
+
def test_ensure_manifest_matches_expected_rejects_different_notes(self) -> None:
with self.assertRaisesRegex(ChangelogError, "does not match the published GitHub release manifest"):
ensure_manifest_matches_expected(
diff --git a/src/remote.rs b/src/remote.rs
index 9a4cc774..3cf1e43b 100644
--- a/src/remote.rs
+++ b/src/remote.rs
@@ -300,9 +300,63 @@ impl RemoteHerdr {
#[derive(Deserialize)]
struct RemoteUpdateManifest {
version: String,
+ protocol: Option<u32>,
+ assets: BTreeMap<String, String>,
+ #[serde(default, deserialize_with = "deserialize_remote_manifest_releases")]
+ releases: BTreeMap<String, RemoteReleaseMetadata>,
+}
+
+#[derive(Deserialize)]
+struct RemoteReleaseMetadata {
+ protocol: Option<u32>,
+ #[serde(default)]
assets: BTreeMap<String, String>,
}
+fn deserialize_remote_manifest_releases<'de, D>(
+ deserializer: D,
+) -> Result<BTreeMap<String, RemoteReleaseMetadata>, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ let value = Option::<serde_json::Value>::deserialize(deserializer)?;
+ Ok(match value {
+ Some(serde_json::Value::Object(object)) => object
+ .into_iter()
+ .filter_map(|(version, release)| {
+ serde_json::from_value::<RemoteReleaseMetadata>(release)
+ .ok()
+ .map(|metadata| (version, metadata))
+ })
+ .collect(),
+ _ => BTreeMap::new(),
+ })
+}
+
+impl RemoteUpdateManifest {
+ fn release_for_version(&self, version: &str) -> Option<RemoteManifestReleaseRef<'_>> {
+ if self.version.trim_start_matches('v') == version {
+ return Some(RemoteManifestReleaseRef {
+ protocol: self.protocol,
+ assets: &self.assets,
+ });
+ }
+
+ self.releases.get(version).and_then(|release| {
+ (!release.assets.is_empty()).then_some(RemoteManifestReleaseRef {
+ protocol: release.protocol,
+ assets: &release.assets,
+ })
+ })
+ }
+}
+
+#[derive(Clone, Copy)]
+struct RemoteManifestReleaseRef<'a> {
+ protocol: Option<u32>,
+ assets: &'a BTreeMap<String, String>,
+}
+
struct InstallSource {
path: PathBuf,
temporary_dir: Option<PathBuf>,
@@ -525,11 +579,23 @@ fn remote_binary_override_path() -> io::Result<Option<PathBuf>> {
}
fn install_source_description(platform: &RemotePlatform, override_binary: Option<&Path>) -> String {
+ install_source_description_for(
+ platform,
+ override_binary,
+ local_binary_can_seed_remote(platform),
+ )
+}
+
+fn install_source_description_for(
+ platform: &RemotePlatform,
+ override_binary: Option<&Path>,
+ local_binary_can_seed_remote: bool,
+) -> String {
if let Some(path) = override_binary {
return format!("{REMOTE_BINARY_ENV_VAR} ({})", path.display());
}
- if *platform == RemotePlatform::local() {
+ if local_binary_can_seed_remote {
"the current local herdr binary".to_string()
} else {
format!(
@@ -549,12 +615,24 @@ fn resolve_install_source(
if *platform == RemotePlatform::local() {
let path = std::env::current_exe()?;
- return Ok(InstallSource::persistent(path));
+ if !crate::update::is_package_manager_managed_exe_path(&path) {
+ return Ok(InstallSource::persistent(path));
+ }
}
download_release_asset(platform)
}
+fn local_binary_can_seed_remote(platform: &RemotePlatform) -> bool {
+ if *platform != RemotePlatform::local() {
+ return false;
+ }
+
+ std::env::current_exe()
+ .map(|path| !crate::update::is_package_manager_managed_exe_path(&path))
+ .unwrap_or(false)
+}
+
#[derive(Debug, Clone, PartialEq, Eq)]
enum RemoteServerStatus {
Running {
@@ -985,16 +1063,22 @@ fn download_release_asset(platform: &RemotePlatform) -> io::Result<InstallSource
let manifest: RemoteUpdateManifest = serde_json::from_slice(&manifest_output.stdout)
.map_err(|err| io::Error::other(format!("failed to parse update manifest JSON: {err}")))?;
- if manifest.version.trim_start_matches('v') != CURRENT_VERSION {
- return Err(io::Error::other(format!(
- "remote host is {}, but this local herdr is {CURRENT_VERSION} and the latest release manifest is {}; build herdr for the remote platform or install it there manually",
- platform.asset_key(),
- manifest.version
- )));
- }
let asset_key = platform.asset_key();
- let url = manifest.assets.get(&asset_key).ok_or_else(|| {
+ let release = manifest.release_for_version(CURRENT_VERSION).ok_or_else(|| {
+ io::Error::other(format!(
+ "release manifest does not include herdr {CURRENT_VERSION}; build herdr for {} or install it there manually",
+ platform.asset_key()
+ ))
+ })?;
+ if let Some(protocol) = release.protocol {
+ if protocol != CURRENT_PROTOCOL {
+ return Err(io::Error::other(format!(
+ "release manifest has herdr {CURRENT_VERSION} protocol {protocol}, but this client needs protocol {CURRENT_PROTOCOL}; set {REMOTE_BINARY_ENV_VAR}=target/release/herdr or install a matching herdr on the remote host manually"
+ )));
+ }
+ }
+ let url = release.assets.get(&asset_key).ok_or_else(|| {
io::Error::other(format!(
"no {asset_key} binary in the release manifest for herdr {CURRENT_VERSION}"
))
@@ -1805,6 +1889,122 @@ mod tests {
}
#[test]
+ fn remote_update_manifest_uses_root_assets_for_latest_version() {
+ let manifest: RemoteUpdateManifest = serde_json::from_str(
+ r#"{
+ "version": "1.2.3",
+ "assets": {
+ "linux-x86_64": "https://example.com/latest"
+ },
+ "releases": {
+ "1.2.3": {
+ "assets": {
+ "linux-x86_64": "https://example.com/archive"
+ }
+ }
+ }
+ }"#,
+ )
+ .unwrap();
+
+ assert_eq!(
+ manifest
+ .release_for_version("1.2.3")
+ .and_then(|release| release.assets.get("linux-x86_64"))
+ .map(String::as_str),
+ Some("https://example.com/latest")
+ );
+ }
+
+ #[test]
+ fn remote_update_manifest_reads_archived_release_assets() {
+ let manifest: RemoteUpdateManifest = serde_json::from_str(
+ r#"{
+ "version": "1.2.4",
+ "assets": {
+ "linux-x86_64": "https://example.com/latest"
+ },
+ "releases": {
+ "1.2.3": {
+ "notes": "ignored",
+ "assets": {
+ "linux-x86_64": "https://example.com/archive"
+ }
+ }
+ }
+ }"#,
+ )
+ .unwrap();
+
+ assert_eq!(
+ manifest
+ .release_for_version("1.2.3")
+ .and_then(|release| release.assets.get("linux-x86_64"))
+ .map(String::as_str),
+ Some("https://example.com/archive")
+ );
+ }
+
+ #[test]
+ fn remote_update_manifest_uses_archived_release_protocol() {
+ let manifest: RemoteUpdateManifest = serde_json::from_str(
+ r#"{
+ "version": "1.2.4",
+ "protocol": 42,
+ "assets": {
+ "linux-x86_64": "https://example.com/latest"
+ },
+ "releases": {
+ "1.2.3": {
+ "notes": "ignored",
+ "protocol": 41,
+ "assets": {
+ "linux-x86_64": "https://example.com/archive"
+ }
+ }
+ }
+ }"#,
+ )
+ .unwrap();
+
+ assert_eq!(
+ manifest
+ .release_for_version("1.2.3")
+ .and_then(|release| release.protocol),
+ Some(41)
+ );
+ }
+
+ #[test]
+ fn remote_update_manifest_does_not_inherit_latest_protocol_for_archived_assets() {
+ let manifest: RemoteUpdateManifest = serde_json::from_str(
+ r#"{
+ "version": "1.2.4",
+ "protocol": 42,
+ "assets": {
+ "linux-x86_64": "https://example.com/latest"
+ },
+ "releases": {
+ "1.2.3": {
+ "notes": "ignored",
+ "assets": {
+ "linux-x86_64": "https://example.com/archive"
+ }
+ }
+ }
+ }"#,
+ )
+ .unwrap();
+
+ assert_eq!(
+ manifest
+ .release_for_version("1.2.3")
+ .and_then(|release| release.protocol),
+ None
+ );
+ }
+
+ #[test]
fn remote_server_restart_reason_requires_stop_for_protocol_mismatch() {
assert_eq!(
remote_server_restart_reason(Some(CURRENT_VERSION), Some(0), false),
@@ -1847,12 +2047,35 @@ mod tests {
arch: "aarch64",
};
assert_eq!(
- install_source_description(&platform, Some(Path::new("/tmp/herdr-aarch64"))),
+ install_source_description_for(&platform, Some(Path::new("/tmp/herdr-aarch64")), false),
"HERDR_REMOTE_BINARY (/tmp/herdr-aarch64)"
);
}
#[test]
+ fn install_source_description_uses_local_binary_when_allowed() {
+ let platform = RemotePlatform::local();
+
+ assert_eq!(
+ install_source_description_for(&platform, None, true),
+ "the current local herdr binary"
+ );
+ }
+
+ #[test]
+ fn install_source_description_uses_release_asset_when_local_binary_cannot_seed_remote() {
+ let platform = RemotePlatform::local();
+
+ assert_eq!(
+ install_source_description_for(&platform, None, false),
+ format!(
+ "the {CURRENT_VERSION} release asset for {}",
+ platform.asset_key()
+ )
+ );
+ }
+
+ #[test]
fn resolve_install_source_uses_override_binary_without_temporary_cleanup() {
let platform = RemotePlatform {
os: "linux",
diff --git a/src/update.rs b/src/update.rs
index afbbc662..81cfb848 100644
--- a/src/update.rs
+++ b/src/update.rs
@@ -276,6 +276,18 @@ fn parse_homebrew_formula_stable_version(input: &[u8]) -> Result<Version, String
})
}
+fn homebrew_update_from_formula_json(
+ input: &[u8],
+ current: &Version,
+) -> Result<Option<Version>, String> {
+ let latest = parse_homebrew_formula_stable_version(input)?;
+ if &latest <= current {
+ return Ok(None);
+ }
+
+ Ok(Some(latest))
+}
+
fn check_homebrew_latest() -> Result<Option<Version>, String> {
let current = Version::current();
@@ -294,15 +306,10 @@ fn check_homebrew_latest() -> Result<Option<Version>, String> {
.map_err(|e| format!("curl failed: {e}"))?;
if !output.status.success() {
- return Ok(None);
- }
-
- let latest = parse_homebrew_formula_stable_version(&output.stdout)?;
- if latest <= current {
- return Ok(None);
+ return Err("failed to fetch Homebrew formula JSON".into());
}
- Ok(Some(latest))
+ homebrew_update_from_formula_json(&output.stdout, &current)
}
// ---------------------------------------------------------------------------
@@ -1425,13 +1432,7 @@ fn is_homebrew_managed_install() -> bool {
return false;
};
- if is_homebrew_managed_exe_path(&current_exe) {
- return true;
- }
-
- current_exe
- .canonicalize()
- .is_ok_and(|path| is_homebrew_managed_exe_path(&path))
+ is_homebrew_managed_exe_path_following_links(&current_exe)
}
fn is_nix_managed_install() -> bool {
@@ -1439,12 +1440,29 @@ fn is_nix_managed_install() -> bool {
return false;
};
- if is_nix_store_exe_path(&current_exe) {
+ is_nix_store_exe_path_following_links(&current_exe)
+}
+
+pub(crate) fn is_package_manager_managed_exe_path(path: &Path) -> bool {
+ is_homebrew_managed_exe_path_following_links(path)
+ || is_nix_store_exe_path_following_links(path)
+}
+
+fn is_homebrew_managed_exe_path_following_links(path: &Path) -> bool {
+ if is_homebrew_managed_exe_path(path) {
+ return true;
+ }
+
+ path.canonicalize()
+ .is_ok_and(|path| is_homebrew_managed_exe_path(&path))
+}
+
+fn is_nix_store_exe_path_following_links(path: &Path) -> bool {
+ if is_nix_store_exe_path(path) {
return true;
}
- current_exe
- .canonicalize()
+ path.canonicalize()
.is_ok_and(|path| is_nix_store_exe_path(&path))
}
@@ -1903,13 +1921,19 @@ fn auto_update_homebrew(events: tokio::sync::mpsc::Sender<crate::events::AppEven
}
fn homebrew_release_notes_body(version: &Version) -> String {
- if let Ok(manifest) = fetch_update_manifest() {
- if let Some(metadata) = manifest.metadata_for_version(version) {
- let notes_body = metadata.notes_body();
- if !notes_body.is_empty() {
- handle_manifest_announcement(&version.to_string(), metadata.announcement.as_ref());
- return notes_body;
- }
+ let manifest = fetch_update_manifest().ok();
+ homebrew_release_notes_body_from_manifest(version, manifest.as_ref())
+}
+
+fn homebrew_release_notes_body_from_manifest(
+ version: &Version,
+ manifest: Option<&UpdateManifest>,
+) -> String {
+ if let Some(metadata) = manifest.and_then(|manifest| manifest.metadata_for_version(version)) {
+ let notes_body = metadata.notes_body();
+ if !notes_body.is_empty() {
+ handle_manifest_announcement(&version.to_string(), metadata.announcement.as_ref());
+ return notes_body;
}
}
@@ -2102,10 +2126,34 @@ mod tests {
}
#[test]
+ fn package_manager_path_detection_follows_homebrew_symlink() {
+ #[cfg(unix)]
+ {
+ let root = std::env::temp_dir().join(format!(
+ "herdr-homebrew-symlink-test-{}",
+ std::process::id()
+ ));
+ let cellar_bin = root.join("Cellar/herdr/0.6.2/bin");
+ let opt_bin = root.join("opt/herdr/bin");
+ fs::create_dir_all(&cellar_bin).unwrap();
+ fs::create_dir_all(&opt_bin).unwrap();
+ let cellar_binary = cellar_bin.join("herdr");
+ let opt_binary = opt_bin.join("herdr");
+ fs::write(&cellar_binary, b"").unwrap();
+ std::os::unix::fs::symlink(&cellar_binary, &opt_binary).unwrap();
+
+ assert!(is_package_manager_managed_exe_path(&opt_binary));
+
+ let _ = fs::remove_dir_all(root);
+ }
+ }
+
+ #[test]
fn nix_store_path_is_detected() {
let path = Path::new("/nix/store/abc123-herdr-0.6.1/bin/herdr");
assert!(is_nix_store_exe_path(path));
+ assert!(is_package_manager_managed_exe_path(path));
}
#[test]
@@ -2126,6 +2174,59 @@ mod tests {
}
#[test]
+ fn homebrew_formula_update_uses_formula_stable_not_manifest_latest() {
+ let current = Version::parse("0.6.1").unwrap();
+ let update = homebrew_update_from_formula_json(
+ br#"{"versions":{"stable":"0.6.2","head":"HEAD","bottle":true}}"#,
+ &current,
+ )
+ .unwrap();
+
+ assert_eq!(update, Some(Version::parse("0.6.2").unwrap()));
+ }
+
+ #[test]
+ fn homebrew_formula_update_ignores_versions_that_are_not_newer() {
+ let current = Version::parse("0.6.2").unwrap();
+ let update = homebrew_update_from_formula_json(
+ br#"{"versions":{"stable":"0.6.2","head":"HEAD","bottle":true}}"#,
+ &current,
+ )
+ .unwrap();
+
+ assert_eq!(update, None);
+ }
+
+ #[test]
+ fn homebrew_release_notes_use_package_manager_guidance() {
+ let body =
+ homebrew_release_notes_body_from_manifest(&Version::parse("0.6.3").unwrap(), None);
+
+ assert_eq!(body, "### Changed\n- v0.6.3 is available through Homebrew.");
+ }
+
+ #[test]
+ fn homebrew_release_notes_can_use_manifest_metadata() {
+ let manifest: UpdateManifest = serde_json::from_str(
+ r####"{
+ "version": "0.6.3",
+ "protocol": 10,
+ "notes": "### Fixed\n- Brew notes",
+ "assets": {
+ "linux-x86_64": "https://example.com/herdr-linux-x86_64"
+ }
+ }"####,
+ )
+ .unwrap();
+ let body = homebrew_release_notes_body_from_manifest(
+ &Version::parse("0.6.3").unwrap(),
+ Some(&manifest),
+ );
+
+ assert_eq!(body, "### Fixed\n- Brew notes");
+ }
+
+ #[test]
fn fake_release_notes_default_to_real_large_changelog_section() {
let _guard = env_lock().lock().unwrap();
std::env::remove_var(FAKE_UPDATE_NOTES_VERSION_ENV);
@@ -2954,5 +3055,31 @@ mod tests {
"unexpected asset name for {target}: {url}"
);
}
+
+ for (version, release) in &manifest.releases {
+ let assets = release
+ .get("assets")
+ .and_then(serde_json::Value::as_object)
+ .unwrap_or_else(|| panic!("missing assets for release {version}"));
+ for target in [
+ "linux-x86_64",
+ "linux-aarch64",
+ "macos-x86_64",
+ "macos-aarch64",
+ ] {
+ let url = assets
+ .get(target)
+ .and_then(serde_json::Value::as_str)
+ .unwrap_or_else(|| panic!("missing asset URL for {version} {target}"));
+ assert!(
+ url.contains(&format!("/releases/download/v{version}/")),
+ "unexpected release URL for {version} {target}: {url}"
+ );
+ assert!(
+ url.ends_with(&format!("herdr-{target}")),
+ "unexpected asset name for {version} {target}: {url}"
+ );
+ }
+ }
}
}
diff --git a/website/latest.json b/website/latest.json
index 6236aad3..ad294ddb 100644
--- a/website/latest.json
+++ b/website/latest.json
@@ -10,13 +10,34 @@
},
"releases": {
"0.6.2": {
- "notes": "### Added\n- Added optional Nix flake support for building, running, installing, and developing Herdr with Nix. (#208, #221, #264)\n- Added `terminal.new_cwd` to choose whether new panes, tabs, and workspaces follow the source pane/workspace, start in `$HOME`, use Herdr's process directory, or use a fixed path.\n- Added `herdr integration install omp` for OMP's `.omp` extension directory. The extension reports OMP pane state through Herdr's socket API without relying on native `omp` process detection.\n- Added CLI and socket API support for Git worktrees with `herdr worktree list/create/open/remove`, optional worktree provenance on workspace responses, and client/server protocol version 10.\n\n### Fixed\n- GitHub Copilot CLI sessions now use tested terminal heuristics for approval prompts, freeform input, plan review, and thinking states in the Agents panel. (#232, #256, thanks @LaneBirmingham)\n- Kiro approval prompts are now detected as blocked in the Agents panel. (#255)\n- Workspace labels now follow the live pane working directory after directory changes.\n- Remote clients using local keybindings no longer show stale server keybinding warnings from the remote host."
+ "notes": "### Added\n- Added optional Nix flake support for building, running, installing, and developing Herdr with Nix. (#208, #221, #264)\n- Added `terminal.new_cwd` to choose whether new panes, tabs, and workspaces follow the source pane/workspace, start in `$HOME`, use Herdr's process directory, or use a fixed path.\n- Added `herdr integration install omp` for OMP's `.omp` extension directory. The extension reports OMP pane state through Herdr's socket API without relying on native `omp` process detection.\n- Added CLI and socket API support for Git worktrees with `herdr worktree list/create/open/remove`, optional worktree provenance on workspace responses, and client/server protocol version 10.\n\n### Fixed\n- GitHub Copilot CLI sessions now use tested terminal heuristics for approval prompts, freeform input, plan review, and thinking states in the Agents panel. (#232, #256, thanks @LaneBirmingham)\n- Kiro approval prompts are now detected as blocked in the Agents panel. (#255)\n- Workspace labels now follow the live pane working directory after directory changes.\n- Remote clients using local keybindings no longer show stale server keybinding warnings from the remote host.",
+ "protocol": 10,
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.2/herdr-macos-aarch64"
+ }
},
"0.6.1": {
- "notes": "### Added\n- Added `ui.mouse_scroll_lines` to configure how many pane scrollback lines each mouse wheel notch scrolls. The default remains 3. (#236)\n- Added `--remote-keybindings local|server` for `herdr --remote`. Remote attach now uses the launching client's local keybindings by default without copying config files to the remote host; use `--remote-keybindings server` to keep the remote server's keybindings. The client/server protocol is now version 9.\n- Added `experimental.reveal_hidden_cursor_for_cjk_ime = false` (opt-in), `experimental.cjk_ime_agents = []` (optional allow-list), and `experimental.cjk_ime_cursor_shape = \"steady_block\"` to expose the focused pane's cursor anchor to the outer terminal even when the pane requested `?25l`, restoring macOS IME candidate-window tracking for TUIs that paint their own cursor (Claude Code, pi, codex). When `cjk_ime_agents` is non-empty, the reveal applies only to focused panes whose detected agent matches one of the listed names. When the pane reports no cursor position, the anchor falls back to the pane's top-left so a stable IME hint is always available. Trade-off when enabled: an extra hardware cursor may appear in the outer terminal for apps that hide the cursor without painting a replacement. (#149, thanks @ChihGodlee)\n- Added explicit sidebar Git worktree groups plus native worktree creation, existing checkout open, and safe checkout cleanup flows, configured by `[worktrees].directory`, `keys.new_worktree`, optional `keys.open_worktree`, and optional `keys.remove_worktree`. (#137)\n- Added named-session reattach and stop command hints so detach and update guidance point back to the active session. (#199, thanks @Golden-Pigeon)\n\n### Fixed\n- Pane apps that query OSC 10/11 default foreground/background colors now receive the host terminal colors, so OpenCode and similar TUIs can detect light terminal themes inside Herdr. (#253)\n- Codex Plan mode question prompts now override stale integration `working` reports when the visible terminal UI is clearly waiting for an answer, stale hook authority is cleared when foreground process detection sees Codex exit back to the shell, and Claude Code cancellations now recover from stale hook `working` reports when the idle prompt returns. (#249)\n- Keybinding parsing now accepts non-ASCII printable keys such as `\u00f6`, `\u00e9`, and `\u011f`, including UTF-8 Alt chords. (#247)\n- Kimi Code CLI sessions now use structural terminal detection for approval prompts and live thinking/tool status, improving working and blocked state reporting in the Agents panel. (#215)\n- Antigravity CLI (`agy`) sessions are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#207)\n- Cursor Agent sessions launched as `cursor-agent` or symlink aliases such as `agent` are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#225)\n- Agent detection now ignores runtime argument strings when identifying foreground processes, reducing false positives from helper commands and wrapped processes. (#238)\n- In-app notifications now stay below interactive floating overlays, so dialogs and menus remain readable and clickable while a toast is visible. (#228)\n- `herdr --remote` now offers to restart the remote server after installing or replacing a remote binary, or when the running server version differs, even if the client/server protocol is still compatible."
+ "notes": "### Added\n- Added `ui.mouse_scroll_lines` to configure how many pane scrollback lines each mouse wheel notch scrolls. The default remains 3. (#236)\n- Added `--remote-keybindings local|server` for `herdr --remote`. Remote attach now uses the launching client's local keybindings by default without copying config files to the remote host; use `--remote-keybindings server` to keep the remote server's keybindings. The client/server protocol is now version 9.\n- Added `experimental.reveal_hidden_cursor_for_cjk_ime = false` (opt-in), `experimental.cjk_ime_agents = []` (optional allow-list), and `experimental.cjk_ime_cursor_shape = \"steady_block\"` to expose the focused pane's cursor anchor to the outer terminal even when the pane requested `?25l`, restoring macOS IME candidate-window tracking for TUIs that paint their own cursor (Claude Code, pi, codex). When `cjk_ime_agents` is non-empty, the reveal applies only to focused panes whose detected agent matches one of the listed names. When the pane reports no cursor position, the anchor falls back to the pane's top-left so a stable IME hint is always available. Trade-off when enabled: an extra hardware cursor may appear in the outer terminal for apps that hide the cursor without painting a replacement. (#149, thanks @ChihGodlee)\n- Added explicit sidebar Git worktree groups plus native worktree creation, existing checkout open, and safe checkout cleanup flows, configured by `[worktrees].directory`, `keys.new_worktree`, optional `keys.open_worktree`, and optional `keys.remove_worktree`. (#137)\n- Added named-session reattach and stop command hints so detach and update guidance point back to the active session. (#199, thanks @Golden-Pigeon)\n\n### Fixed\n- Pane apps that query OSC 10/11 default foreground/background colors now receive the host terminal colors, so OpenCode and similar TUIs can detect light terminal themes inside Herdr. (#253)\n- Codex Plan mode question prompts now override stale integration `working` reports when the visible terminal UI is clearly waiting for an answer, stale hook authority is cleared when foreground process detection sees Codex exit back to the shell, and Claude Code cancellations now recover from stale hook `working` reports when the idle prompt returns. (#249)\n- Keybinding parsing now accepts non-ASCII printable keys such as `\u00f6`, `\u00e9`, and `\u011f`, including UTF-8 Alt chords. (#247)\n- Kimi Code CLI sessions now use structural terminal detection for approval prompts and live thinking/tool status, improving working and blocked state reporting in the Agents panel. (#215)\n- Antigravity CLI (`agy`) sessions are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#207)\n- Cursor Agent sessions launched as `cursor-agent` or symlink aliases such as `agent` are now detected, and their terminal UI now reports working and blocked states in the Agents panel. (#225)\n- Agent detection now ignores runtime argument strings when identifying foreground processes, reducing false positives from helper commands and wrapped processes. (#238)\n- In-app notifications now stay below interactive floating overlays, so dialogs and menus remain readable and clickable while a toast is visible. (#228)\n- `herdr --remote` now offers to restart the remote server after installing or replacing a remote binary, or when the running server version differs, even if the client/server protocol is still compatible.",
+ "protocol": 9,
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.1/herdr-macos-aarch64"
+ }
},
"0.6.0": {
"notes": "### Added\n- Added keybinding v2 with explicit `prefix+...` syntax, array bindings per action, configurable prefix-mode pane focus, tab switching, and direct modified chords for users who opt in. (#154, #201, #202, #219)\n- Added `herdr config reset-keys` to back up `config.toml` and remove custom keybindings so built-in v2 defaults apply on restart or config reload. (#154)\n- Added an integrations tab in settings and first-run onboarding so users can install recommended agent integrations from inside Herdr.\n- Added update badges on the sidebar menu, settings menu item, and integrations settings tab when installed integrations are outdated.\n- Added `terminal.default_shell` to choose the executable used for new interactive panes. When unset, Herdr still falls back to `$SHELL`, then `/bin/sh`. (#196)\n- Added native Kiro CLI detection with idle and working state heuristics. (#185)\n\n### Fixed\n- Keybinding conflict warnings now stay visible and show one readable yellow row per conflicting binding.\n- Update prompts that need to stop a running server now default Enter to yes and show `[Y/n]`.\n- Pending release notes no longer open automatically on startup; the latest notes remain available from the menu.\n- Running `herdr server` directly now prints socket and log paths and explains that normal TUI users should run `herdr`.\n- Kitty graphics virtual Unicode placeholders now render image placements instead of leaving placeholder cells behind. (#136)\n- Clipboard image reads are now capped to Herdr's image payload limit, preventing oversized local clipboard images from being read into memory.\n- The install script now reads Herdr's public latest-release manifest, so fresh installs use the same binary URLs as `herdr update`.\n- The Claude Code integration no longer lets subagent completion hooks report durable `working`, preventing delayed recap or subagent completion events from reviving an idle pane. (#198)\n- Remote clients now bridge local clipboard images into the remote pane by staging them as temporary image files and pasting the remote path, so Claude Code image paste works over `herdr --remote`. (#205)\n\n### Breaking Changes\n- Removed the separate `keys.quit` binding. Use `keys.detach`, which detaches in server mode and exits in `--no-session` mode. The default detach binding is now `prefix+q`.\n- Keybindings now use explicit trigger syntax: `prefix+c` means prefix mode, while `ctrl+alt+c` is direct. Bare printable direct bindings such as `new_tab = \"c\"` are rejected with diagnostics because they intercept normal typing. The default keymap now gives tmux-style tab actions to `prefix+c`, `prefix+n`/`prefix+p`, and `prefix+1..9`, uses `prefix+w` for workspace navigation, and moves pane focus to `prefix+h/j/k/l`. (#154)\n- The client/server protocol is now version 8. Stop and restart any running v0.5.12 server before attaching with this release.",
+ "protocol": 8,
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.6.0/herdr-macos-aarch64"
+ },
"announcement": {
"id": "keybinding-v2",
"title": "Keybind Refactor",
@@ -24,112 +45,330 @@
}
},
"0.5.12": {
- "notes": "### Fixed\n- The Claude Code integration no longer reports successful or failed post-tool hooks as `working`, and installing the updated integration removes Herdr's deprecated post-tool hook entries from existing Claude settings. (#198)\n- The Codex integration now reports native `PermissionRequest` hooks as `blocked`, so permission prompts no longer stay pinned as `working` after a tool-use hook. (#198)\n- Workspace and tab rename prompts now handle Backspace, Ctrl+Backspace, Alt+Backspace, Cmd+Backspace, Ctrl+H, Ctrl+W, and Ctrl+U as editing shortcuts instead of inserting stray characters or clearing unexpectedly. (#204)"
+ "notes": "### Fixed\n- The Claude Code integration no longer reports successful or failed post-tool hooks as `working`, and installing the updated integration removes Herdr's deprecated post-tool hook entries from existing Claude settings. (#198)\n- The Codex integration now reports native `PermissionRequest` hooks as `blocked`, so permission prompts no longer stay pinned as `working` after a tool-use hook. (#198)\n- Workspace and tab rename prompts now handle Backspace, Ctrl+Backspace, Alt+Backspace, Cmd+Backspace, Ctrl+H, Ctrl+W, and Ctrl+U as editing shortcuts instead of inserting stray characters or clearing unexpectedly. (#204)",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.12/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.12/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.12/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.12/herdr-macos-aarch64"
+ }
},
"0.5.11": {
- "notes": "### Added\n- Added the `terminal` built-in theme, which uses the host terminal's ANSI palette for Herdr UI colors. (#140, #146, thanks @babymastodon)\n- Added Hermes Agent foreground-process detection with basic idle, working, and blocked heuristics. (#144)\n- Added a Hermes Agent plugin integration for direct state reporting. (#144)\n- Added `ui.sidebar_min_width` and `ui.sidebar_max_width` to configure the sidebar's expanded resize bounds. Defaults remain 18 and 36 columns; existing configs are unchanged. (#132, #135, thanks @ChihGodlee)\n\n### Fixed\n- Running the internal `herdr client` command from inside Herdr now respects the nested-launch guard, and the command is no longer advertised in root help. (#187)\n- The Herdr agent skill now refuses to claim pane ownership unless it is running inside Herdr. (#152)\n- Terminal-style docs code blocks now keep their copy button in the top-right corner. (#190)\n- The sidebar `new` workspace button now aligns with the sidebar's left padding. (#189)\n- Herdr now preserves `session.json` symlinks when saving persistent session state. (#139, #147, thanks @cloudmanic)\n- Alt+Backspace is now preserved when forwarded into panes. (#155, #165)\n- Directional pane focus now works while a tab is zoomed. (#151, #167)\n- Agent detection now prefers the foreground process group leader, reducing false matches from child helper processes. (#161, #172)\n- Remote attach now uses a matching `herdr` already available on the remote `PATH` before installing a new copy. (#170)\n- Modified Enter input such as Shift+Enter is now preserved in supported terminals. (#168)\n- Sidebar agent entries now show user-assigned agent names when available. (#145)\n\n### Breaking Changes\n- The client/server protocol is now version 7. Stop and restart any running v0.5.10 server before attaching with this release."
+ "notes": "### Added\n- Added the `terminal` built-in theme, which uses the host terminal's ANSI palette for Herdr UI colors. (#140, #146, thanks @babymastodon)\n- Added Hermes Agent foreground-process detection with basic idle, working, and blocked heuristics. (#144)\n- Added a Hermes Agent plugin integration for direct state reporting. (#144)\n- Added `ui.sidebar_min_width` and `ui.sidebar_max_width` to configure the sidebar's expanded resize bounds. Defaults remain 18 and 36 columns; existing configs are unchanged. (#132, #135, thanks @ChihGodlee)\n\n### Fixed\n- Running the internal `herdr client` command from inside Herdr now respects the nested-launch guard, and the command is no longer advertised in root help. (#187)\n- The Herdr agent skill now refuses to claim pane ownership unless it is running inside Herdr. (#152)\n- Terminal-style docs code blocks now keep their copy button in the top-right corner. (#190)\n- The sidebar `new` workspace button now aligns with the sidebar's left padding. (#189)\n- Herdr now preserves `session.json` symlinks when saving persistent session state. (#139, #147, thanks @cloudmanic)\n- Alt+Backspace is now preserved when forwarded into panes. (#155, #165)\n- Directional pane focus now works while a tab is zoomed. (#151, #167)\n- Agent detection now prefers the foreground process group leader, reducing false matches from child helper processes. (#161, #172)\n- Remote attach now uses a matching `herdr` already available on the remote `PATH` before installing a new copy. (#170)\n- Modified Enter input such as Shift+Enter is now preserved in supported terminals. (#168)\n- Sidebar agent entries now show user-assigned agent names when available. (#145)\n\n### Breaking Changes\n- The client/server protocol is now version 7. Stop and restart any running v0.5.10 server before attaching with this release.",
+ "protocol": 7,
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.11/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.11/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.11/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.11/herdr-macos-aarch64"
+ }
},
"0.5.10": {
- "notes": "### Added\n- Added indexed keybind families under `[keys.indexed]` for jumping directly to workspace, tab, or visible agent positions 1-9.\n- Added hook-owned custom agent status labels, so integrations can show short visual states like `indexing` without changing semantic agent status.\n- Added terminal-backed agent commands and socket API methods for listing, reading, sending to, renaming, focusing, waiting on, attaching to, and starting agent terminals.\n- Added direct terminal attach with `herdr agent attach <target>` and `herdr terminal attach <terminal_id>`.\n- Added `ui.prompt_new_tab_name = false` for creating new tabs immediately with generated names instead of opening the rename dialog. (#123)\n- Added optional `keys.edit_scrollback` to open the focused pane's retained scrollback in `$EDITOR` inside a temporary zoomed pane. (#122)\n\n### Changed\n- Renamed the focused pane fullscreen keybinding to `keys.zoom`; `keys.fullscreen` remains supported as a legacy alias.\n\n### Fixed\n- Grok Build is now detected as `grok`, with basic working, blocked, and idle state detection. Conflicting known-agent hook labels are ignored once native foreground-process detection identifies a different known agent. (#133)\n- Terminal cursor shapes now forward through attached clients. (#116)\n- Herdr now redraws immediately when the outer terminal regains focus.\n- GitHub Copilot is now correctly detected when its process name is `copilot`. (#118)\n- Integration installs now respect `PI_CODING_AGENT_DIR`, `CLAUDE_CONFIG_DIR`, and `CODEX_HOME` when choosing Pi, Claude Code, and Codex config paths. (#121)\n- Split pane resize hit areas no longer overlap the first content column or row, making text selection work from the start of right and bottom panes. (#120)\n- Dragging text selections near pane edges now autoscrolls into scrollback, and selection state now clears correctly when switching workspaces, tabs, or panes. (#128, #129, thanks @leeeanh)\n- Zoomed panes now keep their border visible in tabs that contain multiple panes. (#115)"
+ "notes": "### Added\n- Added indexed keybind families under `[keys.indexed]` for jumping directly to workspace, tab, or visible agent positions 1-9.\n- Added hook-owned custom agent status labels, so integrations can show short visual states like `indexing` without changing semantic agent status.\n- Added terminal-backed agent commands and socket API methods for listing, reading, sending to, renaming, focusing, waiting on, attaching to, and starting agent terminals.\n- Added direct terminal attach with `herdr agent attach <target>` and `herdr terminal attach <terminal_id>`.\n- Added `ui.prompt_new_tab_name = false` for creating new tabs immediately with generated names instead of opening the rename dialog. (#123)\n- Added optional `keys.edit_scrollback` to open the focused pane's retained scrollback in `$EDITOR` inside a temporary zoomed pane. (#122)\n\n### Changed\n- Renamed the focused pane fullscreen keybinding to `keys.zoom`; `keys.fullscreen` remains supported as a legacy alias.\n\n### Fixed\n- Grok Build is now detected as `grok`, with basic working, blocked, and idle state detection. Conflicting known-agent hook labels are ignored once native foreground-process detection identifies a different known agent. (#133)\n- Terminal cursor shapes now forward through attached clients. (#116)\n- Herdr now redraws immediately when the outer terminal regains focus.\n- GitHub Copilot is now correctly detected when its process name is `copilot`. (#118)\n- Integration installs now respect `PI_CODING_AGENT_DIR`, `CLAUDE_CONFIG_DIR`, and `CODEX_HOME` when choosing Pi, Claude Code, and Codex config paths. (#121)\n- Split pane resize hit areas no longer overlap the first content column or row, making text selection work from the start of right and bottom panes. (#120)\n- Dragging text selections near pane edges now autoscrolls into scrollback, and selection state now clears correctly when switching workspaces, tabs, or panes. (#128, #129, thanks @leeeanh)\n- Zoomed panes now keep their border visible in tabs that contain multiple panes. (#115)",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.10/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.10/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.10/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.10/herdr-macos-aarch64"
+ }
},
"0.5.9": {
- "notes": "### Added\n- Added experimental Kitty graphics rendering for local panes and attached clients behind `experimental.kitty_graphics`, including support for larger graphics frames.\n- Added `ui.toast.delivery = \"system\"` for OS-level background notifications, using `notify-send` on Linux and `terminal-notifier` or `osascript` on macOS.\n- Added light variants for Catppuccin, Tokyo Night, Gruvbox, One, Solarized, Kanagawa, and Ros\u00e9 Pine themes.\n- Added `ui.mouse_capture = false` for tmux-style mouse behavior, letting the terminal handle normal clicks while still forwarding mouse input to pane apps that request it.\n\n### Changed\n- Moved experimental settings into `[experimental]`.\n\n### Fixed\n- PageUp and PageDown now scroll Herdr pane scrollback for normal panes while still forwarding keys to full-screen or mouse-reporting apps.\n- Enhanced tilde key sequences now parse correctly, improving compatibility with terminals that emit them.\n- `herdr integration install codex` now enables the current Codex `[features] hooks = true` flag and migrates the deprecated top-level `codex_hooks` flag.\n\n### Breaking Changes\n- `advanced.allow_nested` has moved to `experimental.allow_nested`; update configs that allow nested Herdr launches.\n- The client/server protocol is now version 5. Stop and restart any running v0.5.8 server before attaching with this release."
+ "notes": "### Added\n- Added experimental Kitty graphics rendering for local panes and attached clients behind `experimental.kitty_graphics`, including support for larger graphics frames.\n- Added `ui.toast.delivery = \"system\"` for OS-level background notifications, using `notify-send` on Linux and `terminal-notifier` or `osascript` on macOS.\n- Added light variants for Catppuccin, Tokyo Night, Gruvbox, One, Solarized, Kanagawa, and Ros\u00e9 Pine themes.\n- Added `ui.mouse_capture = false` for tmux-style mouse behavior, letting the terminal handle normal clicks while still forwarding mouse input to pane apps that request it.\n\n### Changed\n- Moved experimental settings into `[experimental]`.\n\n### Fixed\n- PageUp and PageDown now scroll Herdr pane scrollback for normal panes while still forwarding keys to full-screen or mouse-reporting apps.\n- Enhanced tilde key sequences now parse correctly, improving compatibility with terminals that emit them.\n- `herdr integration install codex` now enables the current Codex `[features] hooks = true` flag and migrates the deprecated top-level `codex_hooks` flag.\n\n### Breaking Changes\n- `advanced.allow_nested` has moved to `experimental.allow_nested`; update configs that allow nested Herdr launches.\n- The client/server protocol is now version 5. Stop and restart any running v0.5.8 server before attaching with this release.",
+ "protocol": 5,
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.9/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.9/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.9/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.9/herdr-macos-aarch64"
+ }
},
"0.5.8": {
- "notes": "### Added\n- Added manual pane labels through `herdr pane rename`, the `pane.rename` socket API, an optional `keys.rename_pane` binding, and the right-click pane menu.\n- Added `ui.show_agent_labels_on_pane_borders`, which can show detected or reported agent names in split pane borders when no manual pane label is set.\n- Added `herdr integration status [--outdated-only]` so installed agent integrations can be checked for legacy or outdated versions.\n- Added an optional `keys.open_notification_target` binding for jumping to the pane behind the current notification.\n- Added optional `keys.previous_agent` and `keys.next_agent` bindings for cycling through sidebar agent entries.\n\n### Changed\n- Scrolling over the tab bar now switches tabs directly, including overflowing tab bars.\n\n### Fixed\n- Indexed terminal palette colors now render correctly for 256-color terminal apps.\n- Hook-based agent integrations now reject stale out-of-order reports and base notifications on effective agent state, reducing duplicate or stuck state changes.\n- Background tabs now resize when the outer terminal size changes, preventing stale pane dimensions when switching back to them.\n- Client shutdown now drains queued control messages more reliably.\n- Pane cursors are now hidden while scrolled back, and omitted while the mobile switcher is open.\n- Mobile agent switcher entries now include tab context, making agents easier to identify on narrow terminals.\n- macOS foreground job detection now uses process groups, improving agent state tracking for foreground commands.\n- Remote SSH no longer fails before connecting when macOS temporary bridge socket paths exceed Unix socket length limits. (#103, thanks @moonsphere)\n- Nix-wrapped agent commands are now detected by their underlying agent entrypoint.\n- Pane renames made through the socket API now rerender immediately."
+ "notes": "### Added\n- Added manual pane labels through `herdr pane rename`, the `pane.rename` socket API, an optional `keys.rename_pane` binding, and the right-click pane menu.\n- Added `ui.show_agent_labels_on_pane_borders`, which can show detected or reported agent names in split pane borders when no manual pane label is set.\n- Added `herdr integration status [--outdated-only]` so installed agent integrations can be checked for legacy or outdated versions.\n- Added an optional `keys.open_notification_target` binding for jumping to the pane behind the current notification.\n- Added optional `keys.previous_agent` and `keys.next_agent` bindings for cycling through sidebar agent entries.\n\n### Changed\n- Scrolling over the tab bar now switches tabs directly, including overflowing tab bars.\n\n### Fixed\n- Indexed terminal palette colors now render correctly for 256-color terminal apps.\n- Hook-based agent integrations now reject stale out-of-order reports and base notifications on effective agent state, reducing duplicate or stuck state changes.\n- Background tabs now resize when the outer terminal size changes, preventing stale pane dimensions when switching back to them.\n- Client shutdown now drains queued control messages more reliably.\n- Pane cursors are now hidden while scrolled back, and omitted while the mobile switcher is open.\n- Mobile agent switcher entries now include tab context, making agents easier to identify on narrow terminals.\n- macOS foreground job detection now uses process groups, improving agent state tracking for foreground commands.\n- Remote SSH no longer fails before connecting when macOS temporary bridge socket paths exceed Unix socket length limits. (#103, thanks @moonsphere)\n- Nix-wrapped agent commands are now detected by their underlying agent entrypoint.\n- Pane renames made through the socket API now rerender immediately.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.8/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.8/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.8/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.8/herdr-macos-aarch64"
+ }
},
"0.5.7": {
- "notes": "### Added\n- Added ANSI-formatted pane reads to the CLI and socket API with `herdr pane read --format ansi` / `--ansi`, preserving colors and styles for visible and recent pane output.\n\n### Changed\n- The agents panel now highlights the currently focused agent entry, matching the active workspace styling. (#84, thanks @soomtong)\n\n### Fixed\n- Git branch and ahead/behind refreshes now run off the main loop, preventing slow Git status checks from freezing the UI.\n- Update and startup flows now detect incompatible running servers earlier and give clear stop/restart guidance instead of trying to attach with a mismatched client/server protocol.\n- `herdr update` now downloads and prepares the new binary before stopping a running server, reducing the chance of interrupting an active session when download or install preparation fails."
+ "notes": "### Added\n- Added ANSI-formatted pane reads to the CLI and socket API with `herdr pane read --format ansi` / `--ansi`, preserving colors and styles for visible and recent pane output.\n\n### Changed\n- The agents panel now highlights the currently focused agent entry, matching the active workspace styling. (#84, thanks @soomtong)\n\n### Fixed\n- Git branch and ahead/behind refreshes now run off the main loop, preventing slow Git status checks from freezing the UI.\n- Update and startup flows now detect incompatible running servers earlier and give clear stop/restart guidance instead of trying to attach with a mismatched client/server protocol.\n- `herdr update` now downloads and prepares the new binary before stopping a running server, reducing the chance of interrupting an active session when download or install preparation fails.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.7/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.7/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.7/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.7/herdr-macos-aarch64"
+ }
},
"0.5.6": {
- "notes": "### Added\n- Added the `vesper` built-in theme. (#71, thanks @nexxeln)\n- Added `herdr --remote <ssh-target>`, so you can use Herdr as a thin client for remote servers without SSHing in first. Herdr connects over SSH, bootstraps a matching remote `herdr` binary when needed, starts the remote server automatically, and streams an efficient terminal view back to your local terminal.\n\n### Changed\n- Updated the bundled `libghostty-vt` engine and removed the custom Linux C++ runtime link workaround from static builds.\n- CLI workspace, tab, and pane creation now preserve the current focus by default; pass `--focus` to switch to the newly created item.\n\n### Fixed\n- OSC 8 hyperlinks emitted inside panes now remain clickable after Herdr renders them, including titled markdown-style links.\n- Agent panel scope now defaults to `all` and is saved to config when changed, so choosing `current` or `all` survives session resets and upgrades.\n- Native agent hook state now clears when the detected native agent exits, preventing stale hook-reported status from sticking to a pane.\n- Clicking an in-app agent toast now jumps to the relevant pane and clears the toast after focus."
+ "notes": "### Added\n- Added the `vesper` built-in theme. (#71, thanks @nexxeln)\n- Added `herdr --remote <ssh-target>`, so you can use Herdr as a thin client for remote servers without SSHing in first. Herdr connects over SSH, bootstraps a matching remote `herdr` binary when needed, starts the remote server automatically, and streams an efficient terminal view back to your local terminal.\n\n### Changed\n- Updated the bundled `libghostty-vt` engine and removed the custom Linux C++ runtime link workaround from static builds.\n- CLI workspace, tab, and pane creation now preserve the current focus by default; pass `--focus` to switch to the newly created item.\n\n### Fixed\n- OSC 8 hyperlinks emitted inside panes now remain clickable after Herdr renders them, including titled markdown-style links.\n- Agent panel scope now defaults to `all` and is saved to config when changed, so choosing `current` or `all` survives session resets and upgrades.\n- Native agent hook state now clears when the detected native agent exits, preventing stale hook-reported status from sticking to a pane.\n- Clicking an in-app agent toast now jumps to the relevant pane and clears the toast after focus.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.6/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.6/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.6/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.6/herdr-macos-aarch64"
+ }
},
"0.5.5": {
- "notes": "### Added\n- Added a mobile layout for narrow terminals, making it practical to SSH into your machine and run herdr from your phone.\n\n### Fixed\n- Non-ASCII terminal input is no longer dropped when UTF-8 characters arrive split across multiple reads.\n- Native agent detection now clears agents after their foreground process exits and control returns to the shell, preventing stale agent status in the sidebar.\n- Pane contents no longer shift horizontally when scrollback appears, keeping the scrollbar gutter stable."
+ "notes": "### Added\n- Added a mobile layout for narrow terminals, making it practical to SSH into your machine and run herdr from your phone.\n\n### Fixed\n- Non-ASCII terminal input is no longer dropped when UTF-8 characters arrive split across multiple reads.\n- Native agent detection now clears agents after their foreground process exits and control returns to the shell, preventing stale agent status in the sidebar.\n- Pane contents no longer shift horizontally when scrollback appears, keeping the scrollbar gutter stable.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.5/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.5/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.5/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.5/herdr-macos-aarch64"
+ }
},
"0.5.4": {
- "notes": "### Fixed\n- Visible active-tab panes that finish while the outer terminal is unfocused are now marked as seen when you return to herdr, preventing stale done/attention indicators.\n- IME candidate windows and mobile SSH cursor tracking now stay anchored to the focused pane during client redraws, including apps that hide the cursor, instead of drifting to sidebar or repaint positions."
+ "notes": "### Fixed\n- Visible active-tab panes that finish while the outer terminal is unfocused are now marked as seen when you return to herdr, preventing stale done/attention indicators.\n- IME candidate windows and mobile SSH cursor tracking now stay anchored to the focused pane during client redraws, including apps that hide the cursor, instead of drifting to sidebar or repaint positions.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.4/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.4/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.4/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.4/herdr-macos-aarch64"
+ }
},
"0.5.3": {
- "notes": "### Added\n- Added named persistent sessions, so you can keep separate herdr environments for different projects or contexts while sharing the same global config. See the docs for the full session CLI. (#57, thanks @fbettag)\n- Added `herdr status`, `herdr status server`, and `herdr status client` to inspect the local client, running server, protocol compatibility, socket path, and whether a restart is needed.\n\n### Changed\n- Focused panes can now still alert you through terminal notifications when the herdr terminal window is unfocused, so active work does not go quiet just because you switched to another app.\n\n### Fixed\n- Dragging pane split borders now works when the app inside the pane has mouse reporting enabled, including Claude Code no-flicker mode. (#61, thanks @EYH0602)\n- Pressing the prefix key twice now forwards a literal prefix key into the focused pane in client mode again.\n- `herdr integration install` and `herdr integration uninstall` now work without requiring a running herdr server.\n- Pane PTYs now keep their last attached size while detached, preventing detached output from being resized or rewrapped to fallback dimensions."
+ "notes": "### Added\n- Added named persistent sessions, so you can keep separate herdr environments for different projects or contexts while sharing the same global config. See the docs for the full session CLI. (#57, thanks @fbettag)\n- Added `herdr status`, `herdr status server`, and `herdr status client` to inspect the local client, running server, protocol compatibility, socket path, and whether a restart is needed.\n\n### Changed\n- Focused panes can now still alert you through terminal notifications when the herdr terminal window is unfocused, so active work does not go quiet just because you switched to another app.\n\n### Fixed\n- Dragging pane split borders now works when the app inside the pane has mouse reporting enabled, including Claude Code no-flicker mode. (#61, thanks @EYH0602)\n- Pressing the prefix key twice now forwards a literal prefix key into the focused pane in client mode again.\n- `herdr integration install` and `herdr integration uninstall` now work without requiring a running herdr server.\n- Pane PTYs now keep their last attached size while detached, preventing detached output from being resized or rewrapped to fallback dimensions.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.3/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.3/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.3/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.3/herdr-macos-aarch64"
+ }
},
"0.5.2": {
- "notes": "### Added\n- Config can now be reloaded in the running app/server from the global menu or with `herdr server reload-config`, applying safe live settings without restarting the persistent server.\n\n### Fixed\n- Persistent server startup now surfaces config diagnostics in attached clients instead of silently hiding parse or validation errors.\n- Pane backgrounds now stay transparent when the host terminal background color is unknown, while explicit terminal cell backgrounds still render correctly.\n- Persistent-session toast and sound notifications now target the foreground attached client instead of firing across every connected client.\n- Claude Code subagent hook events no longer make the parent Claude pane look idle or released when a subagent finishes, and permissioned tool-call completion keeps the pane in the correct working state."
+ "notes": "### Added\n- Config can now be reloaded in the running app/server from the global menu or with `herdr server reload-config`, applying safe live settings without restarting the persistent server.\n\n### Fixed\n- Persistent server startup now surfaces config diagnostics in attached clients instead of silently hiding parse or validation errors.\n- Pane backgrounds now stay transparent when the host terminal background color is unknown, while explicit terminal cell backgrounds still render correctly.\n- Persistent-session toast and sound notifications now target the foreground attached client instead of firing across every connected client.\n- Claude Code subagent hook events no longer make the parent Claude pane look idle or released when a subagent finishes, and permissioned tool-call completion keeps the pane in the correct working state.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.2/herdr-macos-aarch64"
+ }
},
"0.5.1": {
- "notes": "### Added\n- Toast notifications can now be delivered through the outer terminal as desktop notifications. Configure this with `ui.toast.delivery = \"terminal\"`; see the [configuration docs](https://herdr.dev/docs/configuration/) for details.\n- Herdr now writes separate capped support logs for app, client, and server modes, making persistent-session issue reports easier to diagnose without unbounded log growth.\n- The bundled opencode plugin now reports question prompts as blocked while waiting for user input, then returns to working or idle when answered or dismissed. Question prompts are also detected by the default terminal-screen heuristics. (#51, thanks @mspiegel31)\n\n### Changed\n- Routine API request traces now log at debug level by default, making normal support logs smaller and easier to read while preserving detailed traces when debug logging is enabled.\n\n### Fixed\n- Pasted text and other reverse-video terminal content now stays readable when pane backgrounds are transparent. (#45, thanks @EYH0602)\n- Panes now advertise a stable `TERM=xterm-256color` and `COLORTERM=truecolor` by default, improving redraw and cursor behavior in shells and remote sessions.\n- Pane scrollbars once again reserve their own rightmost column instead of overlaying terminal content in persistent session mode.\n- Terminal-delivered toast notifications now use the server-approved delivery decision in persistent session mode, so attaching clients do not incorrectly suppress them.\n- In-app toast delivery now stays inside herdr instead of also forwarding a terminal/desktop notification."
+ "notes": "### Added\n- Toast notifications can now be delivered through the outer terminal as desktop notifications. Configure this with `ui.toast.delivery = \"terminal\"`; see the [configuration docs](https://herdr.dev/docs/configuration/) for details.\n- Herdr now writes separate capped support logs for app, client, and server modes, making persistent-session issue reports easier to diagnose without unbounded log growth.\n- The bundled opencode plugin now reports question prompts as blocked while waiting for user input, then returns to working or idle when answered or dismissed. Question prompts are also detected by the default terminal-screen heuristics. (#51, thanks @mspiegel31)\n\n### Changed\n- Routine API request traces now log at debug level by default, making normal support logs smaller and easier to read while preserving detailed traces when debug logging is enabled.\n\n### Fixed\n- Pasted text and other reverse-video terminal content now stays readable when pane backgrounds are transparent. (#45, thanks @EYH0602)\n- Panes now advertise a stable `TERM=xterm-256color` and `COLORTERM=truecolor` by default, improving redraw and cursor behavior in shells and remote sessions.\n- Pane scrollbars once again reserve their own rightmost column instead of overlaying terminal content in persistent session mode.\n- Terminal-delivered toast notifications now use the server-approved delivery decision in persistent session mode, so attaching clients do not incorrectly suppress them.\n- In-app toast delivery now stays inside herdr instead of also forwarding a terminal/desktop notification.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.1/herdr-macos-aarch64"
+ }
},
"0.5.0": {
- "notes": "### Breaking Changes Please Read\n- herdr now defaults to a persistent server/client session model. running `herdr` starts or reattaches to a background session server instead of launching the old single-process UI.\n- quitting the UI in default mode now detaches the current client and leaves the shared session running. use `herdr server stop` to stop the background server explicitly.\n- the old monolithic behavior is still available as an escape hatch with `herdr --no-session`.\n\n### Added\n- Persistent sessions are now the default product behavior. You can detach and reattach without stopping pane processes.\n- Added the thin client and headless server as first-class product components, including auto-detect launch, explicit `herdr client`, and `herdr server stop`.\n- Sessions now restore cleanly after full restart, preserving workspaces, tabs, panes, and running process state.\n- Multi-client attach is now supported. Multiple clients can connect to the same shared session.\n\n### Changed\n- In persistence mode, in-app quit actions now detach the current client by default instead of shutting down the whole background server.\n- The current persistence model is a shared session view across attached clients. It is not yet full tmux-style per-client independent navigation.\n- Restored sessions now land in terminal mode, while fresh sessions still start in navigate mode."
+ "notes": "### Breaking Changes Please Read\n- herdr now defaults to a persistent server/client session model. running `herdr` starts or reattaches to a background session server instead of launching the old single-process UI.\n- quitting the UI in default mode now detaches the current client and leaves the shared session running. use `herdr server stop` to stop the background server explicitly.\n- the old monolithic behavior is still available as an escape hatch with `herdr --no-session`.\n\n### Added\n- Persistent sessions are now the default product behavior. You can detach and reattach without stopping pane processes.\n- Added the thin client and headless server as first-class product components, including auto-detect launch, explicit `herdr client`, and `herdr server stop`.\n- Sessions now restore cleanly after full restart, preserving workspaces, tabs, panes, and running process state.\n- Multi-client attach is now supported. Multiple clients can connect to the same shared session.\n\n### Changed\n- In persistence mode, in-app quit actions now detach the current client by default instead of shutting down the whole background server.\n- The current persistence model is a shared session view across attached clients. It is not yet full tmux-style per-client independent navigation.\n- Restored sessions now land in terminal mode, while fresh sessions still start in navigate mode.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.5.0/herdr-macos-aarch64"
+ }
},
"0.4.11": {
- "notes": "### Breaking Changes Please Read\n- The update flow changes in `0.4.11`. Herdr no longer installs updates silently in the background. Starting with this release, herdr only checks for updates and shows them in the UI. To install a new release, quit herdr and then run `herdr update` manually in your shell.\n- This prepares the upcoming `0.5.0` persistence release. Herdr is moving from the old single-binary update model toward a persistent server/client session model, so your workspace can keep running while clients attach, detach, and reconnect.\n- The reason for this change is upgrade safety. Herdr needs to stop the old running process cleanly before the new client/server model takes over, so manual update avoids mixed-version states during the transition.\n\n### Added\n- Hook-reported agent state can now use custom agent labels, so integrations are no longer limited to herdr\u2019s built-in agent names. Custom labels now flow through pane/workspace UI and the socket API anywhere agent names are shown."
+ "notes": "### Breaking Changes Please Read\n- The update flow changes in `0.4.11`. Herdr no longer installs updates silently in the background. Starting with this release, herdr only checks for updates and shows them in the UI. To install a new release, quit herdr and then run `herdr update` manually in your shell.\n- This prepares the upcoming `0.5.0` persistence release. Herdr is moving from the old single-binary update model toward a persistent server/client session model, so your workspace can keep running while clients attach, detach, and reconnect.\n- The reason for this change is upgrade safety. Herdr needs to stop the old running process cleanly before the new client/server model takes over, so manual update avoids mixed-version states during the transition.\n\n### Added\n- Hook-reported agent state can now use custom agent labels, so integrations are no longer limited to herdr\u2019s built-in agent names. Custom labels now flow through pane/workspace UI and the socket API anywhere agent names are shown.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.11/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.11/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.11/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.11/herdr-macos-aarch64"
+ }
},
"0.4.10": {
- "notes": "### Added\n- Prefix mode now supports custom command keybindings via `[[keys.command]]`, so you can launch detached shell helpers or open temporary overlay panes from inside herdr using the active workspace, tab, pane, and cwd context.\n- Pressing the prefix key twice now forwards a literal prefix keystroke into the focused pane, which makes nested tools and terminal apps that use the same prefix easier to control.\n\n### Fixed\n- App-level key handling now normalizes enhanced keyboard reporting consistently, so shifted bindings and text like `?` and uppercase characters work correctly in navigate mode and text-entry UI.\n- Ctrl+letter input is now encoded correctly when pane apps enable kitty keyboard mode, improving compatibility with terminal programs that expect CSI-u style key reporting.\n- The collapsed sidebar now keeps the active workspace visibly highlighted even while you stay in terminal mode.\n- Droid Mission Control screens are now treated as idle instead of active work, reducing false busy-state detection."
+ "notes": "### Added\n- Prefix mode now supports custom command keybindings via `[[keys.command]]`, so you can launch detached shell helpers or open temporary overlay panes from inside herdr using the active workspace, tab, pane, and cwd context.\n- Pressing the prefix key twice now forwards a literal prefix keystroke into the focused pane, which makes nested tools and terminal apps that use the same prefix easier to control.\n\n### Fixed\n- App-level key handling now normalizes enhanced keyboard reporting consistently, so shifted bindings and text like `?` and uppercase characters work correctly in navigate mode and text-entry UI.\n- Ctrl+letter input is now encoded correctly when pane apps enable kitty keyboard mode, improving compatibility with terminal programs that expect CSI-u style key reporting.\n- The collapsed sidebar now keeps the active workspace visibly highlighted even while you stay in terminal mode.\n- Droid Mission Control screens are now treated as idle instead of active work, reducing false busy-state detection.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.10/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.10/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.10/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.10/herdr-macos-aarch64"
+ }
},
"0.4.9": {
- "notes": "### Fixed\n- Droid's primary-screen redraws no longer erase pane scrollback inside herdr, while normal scrollback-clear behavior is preserved elsewhere.\n- `q` is now dedicated to quitting in navigate mode instead of also acting as a generic cancel key in modals and overlays, reducing accidental quits.\n- Tab bar scrolling is tighter: the scroll-right button and new-tab button now sit directly adjacent to the last visible tab without a gap, and manual scroll no longer overscrolls past the last tab."
+ "notes": "### Fixed\n- Droid's primary-screen redraws no longer erase pane scrollback inside herdr, while normal scrollback-clear behavior is preserved elsewhere.\n- `q` is now dedicated to quitting in navigate mode instead of also acting as a generic cancel key in modals and overlays, reducing accidental quits.\n- Tab bar scrolling is tighter: the scroll-right button and new-tab button now sit directly adjacent to the last visible tab without a gap, and manual scroll no longer overscrolls past the last tab.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.9/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.9/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.9/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.9/herdr-macos-aarch64"
+ }
},
"0.4.8": {
- "notes": "### Added\n- Themes can now set `panel_bg = \"reset\"` to let herdr\u2019s panel chrome inherit the host terminal background instead of painting an opaque panel fill. This also accepts the aliases `default`, `none`, and `transparent`.\n- Ghostty-backed panes now preserve the host terminal\u2019s default background when it matches the outer terminal theme, so terminal window transparency can show through pane content instead of being repainted as an opaque color.\n\n### Fixed\n- Clipboard writes now prefer native platform clipboard tools (`pbcopy`, `wl-copy`, `xclip`, or `xsel`) before falling back to OSC 52, which makes copy operations from panes more reliable across terminal setups."
+ "notes": "### Added\n- Themes can now set `panel_bg = \"reset\"` to let herdr\u2019s panel chrome inherit the host terminal background instead of painting an opaque panel fill. This also accepts the aliases `default`, `none`, and `transparent`.\n- Ghostty-backed panes now preserve the host terminal\u2019s default background when it matches the outer terminal theme, so terminal window transparency can show through pane content instead of being repainted as an opaque color.\n\n### Fixed\n- Clipboard writes now prefer native platform clipboard tools (`pbcopy`, `wl-copy`, `xclip`, or `xsel`) before falling back to OSC 52, which makes copy operations from panes more reliable across terminal setups.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.8/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.8/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.8/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.8/herdr-macos-aarch64"
+ }
},
"0.4.7": {
- "notes": "### Added\n- The tab bar now handles large tab sets better: you can scroll overflowing tabs with the mouse controls or wheel, and reorder tabs by dragging them.\n- `workspace create` and `tab create` now return the created root pane in their JSON response, so automation can act on the new pane immediately without an extra lookup.\n\n### Fixed\n- Background panes that start idle no longer show up as `done` or trigger finished-state attention until they have actually transitioned from working or blocked to idle.\n- Left-click now focuses panes and right-click now opens the pane context menu even when the inner TUI has mouse reporting enabled, fixing apps like Claude Code. (#25, thanks @othavioquiliao)\n- OSC 52 clipboard writes from apps running inside panes now reach the host clipboard correctly, including copy requests emitted by child processes inside the pane.\n- `pane close` now removes only the targeted tab when other tabs still exist in the workspace, instead of closing the whole workspace.\n- Amp approval prompts are now detected more reliably as blocked, including tool-call, command, and file edit/create approval screens.\n\n### Breaking Changes\n- Socket API clients that match `result.type` exactly need to handle `workspace_created` and `tab_created` for `workspace.create` and `tab.create`; these calls no longer return `workspace_info` and `tab_info`."
+ "notes": "### Added\n- The tab bar now handles large tab sets better: you can scroll overflowing tabs with the mouse controls or wheel, and reorder tabs by dragging them.\n- `workspace create` and `tab create` now return the created root pane in their JSON response, so automation can act on the new pane immediately without an extra lookup.\n\n### Fixed\n- Background panes that start idle no longer show up as `done` or trigger finished-state attention until they have actually transitioned from working or blocked to idle.\n- Left-click now focuses panes and right-click now opens the pane context menu even when the inner TUI has mouse reporting enabled, fixing apps like Claude Code. (#25, thanks @othavioquiliao)\n- OSC 52 clipboard writes from apps running inside panes now reach the host clipboard correctly, including copy requests emitted by child processes inside the pane.\n- `pane close` now removes only the targeted tab when other tabs still exist in the workspace, instead of closing the whole workspace.\n- Amp approval prompts are now detected more reliably as blocked, including tool-call, command, and file edit/create approval screens.\n\n### Breaking Changes\n- Socket API clients that match `result.type` exactly need to handle `workspace_created` and `tab_created` for `workspace.create` and `tab.create`; these calls no longer return `workspace_info` and `tab_info`.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.7/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.7/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.7/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.7/herdr-macos-aarch64"
+ }
},
"0.4.6": {
- "notes": "### Fixed\n- Agent state detection is now more reliable when panes are scrolled back, when Codex is running in narrow panes, and when Claude opens slash-command or settings menus, reducing false blocked or idle states.\n- Mouse-driven terminal text selection now autoscrolls into pane scrollback and clears cleanly after copy, so selecting beyond the visible viewport works as expected.\n- Pane terminal colors now return to the outer terminal theme after fullscreen TUIs exit, fixing cases like Droid leaving stale background colors behind. This restore path now also works correctly on macOS."
+ "notes": "### Fixed\n- Agent state detection is now more reliable when panes are scrolled back, when Codex is running in narrow panes, and when Claude opens slash-command or settings menus, reducing false blocked or idle states.\n- Mouse-driven terminal text selection now autoscrolls into pane scrollback and clears cleanly after copy, so selecting beyond the visible viewport works as expected.\n- Pane terminal colors now return to the outer terminal theme after fullscreen TUIs exit, fixing cases like Droid leaving stale background colors behind. This restore path now also works correctly on macOS.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.6/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.6/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.6/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.6/herdr-macos-aarch64"
+ }
},
"0.4.5": {
- "notes": "### Added\n- `herdr workspace create` and `herdr tab create` now support `--label`, so scripts and agents can name new workspaces and tabs immediately instead of creating them first and renaming them afterward.\n- The global menu now includes a manual **reload keybinds** action, so you can apply `config.toml` keybinding changes without restarting herdr.\n- The socket API and CLI now expose a `done` agent status, including `herdr wait agent-status --status done`, so automation can distinguish finished agent runs from panes that are merely idle.\n\n### Changed\n- Session state is now saved automatically with a debounce while you work, so recent workspace, tab, pane, and sidebar changes are preserved more reliably even if herdr exits unexpectedly.\n\n### Fixed\n- Only the focused pane now owns the terminal cursor, which removes stray cursor blocks from unfocused panes.\n- In-app **What's New** / release notes now render inline code spans and fenced code blocks correctly.\n- Default numbered tabs now stay auto-named when you keep or rename them back to their numeric label, so generated tab numbering stays compact and predictable."
+ "notes": "### Added\n- `herdr workspace create` and `herdr tab create` now support `--label`, so scripts and agents can name new workspaces and tabs immediately instead of creating them first and renaming them afterward.\n- The global menu now includes a manual **reload keybinds** action, so you can apply `config.toml` keybinding changes without restarting herdr.\n- The socket API and CLI now expose a `done` agent status, including `herdr wait agent-status --status done`, so automation can distinguish finished agent runs from panes that are merely idle.\n\n### Changed\n- Session state is now saved automatically with a debounce while you work, so recent workspace, tab, pane, and sidebar changes are preserved more reliably even if herdr exits unexpectedly.\n\n### Fixed\n- Only the focused pane now owns the terminal cursor, which removes stray cursor blocks from unfocused panes.\n- In-app **What's New** / release notes now render inline code spans and fenced code blocks correctly.\n- Default numbered tabs now stay auto-named when you keep or rename them back to their numeric label, so generated tab numbering stays compact and predictable.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.5/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.5/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.5/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.5/herdr-macos-aarch64"
+ }
},
"0.4.4": {
- "notes": "### Changed\n- The expanded sidebar can now be split into resizable workspace and agent sections with a draggable divider, and that section sizing is preserved across restarts.\n\n### Fixed\n- IME input now works properly for Chinese and other UTF-8 input methods in pane terminals, so candidate selection no longer falls back to typing raw digit keys. (#9, thanks @Edmund-a7)\n- `herdr pane run ...` now uses the bracketed-paste-aware input path, improving compatibility with shells and terminal apps that expect pasted command text to arrive atomically.\n- The local socket API is more robust and secure: its Unix socket is now restricted to the current user, and long-running output waits and subscriptions stop cleanly on disconnect or shutdown instead of hanging indefinitely."
+ "notes": "### Changed\n- The expanded sidebar can now be split into resizable workspace and agent sections with a draggable divider, and that section sizing is preserved across restarts.\n\n### Fixed\n- IME input now works properly for Chinese and other UTF-8 input methods in pane terminals, so candidate selection no longer falls back to typing raw digit keys. (#9, thanks @Edmund-a7)\n- `herdr pane run ...` now uses the bracketed-paste-aware input path, improving compatibility with shells and terminal apps that expect pasted command text to arrive atomically.\n- The local socket API is more robust and secure: its Unix socket is now restricted to the current user, and long-running output waits and subscriptions stop cleanly on disconnect or shutdown instead of hanging indefinitely.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.4/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.4/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.4/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.4/herdr-macos-aarch64"
+ }
},
"0.4.3": {
- "notes": "### Fixed\n- Update checks and in-app **What's New** release notes no longer depend on GitHub\u2019s release API, which avoids the transient 403 failures from the previous update path.\n- `herdr pane run ...` now submits the full command atomically in one request, fixing cases where scripted commands did not reliably execute because the final Enter was sent separately.\n- Bare line-feed input is now preserved in raw terminal input instead of being normalized to Enter, fixing Linux terminal cases where inputs like Shift+Enter or Ctrl+J could be interpreted incorrectly."
+ "notes": "### Fixed\n- Update checks and in-app **What's New** release notes no longer depend on GitHub\u2019s release API, which avoids the transient 403 failures from the previous update path.\n- `herdr pane run ...` now submits the full command atomically in one request, fixing cases where scripted commands did not reliably execute because the final Enter was sent separately.\n- Bare line-feed input is now preserved in raw terminal input instead of being normalized to Enter, fixing Linux terminal cases where inputs like Shift+Enter or Ctrl+J could be interpreted incorrectly.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.3/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.3/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.3/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.3/herdr-macos-aarch64"
+ }
},
"0.4.2": {
- "notes": "### Added\n- The expanded sidebar agent panel can now switch between the current workspace and all workspaces, so you can scan and jump to agents across the whole session.\n- The collapsed sidebar now shows compact per-pane agent indicators, so you can keep an eye on agent activity without reopening the full sidebar.\n\n### Changed\n- The sidebar now handles larger workspace sets more cleanly: the workspace section has headers, its own scrolling, better-aligned drag/drop slots, and manual width changes persist across restarts. Double-clicking the divider resets it to the configured default width.\n- Pane scrollback is now configured with `advanced.scrollback_limit_bytes`, matching Ghostty's byte-based scrollback limit. Set it to `0` to disable pane scrollback entirely. The old `advanced.scrollback_lines` key is still accepted as an alias, but it now uses the same byte-based value.\n- Linux release binaries now ship with libghostty SIMD enabled again without reintroducing the musl startup issue, restoring the optimized Linux build path.\n\n### Fixed\n- Typing in pane terminals on macOS is responsive again after the Ghostty migration, by keeping a persistent per-pane Ghostty key encoder instead of rebuilding it on every keypress.\n- The collapsed sidebar expand toggle works again.\n- Creating a new tab now waits until you confirm the dialog, so cancelling the new-tab flow no longer leaves behind an unwanted tab.\n- Copying selected pane text now uses Ghostty's native selection extraction, which preserves wrapped text and wide characters more accurately.\n- Session restore is more tolerant of older and current snapshot formats, including pre-tab session files."
+ "notes": "### Added\n- The expanded sidebar agent panel can now switch between the current workspace and all workspaces, so you can scan and jump to agents across the whole session.\n- The collapsed sidebar now shows compact per-pane agent indicators, so you can keep an eye on agent activity without reopening the full sidebar.\n\n### Changed\n- The sidebar now handles larger workspace sets more cleanly: the workspace section has headers, its own scrolling, better-aligned drag/drop slots, and manual width changes persist across restarts. Double-clicking the divider resets it to the configured default width.\n- Pane scrollback is now configured with `advanced.scrollback_limit_bytes`, matching Ghostty's byte-based scrollback limit. Set it to `0` to disable pane scrollback entirely. The old `advanced.scrollback_lines` key is still accepted as an alias, but it now uses the same byte-based value.\n- Linux release binaries now ship with libghostty SIMD enabled again without reintroducing the musl startup issue, restoring the optimized Linux build path.\n\n### Fixed\n- Typing in pane terminals on macOS is responsive again after the Ghostty migration, by keeping a persistent per-pane Ghostty key encoder instead of rebuilding it on every keypress.\n- The collapsed sidebar expand toggle works again.\n- Creating a new tab now waits until you confirm the dialog, so cancelling the new-tab flow no longer leaves behind an unwanted tab.\n- Copying selected pane text now uses Ghostty's native selection extraction, which preserves wrapped text and wide characters more accurately.\n- Session restore is more tolerant of older and current snapshot formats, including pre-tab session files.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.2/herdr-macos-aarch64"
+ }
},
"0.4.1": {
- "notes": "### Fixed\n- Fixed Linux release binaries crashing on startup."
+ "notes": "### Fixed\n- Fixed Linux release binaries crashing on startup.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.1/herdr-macos-aarch64"
+ }
},
"0.4.0": {
- "notes": "### Major Changes\n- Herdr now uses a Ghostty-backed terminal engine as its pane runtime.\n- The legacy vt100 pane backend has been removed, making Ghostty the single terminal backend going forward.\n\n### UX and Interaction\n- Workspaces can now be reordered by dragging them in the sidebar.\n- Notification sounds now support custom mp3 file overrides, with either one shared file or separate files for finished vs needs-attention alerts.\n\n### API and Integration\n- Workspace API ids are now stable, making socket and CLI automation more predictable across workspace changes and restores.\n\n### Packaging and Runtime\n- macOS builds now statically link the vendored `libghostty-vt`, preserving the single-binary install and update flow."
+ "notes": "### Major Changes\n- Herdr now uses a Ghostty-backed terminal engine as its pane runtime.\n- The legacy vt100 pane backend has been removed, making Ghostty the single terminal backend going forward.\n\n### UX and Interaction\n- Workspaces can now be reordered by dragging them in the sidebar.\n- Notification sounds now support custom mp3 file overrides, with either one shared file or separate files for finished vs needs-attention alerts.\n\n### API and Integration\n- Workspace API ids are now stable, making socket and CLI automation more predictable across workspace changes and restores.\n\n### Packaging and Runtime\n- macOS builds now statically link the vendored `libghostty-vt`, preserving the single-binary install and update flow.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.4.0/herdr-macos-aarch64"
+ }
},
"0.3.2": {
- "notes": "### Changed\n- The global launcher now surfaces update-related actions more clearly: when release notes are available you can open **What's New**, and when an update has been downloaded you can **quit to apply update** directly from the menu.\n- Release notes are now retained as the latest available notes after you dismiss the startup modal, so you can reopen them later from the UI instead of only seeing them once.\n\n### Fixed\n- Fixed held-key repeat in terminal panes on macOS terminals that send explicit repeat events through the enhanced keyboard protocol, restoring continuous backspace, character, and arrow-key repeat without letting modal close/confirm key repeats leak into the shell."
+ "notes": "### Changed\n- The global launcher now surfaces update-related actions more clearly: when release notes are available you can open **What's New**, and when an update has been downloaded you can **quit to apply update** directly from the menu.\n- Release notes are now retained as the latest available notes after you dismiss the startup modal, so you can reopen them later from the UI instead of only seeing them once.\n\n### Fixed\n- Fixed held-key repeat in terminal panes on macOS terminals that send explicit repeat events through the enhanced keyboard protocol, restoring continuous backspace, character, and arrow-key repeat without letting modal close/confirm key repeats leak into the shell.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.2/herdr-macos-aarch64"
+ }
},
"0.3.1": {
- "notes": "### Added\n- New tabs now open directly into the rename flow, with the default tab name prefilled and replaced on first type so you can name tabs as you create them.\n\n### Changed\n- Polished modal layout and spacing across onboarding, settings, keybind help, and release notes so overlays feel more consistent and their content/actions line up more cleanly.\n- Debug builds now use separate runtime/config paths from normal releases, which avoids local development sessions colliding with your main herdr install.\n\n### Fixed\n- Starting a second herdr instance against an active socket now fails fast with a clear error instead of clobbering the running session.\n- Fixed pane and agent state updates being dropped under internal event queue pressure, which could leave a pane showing stale status after work finished.\n- Fixed onboarding modal sizing and click targets, and corrected release-notes scroll calculations when a scrollbar is present."
+ "notes": "### Added\n- New tabs now open directly into the rename flow, with the default tab name prefilled and replaced on first type so you can name tabs as you create them.\n\n### Changed\n- Polished modal layout and spacing across onboarding, settings, keybind help, and release notes so overlays feel more consistent and their content/actions line up more cleanly.\n- Debug builds now use separate runtime/config paths from normal releases, which avoids local development sessions colliding with your main herdr install.\n\n### Fixed\n- Starting a second herdr instance against an active socket now fails fast with a clear error instead of clobbering the running session.\n- Fixed pane and agent state updates being dropped under internal event queue pressure, which could leave a pane showing stale status after work finished.\n- Fixed onboarding modal sizing and click targets, and corrected release-notes scroll calculations when a scrollbar is present.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.1/herdr-macos-aarch64"
+ }
},
"0.3.0": {
- "notes": "### Major Changes\n- Added tabs within workspaces, so a single workspace can now hold multiple terminal tab contexts with their own pane layouts.\n- Added first-class tab support to the local socket API and CLI wrappers, including `herdr tab ...` commands and tab ids like `1:2` alongside workspace-scoped pane ids.\n- Added built-in direct integrations for pi, claude code, codex, and opencode, plus authoritative hook-driven state reporting so supported agents can report semantic state directly instead of relying only on screen heuristics.\n- Added a post-update release-notes screen so herdr can explain what changed after an update is installed.\n\n### UX and Controls\n- Added optional direct pane-focus keybindings for terminal mode, so you can switch panes with modifier shortcuts like `alt+h` or `alt+right` without entering navigate mode first.\n- Reworked keybind discoverability so the in-app keybind help now shows all supported actions, including optional bindings that are currently unset.\n- Keybind help now uses a centered scrollable modal with mouse and keyboard scrolling, matching the release-notes interaction model more closely.\n- Popups and action-button interactions now use more consistent modal geometry and button semantics across the UI.\n- Polished the sidebar agent section so it focuses on detected agents only and uses clearer two-line agent cards with more breathing room.\n\n### Behavior Fixes\n- Hook-driven agent state updates now stay correct in tabbed workspaces.\n- Modifier-only keypresses no longer leak into panes as stray input.\n- Multi-tab agent labels now include tab names when that extra context matters.\n- Workspace identity now follows the first tab's root pane again instead of stale creation-time cwd.\n- Background notification suppression is now tab-aware rather than workspace-wide, so background tabs in the current workspace can still alert correctly.\n\n### Documentation\n- Updated the README, configuration guide, integrations guide, skill, and socket API docs to reflect tabs, direct integrations, unset optional keybindings, direct terminal-mode navigation examples, workspace-scoped pane ids, and the current workspace identity/sidebar model."
+ "notes": "### Major Changes\n- Added tabs within workspaces, so a single workspace can now hold multiple terminal tab contexts with their own pane layouts.\n- Added first-class tab support to the local socket API and CLI wrappers, including `herdr tab ...` commands and tab ids like `1:2` alongside workspace-scoped pane ids.\n- Added built-in direct integrations for pi, claude code, codex, and opencode, plus authoritative hook-driven state reporting so supported agents can report semantic state directly instead of relying only on screen heuristics.\n- Added a post-update release-notes screen so herdr can explain what changed after an update is installed.\n\n### UX and Controls\n- Added optional direct pane-focus keybindings for terminal mode, so you can switch panes with modifier shortcuts like `alt+h` or `alt+right` without entering navigate mode first.\n- Reworked keybind discoverability so the in-app keybind help now shows all supported actions, including optional bindings that are currently unset.\n- Keybind help now uses a centered scrollable modal with mouse and keyboard scrolling, matching the release-notes interaction model more closely.\n- Popups and action-button interactions now use more consistent modal geometry and button semantics across the UI.\n- Polished the sidebar agent section so it focuses on detected agents only and uses clearer two-line agent cards with more breathing room.\n\n### Behavior Fixes\n- Hook-driven agent state updates now stay correct in tabbed workspaces.\n- Modifier-only keypresses no longer leak into panes as stray input.\n- Multi-tab agent labels now include tab names when that extra context matters.\n- Workspace identity now follows the first tab's root pane again instead of stale creation-time cwd.\n- Background notification suppression is now tab-aware rather than workspace-wide, so background tabs in the current workspace can still alert correctly.\n\n### Documentation\n- Updated the README, configuration guide, integrations guide, skill, and socket API docs to reflect tabs, direct integrations, unset optional keybindings, direct terminal-mode navigation examples, workspace-scoped pane ids, and the current workspace identity/sidebar model.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.3.0/herdr-macos-aarch64"
+ }
},
"0.2.4": {
- "notes": "### Fixed\n- Fixed a macOS-only startup misdetection where pi could briefly appear as codex in the sidebar because process environment entries were being parsed as command-line arguments."
+ "notes": "### Fixed\n- Fixed a macOS-only startup misdetection where pi could briefly appear as codex in the sidebar because process environment entries were being parsed as command-line arguments.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.4/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.4/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.4/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.4/herdr-macos-aarch64"
+ }
},
"0.2.3": {
- "notes": "### Changed\n- Mouse wheel handling now follows the tmux/Ghostty model more closely: fullscreen apps receive wheel input when they own scrolling, while herdr keeps host scrollback for panes that are behaving like a normal terminal transcript.\n- Pane scrollbars now only appear when herdr has real host scrollback for that pane, instead of implying a host-managed scroll position for app-owned scrolling.\n\n### Fixed\n- Fixed Codex and pi panes becoming unscrollable in herdr by preserving recoverable host history for top-anchored normal-screen output, without relying on alternate-screen scrollback retention.\n- Fixed pane wheel routing so apps using mouse reporting or alternate-scroll behavior can receive scroll input directly instead of having herdr always intercept it."
+ "notes": "### Changed\n- Mouse wheel handling now follows the tmux/Ghostty model more closely: fullscreen apps receive wheel input when they own scrolling, while herdr keeps host scrollback for panes that are behaving like a normal terminal transcript.\n- Pane scrollbars now only appear when herdr has real host scrollback for that pane, instead of implying a host-managed scroll position for app-owned scrolling.\n\n### Fixed\n- Fixed Codex and pi panes becoming unscrollable in herdr by preserving recoverable host history for top-anchored normal-screen output, without relying on alternate-screen scrollback retention.\n- Fixed pane wheel routing so apps using mouse reporting or alternate-scroll behavior can receive scroll input directly instead of having herdr always intercept it.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.3/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.3/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.3/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.3/herdr-macos-aarch64"
+ }
},
"0.2.2": {
- "notes": "### Fixed\n- Fixed pane scrollbars so they reserve their own lane instead of drawing over terminal content, which makes scrolling and scrollbar dragging behave more cleanly in narrow panes.\n- Fixed alternate-screen scrollback handling so full-screen terminal apps can preserve recoverable history inside herdr panes instead of losing rows that scroll off.\n- Fixed Codex in herdr panes losing transcript/history while running in alternate screen, so past output remains scrollable instead of disappearing as the session grows.\n- Hid the rendered terminal cursor while a pane is scrolled back, avoiding stray cursor blocks appearing in the wrong place during history navigation."
+ "notes": "### Fixed\n- Fixed pane scrollbars so they reserve their own lane instead of drawing over terminal content, which makes scrolling and scrollbar dragging behave more cleanly in narrow panes.\n- Fixed alternate-screen scrollback handling so full-screen terminal apps can preserve recoverable history inside herdr panes instead of losing rows that scroll off.\n- Fixed Codex in herdr panes losing transcript/history while running in alternate screen, so past output remains scrollable instead of disappearing as the session grows.\n- Hid the rendered terminal cursor while a pane is scrolled back, avoiding stray cursor blocks appearing in the wrong place during history navigation.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.2/herdr-macos-aarch64"
+ }
},
"0.2.1": {
- "notes": "### Added\n- Herdr now checks for updates at startup and periodically while it stays open, so long-running sessions can still discover new releases without a restart cycle.\n- Added a lightweight bottom-right toast when an update has been downloaded and is ready, with a simple restart-to-use-it flow.\n\n### Changed\n- Rendering is now driven more directly by app events instead of relying as much on polling, which makes the UI feel snappier and cuts unnecessary redraw work.\n\n### Fixed\n- Restored smooth fast spinner animation for working agents.\n- Closing a pane or workspace now reliably terminates the processes running inside that pane session instead of leaving shells or child processes behind.\n- Fixed bracketed paste handling so incomplete paste sequences are preserved across read timeouts instead of being dropped or misread."
+ "notes": "### Added\n- Herdr now checks for updates at startup and periodically while it stays open, so long-running sessions can still discover new releases without a restart cycle.\n- Added a lightweight bottom-right toast when an update has been downloaded and is ready, with a simple restart-to-use-it flow.\n\n### Changed\n- Rendering is now driven more directly by app events instead of relying as much on polling, which makes the UI feel snappier and cuts unnecessary redraw work.\n\n### Fixed\n- Restored smooth fast spinner animation for working agents.\n- Closing a pane or workspace now reliably terminates the processes running inside that pane session instead of leaving shells or child processes behind.\n- Fixed bracketed paste handling so incomplete paste sequences are preserved across read timeouts instead of being dropped or misread.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.1/herdr-macos-aarch64"
+ }
},
"0.2.0": {
- "notes": "### Added\n- Added a local Unix socket API for controlling running herdr sessions, including workspace and pane management, pane reads, text/key input, pane splitting, and output waits.\n- Added event subscriptions over the socket API for workspace and pane lifecycle events, pane output matches, and agent state changes.\n- Added CLI wrappers on top of the socket API with `herdr workspace ...`, `herdr pane ...`, and `herdr wait ...`, using compact public ids like `1` and `1-2` for scripting and agent orchestration.\n- Added a settings popup with mouse support for changing themes, sound alerts, and toast notifications from inside herdr.\n- Added 9 built-in themes: catppuccin, tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, and ros\u00e9 pine.\n- Added interactive pane scrollbars, manual sidebar resizing, and upstream git ahead/behind indicators in the workspace sidebar.\n\n### Changed\n- Redesigned the sidebar into a two-section layout that separates workspace-level triage from per-agent detail, making it easier to supervise multiple agents in parallel.\n- Agent state names exposed in the UI and integration surfaces now use `working` and `blocked`.\n- Herdr now blocks nested launches by default when started inside a herdr-managed pane; set `advanced.allow_nested = true` to opt back in.\n\n### Fixed\n- Improved terminal keyboard protocol parsing and input forwarding across terminal variants, including better handling for shifted printable keys.\n- Fixed Ghostty on macOS misparsing some arrow-key and modifier/enhanced key sequences.\n- Refined sidebar rollups and pane ordering so workspace status and agent lists stay more stable and predictable.\n\n### Documentation\n- Refreshed the README, socket API reference, and reusable agent skill docs to better explain herdr's agent multiplexer model and integration surface."
+ "notes": "### Added\n- Added a local Unix socket API for controlling running herdr sessions, including workspace and pane management, pane reads, text/key input, pane splitting, and output waits.\n- Added event subscriptions over the socket API for workspace and pane lifecycle events, pane output matches, and agent state changes.\n- Added CLI wrappers on top of the socket API with `herdr workspace ...`, `herdr pane ...`, and `herdr wait ...`, using compact public ids like `1` and `1-2` for scripting and agent orchestration.\n- Added a settings popup with mouse support for changing themes, sound alerts, and toast notifications from inside herdr.\n- Added 9 built-in themes: catppuccin, tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, and ros\u00e9 pine.\n- Added interactive pane scrollbars, manual sidebar resizing, and upstream git ahead/behind indicators in the workspace sidebar.\n\n### Changed\n- Redesigned the sidebar into a two-section layout that separates workspace-level triage from per-agent detail, making it easier to supervise multiple agents in parallel.\n- Agent state names exposed in the UI and integration surfaces now use `working` and `blocked`.\n- Herdr now blocks nested launches by default when started inside a herdr-managed pane; set `advanced.allow_nested = true` to opt back in.\n\n### Fixed\n- Improved terminal keyboard protocol parsing and input forwarding across terminal variants, including better handling for shifted printable keys.\n- Fixed Ghostty on macOS misparsing some arrow-key and modifier/enhanced key sequences.\n- Refined sidebar rollups and pane ordering so workspace status and agent lists stay more stable and predictable.\n\n### Documentation\n- Refreshed the README, socket API reference, and reusable agent skill docs to better explain herdr's agent multiplexer model and integration surface.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.2.0/herdr-macos-aarch64"
+ }
},
"0.1.2": {
- "notes": "### Added\n- Added first-run onboarding flow that lets you choose notification preferences (sound and toast) on startup.\n- Added optional visual toast notifications in the top-right corner for background workspace events (completion and attention-needed alerts).\n- Added configurable keybindings for all navigate mode actions: new workspace, rename workspace, close workspace, resize mode, and toggle sidebar. See the [configuration docs](https://herdr.dev/docs/configuration/) for the full key reference.\n- Added configuration validation with startup diagnostics. Invalid key combinations or duplicate bindings now fall back to safe defaults with a visible warning.\n\n### Changed\n- **Breaking:** Default prefix key changed from `ctrl+s` to `ctrl+b` to avoid common terminal flow control conflicts.\n- Workspaces now derive their identity from the repository or folder of their root pane, updating automatically as you navigate. Custom names act as overrides rather than static labels.\n- Sidebar now shows workspace numbers again in expanded view.\n- Refined sidebar presentation with consistent marker/name/state ordering and comma-separated agent summaries.\n- Keybinding parser now accepts special keys (`enter`, `esc`, `tab`, `backspace`, `space`) and function keys (`f1`\u2013`f12`).\n\n### Documentation\n- Split configuration reference into dedicated configuration docs with full keybinding documentation and config diagnostics explanation."
+ "notes": "### Added\n- Added first-run onboarding flow that lets you choose notification preferences (sound and toast) on startup.\n- Added optional visual toast notifications in the top-right corner for background workspace events (completion and attention-needed alerts).\n- Added configurable keybindings for all navigate mode actions: new workspace, rename workspace, close workspace, resize mode, and toggle sidebar. See the [configuration docs](https://herdr.dev/docs/configuration/) for the full key reference.\n- Added configuration validation with startup diagnostics. Invalid key combinations or duplicate bindings now fall back to safe defaults with a visible warning.\n\n### Changed\n- **Breaking:** Default prefix key changed from `ctrl+s` to `ctrl+b` to avoid common terminal flow control conflicts.\n- Workspaces now derive their identity from the repository or folder of their root pane, updating automatically as you navigate. Custom names act as overrides rather than static labels.\n- Sidebar now shows workspace numbers again in expanded view.\n- Refined sidebar presentation with consistent marker/name/state ordering and comma-separated agent summaries.\n- Keybinding parser now accepts special keys (`enter`, `esc`, `tab`, `backspace`, `space`) and function keys (`f1`\u2013`f12`).\n\n### Documentation\n- Split configuration reference into dedicated configuration docs with full keybinding documentation and config diagnostics explanation.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.2/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.2/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.2/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.2/herdr-macos-aarch64"
+ }
},
"0.1.1": {
- "notes": "### Added\n- Added optional sound notifications for agent state changes, including a completion chime when background work finishes and an alert when an agent needs input.\n- Added per-agent sound overrides under `[ui.sound.agents]`, so you can mute or enable notifications by agent instead of using one global setting. Droid notifications are muted by default.\n\n### Changed\n- Request alerts now play even when the agent is in the active workspace, while completion sounds remain limited to background workspaces.\n\n### Fixed\n- Improved foreground job detection on Linux and macOS so herdr can recognize agents that run through wrapper processes or generic runtimes, including cases like Codex running under `node`.\n- Made Claude Code state detection more stable by handling more spinner variants and smoothing short busy/idle flicker during screen updates."
+ "notes": "### Added\n- Added optional sound notifications for agent state changes, including a completion chime when background work finishes and an alert when an agent needs input.\n- Added per-agent sound overrides under `[ui.sound.agents]`, so you can mute or enable notifications by agent instead of using one global setting. Droid notifications are muted by default.\n\n### Changed\n- Request alerts now play even when the agent is in the active workspace, while completion sounds remain limited to background workspaces.\n\n### Fixed\n- Improved foreground job detection on Linux and macOS so herdr can recognize agents that run through wrapper processes or generic runtimes, including cases like Codex running under `node`.\n- Made Claude Code state detection more stable by handling more spinner variants and smoothing short busy/idle flicker during screen updates.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.1/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.1/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.1/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.1/herdr-macos-aarch64"
+ }
},
"0.1.0": {
- "notes": "### Added\n- Initial release."
+ "notes": "### Added\n- Initial release.",
+ "assets": {
+ "linux-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.0/herdr-linux-x86_64",
+ "linux-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.0/herdr-linux-aarch64",
+ "macos-x86_64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.0/herdr-macos-x86_64",
+ "macos-aarch64": "https://github.com/ogulcancelik/herdr/releases/download/v0.1.0/herdr-macos-aarch64"
+ }
}
}
}