Skip to content

feat(install): set Ovis up on herdr-core where there is no herdr - #2688

Merged
devswha merged 5 commits into
mainfrom
feat/hc-native-install
Nov 4, 2026
Merged

devswha merged 5 commits into
mainfrom
feat/hc-native-install

Conversation

@devswha

@devswha devswha commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

On a Linux or macOS PC that has herdr-core (hc) and no herdr, curl -fsSL https://ovis.sh/install.sh | sh used to install herdr's TUI and the herdr plugin anyway, and then stop at "herdr is not running ... Run: herdr". It now sets Ovis up on herdr-core instead:

  • Runtime pick: OVIS_RUNTIME (herdr / herdr-core) when set. Otherwise herdr-core when an earlier run installed Ovis on it, or when there is no herdr and an hc answers --version with hc <version>. Otherwise herdr, installed when missing, as before. Only --version is run (any other hc command starts a core), within a 5 s bound. Candidates follow the server's own search: OVIS_HC_BIN, the PATH, ~/.local/bin, Homebrew, /usr/local/bin, mise, Nix, cargo, with herdr-core before hc in each. --version must exit 0.
  • No herdr, no plugin: Bun only. Ovis is cloned at the release tag (--depth 1, then a local main branch at that commit so Settings → Updates accepts the checkout) into ~/.local/share/ovis/app.new, built with the same steps as herdr-plugin.toml's Linux/macOS [[build]] (preflight, bun install, bun run build; the Rust PTY host is skipped because herdr-core's terminals don't use it), and moved to ~/.local/share/ovis/app only once built. A rerun keeps that checkout. Settings → Updates keeps it current through the managed launcher, as it does for the plugin. I checked the updater's tag fetch, unshallow fetch and ancestry check on a shallow tag clone.
  • Settings: ~/.config/ovis/env, owner-only, gets OVIS_RUNTIME=herdr-core (replacing any other runtime named in env or .env). It also gets the hc found, as OVIS_HC_BIN (released servers run only that or hc on the PATH), and HC_SESSION/HC_SOCKET when the installer ran with them. The service and the installer's start pass HERDR_PLUGIN_CONFIG_DIR/HERDR_PLUGIN_STATE_DIR for this folder and ~/.local/state/ovis, so a herdr plugin's config found later is never read in its place. Where the herdr plugin already runs Ovis, OVIS_RUNTIME=herdr-core is refused with a pointer to the plugin's own settings.
  • Start and service: Ovis is started with bun <app>/scripts/plugin.ts start, the managed launcher the plugin uses too, so telemetry reports install_method: managed. Its start, stop and status work the same. It is registered as a user service that starts it at login:
    • Linux: ~/.config/systemd/user/ovis.service (oneshot + RemainAfterExit; ExecStop runs plugin.ts stop), systemctl --user enable --now. When linger is off, it prints the loginctl enable-linger hint.
    • macOS: the sh.ovis.server LaunchAgent (RunAtLoad, AbandonProcessGroup), loaded with launchctl bootstrap.
    • With no user systemd (containers, some WSL), it starts Ovis once and prints the command to start it again.
  • Windows: install.ps1 keeps herdr. When it finds herdr-core, it says Ovis runs on herdr-core on Linux and macOS only for now.
  • Docs: INSTALL.md (method C, uninstall) and the guide's "Herdr app terminals" section. Changelog fragment added.

Note on #2667: that PR picks the runtime from facts and offers a Settings switch, and OVIS_RUNTIME locks that switch. This installer writes OVIS_RUNTIME=herdr-core because today's server only serves herdr-core when it is set. Once #2667 is merged, the env line can be dropped in favor of its detection; I'll follow up if this lands first. No #2667 file is touched here.

