Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ to change. Also read [server/AGENTS.md](server/AGENTS.md) and [src/AGENTS.md](sr
a `mkdtempSync` `stateDir` and `port: 0` for every `createServer`. Never run the real
`herdr update` in a test.
- Screenshots and recordings come from the demo or a test session, never the user's live one.
- A web UI server an agent starts for someone to open (manual QA, a preview) binds to this PC's
- An Ovis server an agent starts for someone to open (manual QA, a preview) binds to this PC's
Tailscale address, not loopback: `HOST=$(tailscale ip -4) PORT=<free port> bun run server`,
then hand over `http://<that address>:<port>`. A Tailscale-only bind stays inside the tailnet
(`lanExposed` in `server/access.ts`); never bind `0.0.0.0` for it. Tests keep `port: 0` on
Expand Down
2 changes: 1 addition & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ address is open to anyone who reaches it, as before; the server warns on startup
plain `http://` is readable by anyone on the network path: prefer HTTPS (Tailscale or a
TLS-terminating proxy) for any address others can reach.

Other PCs over SSH are added from the web UI (Settings → Remote PCs → **Add PC**), not by an install step here.
Other PCs over SSH are added in Ovis (Settings → Remote PCs → **Add PC**), not by an install step here.

## Configuration

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Yes. Run the agent in a [herdr](https://github.com/herdrdev/herdr) pane on your

**Which agents does the chat view support?**

Claude Code, Codex, omp, omo, gjc, pi and Hermes are read from their own session stores. GJC chat and done alerts use the web UI's native GJC extension to identify the active session, without an SDK broker or CLI lookup. [Install the extension](docs/guide.md#supported-agents) and restart GJC to enable them; missing or ambiguous session identity uses Terminal and herdr's own status. For OpenCode, chat reads the session herdr reports from its SQLite database, including supported 2.x and 1.x schemas. The home screen, missing session identity or an unsupported, unreadable or over-limit store uses the terminal instead. Devin CLI is a chat when herdr or the running process names its session, as `devin --resume <id>` does; a plain `devin` shows the live terminal.
Claude Code, Codex, omp, omo, gjc, pi and Hermes are read from their own session stores. GJC chat and done alerts use Ovis's native GJC extension to identify the active session, without an SDK broker or CLI lookup. [Install the extension](docs/guide.md#supported-agents) and restart GJC to enable them; missing or ambiguous session identity uses Terminal and herdr's own status. For OpenCode, chat reads the session herdr reports from its SQLite database, including supported 2.x and 1.x schemas. The home screen, missing session identity or an unsupported, unreadable or over-limit store uses the terminal instead. Devin CLI is a chat when herdr or the running process names its session, as `devin --resume <id>` does; a plain `devin` shows the live terminal.

Grok chat is Linux-only and requires one process-held session matching herdr's session identity; macOS, Windows or ambiguous identity use Terminal. Antigravity (agy) chat is experimental: Linux native-tested, macOS untested, Windows terminal-only. It follows the running process's held conversation lock rather than guessing a session. Any unsupported or unresolved transcript uses the terminal instead. [Supported agents →](docs/guide.md#supported-agents)

Expand Down
6 changes: 3 additions & 3 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bun run check run --build bun scripts/ui-regression.ts # bui
```

`fast` needs no herdr. The other modes run on a herdr of their own: its config, its plugin state
and the web UI's state live in a directory made for the run (`XDG_CONFIG_HOME`, `XDG_STATE_HOME`,
and Ovis's state live in a directory made for the run (`XDG_CONFIG_HOME`, `XDG_STATE_HOME`,
`OVIS_STATE_DIR`), under a session name made for the run. Nothing reads your herdr config,
so no plugin installed there starts with the test servers, and two runs on one PC share no
socket and no file. The run stops its herdr servers and removes the directory when it ends, also
Expand Down Expand Up @@ -429,7 +429,7 @@ comes from `scripts/film/render.ts loop`.

## The film

The film (`site/media/herdr-web-ui-film.mp4`, 56 s) and chat loop (`site/media/chat-loop.mp4`, with the README's
The film (`site/media/ovis-film.mp4`, 56 s) and chat loop (`site/media/chat-loop.mp4`, with the README's
`docs/media/chat-loop.gif`) are the real client on the demo's fixtures, recorded and composited by `scripts/film/`.
Raw footage and renders go to `_film/` (gitignored); only the outputs under `docs/media/` are committed.
herdrweb.dev no longer publishes `site/media/` (it forwards to ovis.sh), so the film and loop MP4s wait for a
Expand All @@ -439,7 +439,7 @@ home on ovis.sh. Needs ffmpeg and Chrome at `/usr/bin/google-chrome` (`CHROME_PA
bun run build:site # the demo the takes are recorded from
bun scripts/film/capture.ts [stills] [rec] [stepped] [R10 R11 … | still names] # _film/footage/
bun scripts/readme-media/banner.ts # banner, look-*.png from the stills
bun scripts/film/render.ts film # site/media/herdr-web-ui-film.{mp4,jpg}
bun scripts/film/render.ts film # site/media/ovis-film.{mp4,jpg}
bun scripts/film/render.ts loop # site/media/chat-loop.{mp4,jpg}, docs/media/chat-loop.gif
bun scripts/film/render.ts check # acceptance frame grabs, sizes, loop seam
```
Expand Down
2 changes: 1 addition & 1 deletion docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ curl -fsSL https://ovis.sh/install.sh | sh

It does, in order, only what is not done yet:

- **What it runs on.** [herdr](https://github.com/herdrdev/herdr) 0.9.0+, [Bun](https://bun.sh) 1.4+ and Node 18+ (Node runs the terminal sidecar). A missing one is installed for your user only, without sudo: herdr and Bun by their own installers, into `~/.local/bin` and `~/.bun`, and Node 22 from nodejs.org, checked against its published SHA-256, into `~/.local/share/herdr-web-ui/node`. Nothing is compiled.
- **What it runs on.** [herdr](https://github.com/herdrdev/herdr) 0.9.0+, [Bun](https://bun.sh) 1.4+ and Node 18+ (Node runs the terminal sidecar). A missing one is installed for your user only, without sudo: herdr and Bun by their own installers, into `~/.local/bin` and `~/.bun`, and Node 22 from nodejs.org, checked against its published SHA-256, into `~/.local/share/ovis/node`. Nothing is compiled.
- **The app**, as a herdr plugin at the latest release (set `OVIS_REF` to install another branch or tag): herdr builds it and starts it along with itself, on `127.0.0.1:7317`, following the socket of the current herdr session. When herdr is already running, the app starts now.
- **The phone address.** When Tailscale runs on this PC, it serves the app to your tailnet (`tailscale serve`, see [On your phone](#on-your-phone)), tells you the command that undoes it, and prints the address as a QR code. Without Tailscale, it says what to set up.

Expand Down
16 changes: 8 additions & 8 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,15 @@ function Invoke-GhApi([string]$Arguments) {
if (-not $gh) { return }
$job = [IntPtr]::Zero
try {
if (-not ('HerdrWebUi.GhJob' -as [type])) {
if (-not ('Ovis.GhJob' -as [type])) {
Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace HerdrWebUi {
namespace Ovis {
public static class GhJob {
[StructLayout(LayoutKind.Sequential)]
struct BasicLimits {
Expand Down Expand Up @@ -356,7 +356,7 @@ namespace HerdrWebUi {
}
'@
}
$job = [HerdrWebUi.GhJob]::Create()
$job = [Ovis.GhJob]::Create()
} catch { $job = [IntPtr]::Zero } # taskkill fallback cannot find an orphan after its launcher exits
$start = New-Object Diagnostics.ProcessStartInfo
$ghArguments = "api --hostname github.com --include $Arguments"
Expand All @@ -376,9 +376,9 @@ namespace HerdrWebUi {
$process = $null
try {
if ($job -ne [IntPtr]::Zero) {
$process = [HerdrWebUi.GhJob]::StartSuspended($start.FileName, $start.Arguments)
if (-not [HerdrWebUi.GhJob]::Assign($job, $process.Handle)) {
$null = [HerdrWebUi.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
$process = [Ovis.GhJob]::StartSuspended($start.FileName, $start.Arguments)
if (-not [Ovis.GhJob]::Assign($job, $process.Handle)) {
$null = [Ovis.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
}
$process.Resume()
} else {
Expand All @@ -389,7 +389,7 @@ namespace HerdrWebUi {
$null = $process.StandardError.ReadToEndAsync()
if (-not $process.WaitForExit(10000) -or -not $said.Wait(2000)) {
# closing the job kills gh and every process it started, also one whose parent has exited
if ($job -ne [IntPtr]::Zero) { $null = [HerdrWebUi.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero }
if ($job -ne [IntPtr]::Zero) { $null = [Ovis.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero }
try { & $env:ComSpec /d /c "taskkill /T /F /PID $($process.Id) >nul 2>&1" } catch { }
return
}
Expand All @@ -398,7 +398,7 @@ namespace HerdrWebUi {
@{ code = $process.ExitCode; status = $status }
} finally {
# what gh left running after it answered ends here too
if ($job -ne [IntPtr]::Zero) { $null = [HerdrWebUi.GhJob]::CloseHandle($job) }
if ($job -ne [IntPtr]::Zero) { $null = [Ovis.GhJob]::CloseHandle($job) }
if ($process) {
# Dispose leaves the pipe readers open on .NET Framework; a reader still busy with its
# ReadToEndAsync may refuse to close, and then the job has ended the writers already
Expand Down
8 changes: 4 additions & 4 deletions scripts/film/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
* bun scripts/film/render.ts loop [--start 2.4] site/media/chat-loop.{mp4,jpg} + docs/media/chat-loop.gif
* bun scripts/film/render.ts check acceptance grabs, sizes, seam PSNR, duplicate frames
*
* `film` writes _film/renders/film-master.mp4 (CRF 10, animated grain) and site/media/herdr-web-ui-film.mp4
* `film` writes _film/renders/film-master.mp4 (CRF 10, animated grain) and site/media/ovis-film.mp4
* (CRF 19, preset veryslow, no grain, ≤ 20 MB): at a web bitrate x264 freezes per-frame grain into blocky
* mottle that only refreshes on I-frames (a visible 2 s pulse), and even a static grain field costs ~3 MB
* that the UI text needs more; the site draws its own static grain over the stage.
* and the poster site/media/herdr-web-ui-film.jpg (the frame at 34.40 s). A full render takes a few
* and the poster site/media/ovis-film.jpg (the frame at 34.40 s). A full render takes a few
* minutes on 32 cores. Needs /usr/bin/google-chrome (CHROME_PATH) and ffmpeg; the brand mark comes
* from _film/brand/mark-paper.png, made by the brief's ffmpeg derivation from docs/brand/icon-source.png
* (`render.ts` runs it when the file is missing).
Expand All @@ -41,8 +41,8 @@ import { DURATION, FPS, LOOP_FPS, LOOP_LEN, LOOP_START, frame, loopFrame, report

const CHROME = process.env["CHROME_PATH"] ?? "/usr/bin/google-chrome";
const RENDERS = join(REPO, "_film/renders");
const FILM_MP4 = join(REPO, "site/media/herdr-web-ui-film.mp4");
const FILM_JPG = join(REPO, "site/media/herdr-web-ui-film.jpg");
const FILM_MP4 = join(REPO, "site/media/ovis-film.mp4");
const FILM_JPG = join(REPO, "site/media/ovis-film.jpg");
const LOOP_MP4 = join(REPO, "site/media/chat-loop.mp4");
const LOOP_JPG = join(REPO, "site/media/chat-loop.jpg");
const LOOP_GIF = join(REPO, "docs/media/chat-loop.gif");
Expand Down
10 changes: 5 additions & 5 deletions scripts/windows-install.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -309,21 +309,21 @@ public static class ImmediateGh {
}
}
'@
$assignment = '[HerdrWebUi.GhJob]::Assign($job, $process.Handle)'
$assignment = '[Ovis.GhJob]::Assign($job, $process.Handle)'
$orderedSource = $ghApi.Extent.Text.Replace("`r`n", "`n").Replace($assignment, '(Assign-TestGhJob $job $process)')
Assert ($orderedSource -ne $ghApi.Extent.Text) 'control: interpose at the real job assignment boundary'
function Assign-TestGhJob($Job, $Process) {
if ($Process -is [Diagnostics.Process]) {
Assert ($ready.WaitOne(5000)) 'control: the runnable shim must reach child-ready before assignment'
}
Assert (-not $ready.WaitOne(0)) 'regression: shim ran before job assignment'
[HerdrWebUi.GhJob]::Assign($Job, $Process.Handle)
[Ovis.GhJob]::Assign($Job, $Process.Handle)
}
$suspendedLaunch = @'
if ($job -ne [IntPtr]::Zero) {
$process = [HerdrWebUi.GhJob]::StartSuspended($start.FileName, $start.Arguments)
$process = [Ovis.GhJob]::StartSuspended($start.FileName, $start.Arguments)
if (-not (Assign-TestGhJob $job $process)) {
$null = [HerdrWebUi.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
$null = [Ovis.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
}
$process.Resume()
} else {
Expand All @@ -333,7 +333,7 @@ public static class ImmediateGh {
$runnableLaunch = @'
$process = [Diagnostics.Process]::Start($start)
if ($job -ne [IntPtr]::Zero -and -not (Assign-TestGhJob $job $process)) {
$null = [HerdrWebUi.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
$null = [Ovis.GhJob]::CloseHandle($job); $job = [IntPtr]::Zero
}
'@
# Scratch-source reversion of exactly the pre-fix runnable Start/Assign ordering; no repository file changes.
Expand Down
5 changes: 4 additions & 1 deletion telemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ edit to `telemetry/worker.ts` or `shared/telemetry.ts` counts, comments included
changes nothing is sometimes the price.

The Worker answers at `https://herdr-web-ui-telemetry.<account>.workers.dev/v1/events`, and
`TELEMETRY_URL` in `server/telemetry.ts` must name that address. `HERDR_WEB_TELEMETRY_URL` does not
`TELEMETRY_URL` in `server/telemetry.ts` must name that address. `OVIS_TELEMETRY_URL` does not
exist on purpose: an install cannot be pointed elsewhere by its environment.

The Worker and its D1 database keep the `herdr-web-ui-telemetry` name they had before Ovis took its
name: installs already send to that address, and a D1 database cannot be renamed.

## Reading the counts

After `bunx wrangler login` from `telemetry/`, run
Expand Down
Loading