Agent control
The ovvi command: agents float panes, open browser and plugin cards, manage plugins and learn whether Ovvi shows them, on This Mac and on remote machines
An agent in a herdr pane can do everything herdr does: make tabs, spaces
and splits, run commands, rename and close panes. It asks Ovvi for the
things only Ovvi has: a floating window, a browser or plugin card, the list
of plugins, a new plugin, a notification on the Mac, an agent with the chat
view, and the answer to "does Ovvi show me?". It asks
with one command, ovvi, which works the same on This Mac and on every
remote machine that Ovvi connects to (D104).
- The command,
ovvi, is a smallshscript at~/.cache/ovvi/bin/ovvion each machine where Ovvi opened a session. Ovvi writes it there (CLI). - herdr is the bus. The command writes its arguments to a file on its own machine and rings a doorbell: a herdr metadata token on its own pane. Each Ovvi that follows the session hears the token on its event stream. One of them takes the file, does the work and writes the answer back as files (Protocol).
- Ovvi parses the arguments, not the script. The script only carries argv and prints what comes back. A new command needs no new script on any machine.
- Two presence tokens say whether Ovvi shows a pane (
ovvi-shown) and whether an Ovvi follows the session (ovvi-open).ovvi statusreads them from herdr, with no Ovvi involved (Is my pane in Ovvi?). - An agent never moves the user's view. It can add a card or a floating window. To point at something, it shows a notice with Show.
The ovvi skill
A skill is a folder of instructions that an agent loads when a task needs it.
The ovvi skill, in skills/ovvi/ of the Ovvi repo, teaches an agent the
ovvi command. Its SKILL.md says what Ovvi is, how to tell that Ovvi
shows the pane (ovvi status), the commands an agent uses most and the rules.
One file per topic loads only when the agent needs it:
| File | Holds |
|---|---|
cards.md | open in each place, reuse, replace, browser addresses, float, card, shown, balance |
plugins.md | list, make, reload and install plugins |
agents.md | start an agent with the chat view, relaunch an agent with chat, switch a card between chat and TUI |
remote.md | what differs on a remote machine |
Every herdr detail points to the herdr skill (herdr --skill).
- On This Mac,
make installlinks the folder to~/.agents/skills/ovvi(pi and Codex) and~/.claude/skills/ovvi(Claude Code). It leaves anovviskill that is already there alone. - On a remote machine, copy the folder to the same places, for example
ssh <machine> mkdir -p .agents/skills && scp -r skills/ovvi <machine>:.agents/skills/. Ovvi does not install it there.
What Ovvi does, and what stays herdr
| Operation | Who | Command |
|---|---|---|
| New tab, space, split; run a command; rename, move, close a pane; read output; send keys; agent status | herdr | herdr pane split …, herdr tab create … |
| Is my pane shown in Ovvi? Does an Ovvi follow my session? | herdr tokens that Ovvi writes | ovvi status (no Ovvi needed) |
| Ovvi's version, protocol, commands, appearance | Ovvi | ovvi info |
| List the kinds an agent can open (the browser and every plugin) | Ovvi (the plugins live on the Mac) | ovvi plugins |
| Make, build and install a plugin | Ovvi, for a pane on This Mac | ovvi plugins new, ovvi plugins reload, ovvi plugins install |
| Open a browser or plugin card: beside a pane, in a new tab, floating, or in place of a card | Ovvi | ovvi open git . uncommitted |
| Open a file or URL with its default plugin | Ovvi | ovvi open ./README.md |
| Float and unfloat a pane, Stay on Top | Ovvi | ovvi float w1:p3 --on-top, ovvi unfloat w1:p3 |
| Point the user at a pane, without moving their view | Ovvi | ovvi reveal w1:p3 |
| What a card shows: kind, argument, title, unsaved edits, floating | Ovvi | ovvi card w1:p3 |
| Which panes of my session show now, and which float | Ovvi | ovvi shown |
| A notification on the Mac; a click shows the pane | Ovvi | ovvi notify "Tests pass" "42 passed" |
| Start an agent with the chat view | Ovvi (the launch flags are made per launch) | ovvi agent claude |
| Relaunch an idle agent with the chat view | Ovvi | ovvi --timeout 40 chat w1:p4 |
| Switch an agent's card to its chat or its TUI | Ovvi | ovvi view w1:p4 chat |
| Even out the splits of a tab | Ovvi | ovvi balance |
| Copy text to the Mac's clipboard | Ovvi | echo hi | ovvi copy |
Every command, its options and its JSON output: CLI.
Is my pane in Ovvi?
An agent wants to know if a person sees its pane in Ovvi now, and to keep knowing as that changes. Two tokens answer it. Ovvi writes both, herdr keeps them, and any process in the session reads them with herdr calls.
| Token | On | Value | Written | Means |
|---|---|---|---|---|
ovvi-shown | each pane in view | 1, or remote when the pane's machine is not the Mac that runs that Ovvi | when the pane comes into view, every 10 s while it stays, cleared when it leaves; ttl_ms 30000 | an Ovvi window shows the pane now: it is in the shown tab of the page in view of a visible window (and is the zoomed card, when one is), or it floats |
ovvi-open | each space of the session | the protocol version, 1 | while any window of that Ovvi has the session open (a float-only page too): on each snapshot with a new space, every 10 s; cleared when the last window lets the session go and on quit; ttl_ms 30000 | an Ovvi follows the session, so it takes requests, also when the pane is in a hidden tab |
ovvi status --json reads them with pane get and workspace get and
prints:
{"session":"default","pane":"w1:p2","open":true,"shown":true,"remote":false,"protocol":1}| Field | Type | Meaning |
|---|---|---|
session | string | $HERDR_SESSION |
pane | string | the asking pane, $HERDR_PANE_ID or --pane |
open | boolean | the pane's space has ovvi-open: an Ovvi takes requests for this session |
shown | boolean | the pane has ovvi-shown: at least one Ovvi window, on any Mac, shows it now |
remote | boolean | ovvi-shown is remote: the Ovvi that marked it last runs on another machine, so the agent's own pbcopy does not reach that Mac |
protocol | integer or null | the value of ovvi-open; null when open is false |
- Once per action is the rule. pi-herd reads
shownat each click. An agent readsopenbefore it callsovvi, or it calls and handles exit code 3. - Keep knowing. A process that shows the state (a footer, a status line)
subscribes to herdr's
pane.updatedfor its own pane andworkspace.metadata_updatedfor its space. herdr sends them on each write and when a token expires.ovvi status --watchprints the JSON line again each time it changes. It reads every 2 s, because a shell script cannot hold a herdr subscription. - Several windows and Macs share one
ovvi-shownper pane.shownis true while any window of any Ovvi shows the pane. A window that hides the tab clears the mark, and another window or Mac that still shows it writes it again within 10 s. Soshowncan read false for up to 10 s while a second Mac shows the pane. A floating pane counts as shown. - Ovvi quits: it clears all its marks at once and waits up to 1 s. A crash leaves the marks until
ttl_msends, 30 s at most.
The user's view
An agent adds and offers. It never moves the view:
- Ovvi never comes to the front for a request, never selects a tab or a page, and never moves herdr's focus or the keyboard.
- A new card beside the asking pane shows where the agent is.
- A card out of view (in a new tab, or a card that already existed), and
ovvi revealof a pane out of view, show a notice with Show in each window that shows the session (Notice). Show selects the pane's space, tab and card in that window. ovvi revealof a pane in view flashes its card's border once.- A float from an agent orders its window to the front without activating Ovvi. The keyboard stays in the window that had it.
- A click on an agent's notification brings Ovvi to the front and shows the pane: the user asked for it.
- The confirmation for
ovvi plugins installshows on the session's window and asks for attention in the Dock. Ovvi does not come to the front, and Return does not press Install.
Security
Any process that can reach a session's herdr socket (the same user on that machine) can ring the doorbell. That process can already type into every pane of the session, so Ovvi gives it nothing on that machine that herdr does not. The rules limit what lands on the Mac: a request acts only on its own machine, reads nothing on the Mac, changes plugins only from This Mac, never moves the view, and sends at most one notification per pane every 10 s (Protocol).
Why this design
- herdr as the bus reaches every machine that Ovvi follows and every
Ovvi that follows the session, with no new connection. Ovvi's own socket
forwarded over SSH would open a door from the machine to the Mac, which the
SSH link keeps shut on purpose
(Why not a forwarded socket).
The
ovvi://floatURL works only on This Mac and gives no answer. Escape sequences go to herdr, which owns the terminal, not to Ovvi. - argv in, Ovvi parses keeps the script small and the same on every machine. Structured JSON requests would make the script know every command.
- A command, not an MCP server, works for every agent and shell script with no configuration per agent. An MCP server can wrap it.
- Fail fast with exit 3 when no Ovvi takes a request. The caller picks its fallback: pi-herd opens herdr's popup, an agent tells the user.
Not built
- Agents that drive a browser card's page (read it, run script, capture it): it needs its own consent design (Future work).
- Update and Remove of a plugin from an agent: they stay the user's, in the Plugins page.
- The size and position of a floating window from an agent: it keeps the frame of the pane's last float.
- Changing the theme: agents can read the appearance only (
ovvi info). - Callers outside herdr panes (cron, Mac apps):
ovvi://floatcovers This Mac. - Presence tokens per Mac, which would close the 10 s gap above.
- pi-herd's hidden agents with the chat view: pi-herd starts agents with its own command line.
- iPhone and iPad.