Validation

  • Before: clean ubuntu:24.04 container with only hc 0.1.17 (from releases.herdr.dev/core/install.sh). main's install.sh installed herdr 0.9.5 and the plugin v0.4.22, and the app was not running.
  • After, same container: no herdr installed, Ovis v0.4.22 in ~/.local/share/ovis/app, /api/health answers "runtime":"herdr-core", and GET /api/telemetry shows install_method: "managed". A second run says "already installed" and keeps the running server.
  • After, in a systemd container (linger on): ovis.service enabled and active (exited) with the server processes in its cgroup. systemctl --user restart ovis brings it back. After a container restart, Ovis answers again within 2 s. systemctl --user stop ovis ends it.
  • scripts/install-herdr-core.test.ts (new, 24 tests): runtime pick, hc probing (another program named hc, a hung one, a failing one, OVIS_HC_BIN, a saved one, cargo), the env file (mode 0600, idempotent, an existing runtime kept, the pre-rename dir), the systemd unit and LaunchAgent with stand-in tools, and the build steps matching herdr-plugin.toml.
  • sh -n / dash -n pass. shellcheck (koalaman/shellcheck:stable) reports only info-level SC2030/SC2031 PATH notes, the same kind as on main.
  • bun run check fast: passed at 868ae08: workflow syntax, generated types/themes fresh, typecheck, build, unit tests (10915 pass, 0 fail, 42 skip). Earlier runs on this busy host failed in unrelated files from /tmp running out of inodes (ENOSPC); those files passed when rerun alone.
  • Not run here: macOS (the LaunchAgent path is covered only by the stand-in test above) and the Windows CI job.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 30 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between e96b369 and 4fcfc7c.

Files selected for processing: 7
  • INSTALL.md
  • changelog.d/install-on-herdr-core.md
  • docs/guide.md
  • install.ps1
  • install.sh
  • scripts/conventions.test.ts
  • scripts/install-herdr-core.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@devswha

devswha commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Review round 1 (omo reviewer + Codex) on ea507df, fixed in bbd6b7c:

Fixed

  • HIGH (reproduced): Settings → Updates was blocked. A detached tag clone without HERDR_PLUGIN_ROOT hit sourceBlock ("Switch the source checkout to main to update."). The checkout is now on a local main branch at the release commit, which released servers (v0.4.22 included) accept. In an hc-only container, /api/updates now shows blocked_reason: null and the check goes on to fetch tags. Separately, I checked the updater's tag fetch, unshallow fetch and ancestry check on a shallow tag clone.
  • HIGH/MEDIUM (reproduced): the settings could come from somewhere else. plugin.ts prefers a herdr plugin's config dir when one has an env file. The service and the installer's own start now pass HERDR_PLUGIN_CONFIG_DIR=~/.config/ovis and HERDR_PLUGIN_STATE_DIR=~/.local/state/ovis. An OVIS_RUNTIME naming another runtime in either env file is replaced, and the installer says so. With OVIS_RUNTIME=herdr-core on a PC where the herdr plugin already runs Ovis, it now refuses and points to the plugin's own settings, instead of adding a second Ovis.
  • MEDIUM (confirmed in code): v0.4.22's server runs only OVIS_HC_BIN or hc on the PATH. The hc the installer found is now written as OVIS_HC_BIN, unless a file already names one. The container run shows the server running ~/.local/bin/herdr-core connect.
  • MEDIUM: hc discovery. It now tries OVIS_HC_BIN, the PATH, ~/.local/bin, Homebrew, /usr/local/bin, mise shims, Nix and cargo, herdr-core before hc in each, and requires --version to exit 0.
  • MEDIUM: HC_SESSION / HC_SOCKET from the installing shell are kept in the settings file.
  • MEDIUM: an earlier herdr-core install stays on herdr-core on a rerun. When hc does not answer, the installer fails with a message instead of installing herdr.
  • MEDIUM: a non-checkout ~/.local/share/ovis/app is refused up front instead of having the new build moved inside it.
  • LOW: escaping. Plist values are XML-escaped. Unit values escape \ and ", double %, and double $ on Exec lines. Tested with a PATH containing %, quotes, a backslash, & and $.

Not changed

  • If the app fails to start, the installer prints why and exits 0, as the plugin path does when its start times out.

Validation after the fixes

  • hc-only container: install, /api/health runtime: herdr-core, install_method: managed, settings file 0600 with OVIS_RUNTIME and OVIS_HC_BIN, rerun.
  • systemd container: unit enabled and active, restart, reboot autostart in 2 s, stop.
  • scripts/install-herdr-core.test.ts: 22 pass. shellcheck: no findings beyond the info-level PATH notes that main has too.
  • CodeRabbit is rate-limited on this PR ("Review limit reached"), so no CodeRabbit review ran on either head.

@devswha

devswha commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Review round 2 (omo reviewer + Codex) on bbd6b7c: neither reviewer found a HIGH. The cheap MEDIUM/LOW items are fixed in this push:

  • Stale OVIS_HC_BIN (MEDIUM, reproduced by omo): the installer now owns that line like OVIS_RUNTIME. Each run drops any OVIS_HC_BIN from env/.env and writes the hc that find_core just validated. find_core tries the saved value right after an explicit OVIS_HC_BIN, so a rerun still finds an hc outside the PATH, and a saved path that no longer works is passed over.
  • Phone setup / open_app read other settings (MEDIUM): install_core exports HERDR_PLUGIN_CONFIG_DIR/HERDR_PLUGIN_STATE_DIR, so every plugin.ts call in the run (start, phone, status) reads what the service reads.
  • Settings rewrite was not atomic (MEDIUM): it now writes a cp -p copy and mvs it over the original, keeping the file's mode.
  • Newline in PATH (LOW): refused before any unit is written.
  • Pre-rename runtime key (LOW, reproduced by omo): HERDR_WEB_RUNTIME/HERDR_WEB_HC_BIN are removed along with the new names. The test file that checks this is listed in CARRY_OVER.

Left as notes, not changed: the service does not carry the installing shell's XDG_CONFIG_HOME/XDG_STATE_HOME/XDG_RUNTIME_DIR (LOW, unreproduced; a custom hc session is kept through HC_SESSION/HC_SOCKET). If the app fails to start, the installer exits 0 after saying why, as the plugin path does.

Validation at this head: scripts/install-herdr-core.test.ts 24 pass. Re-ran both containers: in the hc-only one, install, rerun, runtime: herdr-core, install_method: managed, OVIS_HC_BIN recorded, /api/updates blocked_reason: null. In the systemd one: enabled/active, restart, reboot autostart in 2 s, stop. shellcheck: nothing beyond main's info notes. bun run check fast: passed (10915 pass, 0 fail). CodeRabbit is still rate-limited on this PR, so no CodeRabbit review ran.

@devswha

devswha commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Review round 3 (omo reviewer) at 868ae08: CLEAR, no HIGH or MEDIUM. Its LOW notes are left as follow-ups rather than another push:

  • A relative OVIS_HC_BIN (e.g. ./hc) is saved as written, but the server runs from the app folder. It could be made absolute before saving.
  • command -v hc tries only the first hc on the PATH. The server tries every PATH folder. When that first hc is another program, the installer falls back to herdr, as main does today.
  • The settings rewrite treats a grep I/O error like "no lines matched". This needs a disk error to happen.
  • OVIS_REF set to a release older than herdr-core support would be cloned for a herdr-core install. OVIS_REF is a testing option.
  • A rerun on an existing herdr-core install keeps its checkout and ignores OVIS_REF, by design. git clone --branch takes branches and tags, not commit SHAs.

Not reproduced as user-hittable, so no follow-up issue.

@devswha

devswha commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

Merge note: CodeRabbit was rate-limited for this head; merged on the omo review (CLEAR at 4fcfc7c), Codex Terra (round-1 HIGHs reproduced and fixed; round 2 no HIGH), container verification (hc-only install, systemd autostart/restart/stop) and green required checks. Only docs/guide.md changed on main since this head's CI, and it merges cleanly.

@devswha
devswha merged commit 98b032d into main Nov 4, 2026
16 checks passed
@devswha
devswha deleted the feat/hc-native-install branch November 4, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant